栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JPA使用总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JPA使用总结

个人觉得JPA没有MybatisPlus好用,但公司用到,写下技术总结。

一. 介绍

ORM(Object-Relational Mapping) 表示对象关系映射。常见的 orm 框架:Mybatis(ibatis)、Hibernate、Jpa。JPA 规范本质上就是一种 ORM 规范,注意不是 ORM 框架——因为 JPA 并未提供 ORM 实现,它只是制 订了一些规范,提供了一些编程的 API 接口,底层需要 hibernate 作 为其实现类完成数据持久化工作。JPA是一个尽量避免写sql的框架,面向对象化的查询而非面向数据库。

优势:
单表查询,简单条件查询非常快

劣势:
多表关联存在子查询时不方便,分页存在问题,且容易循环注入导致栈溢出。

二. JPA的基本使用 1.导入包
  
    org.springframework.data
    spring-data-jpa
  
2.配置文件
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mytest
    type: com.alibaba.druid.pool.DruidDataSource
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver //驱动
  jpa:
    hibernate:
      ddl-auto: update //自动更新
    show-sql: true  //日志中显示sql语句
3.创建实体 公司表
@Entity//声明实体类
@Table(name = "company")//建立实体类和表的映射关系
@Data//lombok自动生成get,set方法
public class CompanyEntity implements Serializable {
    
	private static final long serialVersionUID = 1L;
	
	//标识主键
	@Id
	//配置主键的生成策略
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    //指定和表中id 字段的映射关系
    @Column(name = "id")
    private Integer id;

    @Column(name = "name")
    private String name;
    
	//标识这个类与SysAreaEntity 表是一对一关系,即一个企业对应有一个区域
    @oneToOne
    //指定area_code关联SysAreaEntity 的 tree_code字段,referencedColumnName:指定引用主表的
    //主键字段名称,不写默认关联SysAreaEntity 的主键id
    @JoinColumn(name = "area_code", referencedColumnName = "tree_code")
    private SysAreaEntity sysAreaEntity;

    @Column(name = "address")
    private String address;

    @Column(name = "create_user_id")
    private int createUserId;

	//@OneToMany标识公司与设备是一对多关系,即一个公司下面有多个设备,且在DeviceEntity中用
	//@ManyToOne
	//@JoinColumn(name = "company_id")
    //private CompanyEntity company1;
   	//对应设备与公司是多对一关系。mappedBy:指定从表实体类中引用主表对象的名称,
   	//cascade:指定要使用的级联操作,fetch:指定是否采用延迟加载
    @OneToMany(mappedBy = "company1", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List deviceEntities ;
}

区域表
@Entity
@Table(name="sys_area")
@Data
public class SysAreaEntity implements Serializable {

    private static final long serialVersionUID = 1L;
   
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

	//这里与公司关联
    @Column(name = "tree_code")
    private String treeCode; 

    @Column(name = "name")
    private String name;
}

设备表
@Entity
@Table(name = "company_device")
@Data
public class DeviceEntity implements Serializable {

    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

	//这里与公司关联,@ManyToOne标识一个设备对应多个公司
    @ManyToOne
    @JoinColumn(name = "company_id")
    private CompanyEntity company1;

    @Column(name = "total_number")
    private Integer totalNumber;
}

4.搭建Dao层
//构建dao层接口继承JpaRepository包含了一般的curd方法,JpaSpecificationExecutor
//包含了条件查询查询的方法和分页查询方法
public interface CompanyDao extends JpaRepository
        , JpaSpecificationExecutor {
	
	//操作数据有三种方式
	
	//第一种用它提供的方法
	
	//第二种自己写sql
	//@Query查询语句,nativeQuery = true是本机查询,接收参数可以用实体也可以用万能的Map
    @Query(nativeQuery = true, value = "select id,name from company where if(?1 is null ,1=1,id in ?2)")
    List> findIdAndNameByIds(Integer isAll,List companyIds);
	
	//如果是修改或删除需要加上@Modifying,?2代表第二个参数,?1代表第一个参数
	@Query(value="update company  set name=?2 where  id=?1",nativeQuery=true)
    @Modifying
    void updateCompany  (Integer id, String name);
	
	// 这种方式也可以实现复杂动态的查询,例如
	 @Query(value = "select * from t1 left join t2 on t1.id=t2.company_id where
	  if(:isAll is null ,1=1,t1.id in :companyIds) and 
	  (:labelName is null or labels like %:labelName%)
	    limit :pageIndex,:pageSize",nativeQuery = true)
    List> getCompanies(@Param("labelName") String labelName, 
    @Param("pageIndex") Integer pageIndex, @Param("pageSize") Integer pageSize,
    @Param("isAll")Integer isAll,@Param("companyIds") List companyIds);
	
	//第三种使用方法命名规则查询,可以根据方法命名来自动查询,但By后面的字段一定要是实体类中存在的
	//且方法命名要符合规范。例如根据公司地址查询所有的公司:
	List findAllByAddress(String address);
}
5.搭建Service层
@Service
public class CompanyService {

    private Logger log = LoggerFactory.getLogger(CompanyService.class);

    @Autowired
    CompanyDao companyDao;
    
    //根据公司id和区域id分页查询公司列表
    public Object pageByCondition(Integer pageIndex, Integer pageSize,String companyId,String areaId) {
    	//使用JPA自带的分页查询
        Page page = companyDao.findAll((Specification) (root, query, criteriaBuilder) -> 	
        	{
            List list = new ArrayList<>();
            if (nul != companyId) {
                list.add(criteriaBuilder.equal(root.get("id"), companyId));
            }
            // JoinType.INNER代表公司表与区域表采用内连接方式关联
            Join areaEntityJoin = root.join("sysAreaEntity", JoinType.INNER);
            if (null != areaId) {
                list.add(criteriaBuilder.equal(areaEntityJoin.get("id"), areaId));
            }
            return criteriaBuilder.and(list.toArray(new Predicate[]{}));
        }, PageRequest.of(pageIndex, pageSize, Sort.by(Sort.Direction.DESC, "id")));
        
  		// 因为ComanyEntity中包含了 List,而每个 DeviceEntity 中含有一个CompanyEntity ,这里面的
  		//CompanyEntity 又包含了List......,通过调试发现循环注入,如果直接返回页面会出现套娃现象的
  		//数据,所以要专门写一个方法来转换到页面数据CompanyVo
        List result = entityToVo(page.getContent().toArray(new CompanyEntity[]{}))
        return result ;
    }

     //实体转VO
    public List entityToVo(CompanyEntity... entities) {
        List vos = new ArrayList<>();
        for (CompanyEntity entity : entities) {
            CompanyVo vo = new CompanyVo();
            vo.setName(entity.getName());
            //设置区域名称
            vo.setArea(entity.getSysAreaEntity().getName());
            ......
            //把公司的设备单独拿出来处理
            List deviceEntities = entity.getDeviceEntities();
            StringBuffer deviceNumber = new StringBuffer();
            for (DeviceEntity deviceEntity : deviceEntities) {
                deviceNumber.append(deviceEntity.getTotalNumber() + "、");
            }
            vo.setDeviceNumber(deviceNumber);
            vos.add(vo);
        }
        return vos;
    }

     //新增,修改
    @Transactional
    public Object save(String companyName, Integer areaId, String address, String name) {
        //新增企业,save方法如果有主键id则是修改,没有则是新增,且新增成功后会把id返回来,
        CompanyEntity company = new CompanyEntity();
        company.setName(companyName);
       	//实体类包含其它对象的,要先创造其它对象,这些对象要有主键id,否则会失败
        Optional sysAreaEntity = sysAreaDao.findById(areaId);
        company.setSysAreaEntity(sysAreaEntity.get());
        company.setAddress(address);
        companyDao.save(company);
		return "ok";
    }
        
	//删除
    @Transactional
	public Object deleteById(Integer id){
        companyDao.deleteById(id);
    	return "ok";
	}
}
三. 补充使用方法命名规则查询的规范(部分常用)
KeywordSampleJPQL
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs, findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
AfterfindByStartDateAfter …where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/343721.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号