SpringData JPA


SpringData JPA

JPA是规范:本质上是一种ORM规范,不是框架。

SpringData JPA是封装基于jpa规范的一套应用框架。

  1. findOne(long id)
  2. sava(eneity)
  3. findAll(long id)
  4. delete(long id)

实现原理:

通过动态代理的方式,自动生成代理对象。

  1. 通过JdkDynamicAopProxy的invoke方法创建动态代理实现
  2. SimpleJpaRepository当中封装了JPA的操作(基本crud)
  3. 通过hibernate完成数据库操作。

复杂查询:

  1. 借助接口中定义好的查询方法。

    1. count() 统计总条数
    2. boolean exists(long id)
    3. findOne 立即加载 与 方法,延迟加载。
  2. 使用jpql查询。在实体类的属性上添加@Query
    @Query(value=“from user where name=?”)
    public User getUser(String name) ;

    • 有多个占位数参数,默认情况下,占位符的位置需要和方法中的参数位置保持一致
    • 也可以指定参数的位置 ?索引的方式 指定取参数中第几个值。
    • @Modifying 声明这是个更新参数。
    • 进行更新或删除操作时,需要添加事务和设置不回滚操作。
  3. SQL查询

    1. @Query 中value:jpql语句 | sql语句
    2. nativeQuery=true 代表sql查询。 false jpql查询
  4. 方法名称规则查询,是对jpql查询更加深入的封装。

    1. findBy查询(对象的属性名首字母大写) 例如 findByCustName
    2. 模糊查询 findBy+实体类属性名+查询方式 (like|isnull) findByCustNameLike
    3. 多条件查询 findBy+实体类属性名+查询方式 (like|isnull)+连接符(and|or)+属性名+查询方式 (like|isnull) findByCustNameLikeAndCustIdustry()

自定义查询条件:

  1. 实现specification接口(提供泛型)
  2. 实现toPredicate方法(构造查询条件)
  3. 借助方法中的两个参数
    1. root 获取 查询对象的属性
    2. CriteriaBuilder:构造查询条件的,内部封装了很多查询条件(模糊匹配,精准匹配)

分页:

使用Pageable接口,pageRequest实现类 ,使用构造方法创建

第一个参数,查询当前页的页数,第二个参数,煤业查询的数量。

page.getContent();//得到内容数据集合列表

page.getTotalElements();//得到总条数

page.getTotalPages();//得到总页数

多表查询

表关系:

  • 一对一
  • 一对多
    • 一的一方:主表
    • 多的一方:从表
    • 外键:需要在从表上建立一列作为外键,值为主表的主键
  • 多对多
    • 中间表:至少两个字段组成,这两个字段作为外键指向两张表的主键,又组成联合主键。

1、一对多

老师对学生:一对多

实体类的关系:

包含关系:通过实体类的包含关系来描述表关系

继承关系

分析步骤:

  1. 明确表关系
  2. 确定表关系(描述 外键|中间表)
  3. 编写实体类。用实体类描述表关系(包含关系)
  4. 配置映射关系

客户和联系人之前的关系:一对多

  • 客户实体类:相对于本身,一对多,使用集合保存联系人,推荐使用Set

使用@OneToMany(targetEntity = linkMan.class)

targetEntity :对方的字节码对象

@JoinColumn配置外键

	name:外键字段名称   referenceColumnName参照主表的主键字段名称

需要在1的一方,添加了外键的配置,所以对客户而言,也具备了维护外键的作用。

@OneToMany(targetEntity = linkMan.class)
@JoinColumn(name="从表表示外键的字段",referenceColumnName="主表的主键")
private Set linkMans
  • 联系人实体类:相对于本身,多对一,实体类中包含了客户的对象。

    @ManyToOne(targetEntity = Customer.class)
    @JoinColumn(name="从表 表示外键的字段",referenceColumnName="主表的主键")
    private Customer customer

当两边都配置外键关系时,是双向外键维护。

一的一方,会多执行一条update语句维护外键。

多的一方,会直接在insert中维护外键。

双向绑定会多执行一条update语句,如果不需要执行,那么一的一端需要主动放弃外键维护权。

mappedBy:对方配置关系的属性名称

@OneToMany(mappedBy = "customer")
private Set linkMans

一对多的删除

删除主表数据时

  • 当从表有数据
  1. 在默认情况,会把外键字段置为null,然后删除主表数据,如果从表外键字段有非空约束,默认情况就会报错。
  2. 如果配置了放弃维护关联关系的权力,则不能删除,因为在删除时,根本不会去更行从表的字段
  3. 如果还想删除,使用级联删除引用。

级联

操作对象的同时,同时操作他的关联对象。

级联操作:

  1. 需要区分操作主体
  2. 需要在操作的主体的实体上,添加级联属性
  3. cascade(配置级联)

级联添加

保存一个客户的同时,保存客户的所有联系人

需要在操作主体的实体上,配置casacde属性

ALL:所有

MERGE :更新

PERSIST:保存

REMOVE:删除

@OneToMany(mappedBy = "customer" cascade=CascadeType.ALL)
private Set linkMans

级联删除

删除1号客户的同时,删除1号客户的所有联系人。

2、多对多

案例:用户和角色

	用户:用户有很多角色

	角色:角色可分配给多个用户

配置多对多的映射关系

  1. 申明表关系的配置

    1. @ManyToMany(targetEntity = Role.class) //多对多
  2. 配置中间表

    //User.java

    @ManyToMany(targetEntity = Role.class)
    @JoinTable(name = "sys_user_role",
    //joinColumns,当前对象在中间表的外键
    joinColumns = {@joinColumn(name = "sys_user_id", referenceColumnName = "user_id")},
    //inverseJoinColumns,对方对象在中间表的外键
    inverseJoinColumns = {@joinColumn(name = "sys_role_id", referenceColumnName = "role_id")})
    private Set roles = new HashSet<>();

    //Role.java

    @ManyToMany(targetEntity = User.class)
    @JoinTable(name = "sys_user_role",
    //joinColumns,当前对象在中间表的外键
    joinColumns = {@joinColumn(name = "sys_role_id", referenceColumnName = "role_id")},
    //inverseJoinColumns,对方对象在中间表的外键
    inverseJoinColumns = {@joinColumn(name = "sys_user_id", referenceColumnName = "user_id")})
    private Set users = new HashSet<>();

多对多放弃维护权,被动一方放弃维护权。

//User.java
@ManyToMany(targetEntity = Role.class)
@JoinTable(name = "sys_user_role",
          //joinColumns,当前对象在中间表的外键
          joinColumns = {@joinColumn(name = "sys_user_id", referenceColumnName = "user_id")},
           //inverseJoinColumns,对方对象在中间表的外键
          inverseJoinColumns = {@joinColumn(name = "sys_role_id", referenceColumnName = "role_id")})
private Set roles = new HashSet<>();



//Role.java
@ManyToMany(mappedBy = "roles")
private Set users = new HashSet<>();

级联

多对多支持级联

多表的查询

  1. 对象导航查询
    查询一个对象的同时,通过此对象查询他的关联对象。
    默认使用延迟加载的方式查询,调用get方法不会立即发送查询,而是在使用关联对象的时候才会出现查询。
    不使用延迟加载,需要配置。
    fetch ,需要配置到多表映射关系的注解上。EAGER 立即加载 LAZY延迟加载

    @ManyToMany(mappedBy = "roles" , fetch = FetchType.EAGER)

EAGER 立即加载 底层实现,通过连表(left join)的方式实现,不推荐立即查询

一对多中 从多的一方查询,默认使用立即加载。将其中1的一方一起查询出来。

从一表查询多方

*默认:使用延迟加载。

多方查询一方

*默认使用:立即加载。
jpa