一、JPA概述及基本操作
1、ORM思想
- ORM(Object-Relational Mapping) 表示对象关系映射。
- 目的:通过操作实体类就可以对数据库表进行操作
- 建立两个映射:
- 实体类和表的映射
- 实体类属性和表中字段的映射
- 实现ORM思想的框架:Hibernate、mybatis
2、JPA的介绍
- Hibernate封装jdbc,是一个orm关系对象映射框架,可以自动生成sql语句自动执行
- JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范
3、CRUD入门案例
- 步骤
- 坐标
- 配置文件resources/META-INF/persistence.xml
- showsql/hbm2ddl.auto
- 编写实体类
- 配置映射关系
- @GeneratedValue
- @Id
- @Column
- 编写测试类,通过EntityManager实现保存
4、常用操作
- 主键生成策略:IDENTITY(MySQL自增长,只需要这一种就可以)
- JpaUtils工具类:静态代码块加载配置文件,提供方法直接获取实体管理器
- 立即加载find与延迟加载getReference
- 更新:先查询再merge,CRUD均需要创建事务对象
5、jpql查询
- JPQL全称Java Persistence Query Language,查询的是实体类和类中属性
- 实现操作:查询全部、分页查询、统计、条件查询(em.setParameter设置对应位置的参数)、排序
- 调用em.createQuery(sql)得到Query对象调用getResultList/getSingleResult方法得到结果
二、Spring Data JPA
1、概述
- 基于ORM框架&JPA规范封装的框架,dao中只需要写接口
- 与Hibernate的关系:底层调用了hibernate
2、快速入门
- 步骤
- 搭建环境(配置文件、实体类注解配置映射)
- 编写dao接口,实现JpaRepository,JpaSpecificationExecutor接口
- 原理:创建动态代理对象、借助jpa完成操作、hibernate完成数据库操作
3、Spring Data JPA查询
- 复杂查询:定义好的接口方法(findOne立即加载<em.find>、getOne<em.getReference>懒加载)、jpql查询使用Query注解配置到接口的方法上(占位符?1)、sql使用注解配置到dao的方法上(nativeQuery = true)、方法命名规则查询
- 命名规则查询
- 模糊匹配:Likes
- 多条件查询:and/or
三、动态查询与多表操作
1、Specification动态查询
- findOne/findAll/count的参数,用于设置查询条件
- 查询单个对象、查询列表 List、分页查询返回Page对象
- Specification匿名内部类实现toPredicate方法返回Predict对象
Specification<Customer> spec = new Specification<Customer>() { @Override public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { return null; }};
- Predicate toPredicate(Root<T> var1【获取属性Path】, CriteriaQuery<?> var2【自定义查询对象,了解】, CriteriaBuilder var3【查询构造器】);
//多条件查询 Predicate p1 = criteriaBuilder.equal(custName, "传智播客"); Predicate p2 = criteriaBuilder.equal(custIndustry, "IT教育"); Predicate and = criteriaBuilder.and(p1, p2); //以与的形式拼接多个查询条件 //模糊匹配 Path<Object> custName = root.get("custName"); //查询方式:模糊匹配 Predicate like = criteriaBuilder.like(custName.as(String.class), "传智播客%"); //排序 Sort sort = new Sort(Sort.Direction.DESC,"custId"); List<Customer> all = customerDao.findAll(spec,sort); //分页 Pageable pageable = new PageRequest(0,2); Page<Customer> page = customerDao.findAll(null, pageable); System.out.println(page.getContent()); //得到数据集合列表 System.out.println(page.getTotalElements()); //得到总条数 System.out.println(page.getTotalPages()); //得到总页数
2、多表操作
- 一(主表)对多(从表),多对多(中间表,联合主键)
- 分析步骤
- 明确表关系
- 确定表关系
- 编写实体类,描述表关系
- 配置映射关系
3、一对多操作(客户与联系人)
- 新建List集合,设置OneToMany和JoinColumn注解
- 配置文件注入Hibernate配置信息(hibernate.hbm2ddl.auto为create或update)
- 保存时需要对多的一方list.add:customer.getLinkMans().add(linkMan);
- 放弃外键维护:@OneToMany(mappedBy = "customer")
- 级联操作(主体配置)
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL) private Set<LinkMan> linkMans = new HashSet<>();
4、多对多操作(用户和角色)
- 设置联合主键
@ManyToMany(targetEntity = Role.class) @JoinTable(name = "sys_role_user", //joinColumns,当前对象在中间表中的外键 joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}, //inverseJoinColumns,对方对象在中间表的外键 inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} ) private Set<Role> roles= new HashSet<>();
- 另一方放弃维护权
@ManyToMany(mappedBy = "roles") //对方配置的属性名称 private Set<User> users = new HashSet<>();
5、对象导航查询
- 查询一个对象时,可以通过此对象查询其关联对象
- Set<LinkMan> linkMans = customer.getLinkMans();
- 延迟加载:Customer customer = customerDao.findOne(1L);
- 关联对象加载设置(不推荐)
/* fetch配置关联对象的加载方式 * EAGER:立即加载 * LAZY:延迟加载 */ @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL,fetch = FetchType.EAGER) private Set<LinkMan> linkMans = new HashSet<>();
- 总结:
- 一查多,默认延迟加载
- 多查一,默认立即加载