JPA关联关系

1. 单向多对一(使用用户和订单为例)

  1. 使用注解:

    • @ManyToOne

      • 是属性或方法级别的注解,用于定义源实体目标实体是多对一的关系
      • 属性:
        • targetEntity源实体关联的目标实体类型,默认是该成员属性对应的类型,可以缺省
        • cascade:定义源实体和关联的目标实体间的级联关系。默认没有级联操作。可选值有:
          • CascadeType.PERSIST:级联新建。若保存实体时,数据库中没有与该实体相关联的实体的那条记录,会在保存实体的同时保存与之相关联的实体
          • CascadeType.REMOVE:级联删除。删除当前实体时,与它有映射关系的实体也会跟着被删除
          • CascadeType.REFRESH:级联刷新。在更新前重新获取数据。
            • 使用场景:你先获取了数据,但是在保存时数据库的数据被修改了,这时候就需要重新获取一次数据(refresh),然后执行update操作
          • CascadeType.MERGE:级联更新。当当前实体的数据改变,会相应地更新关联的实体的数据
          • CascadeType.DETACH:级联脱管/游离操作。删除实体因为有外键无法删除时,撤销所有相关的外键关联,然后删除
            • @since Java Persistence 2.0:表示从Java Persistence 2.0开始才有的这个可选值
          • CascadeType.ALL:(包含以上五项)
        • fetch:定义关联的目标实体的数据的加载方式。
          • FetchType.LAZY(懒加载) | FetchType.EAGER(立即加载,默认)
        • optional源实体关联的目标实体是否允许为 null,默认为 true
    • @JoinColumn

      • 该注解用于定义外键列,只能标注在实体类型的成员属性或方法上,如果没有声明,则使用该注解的默认值

      • 属性值:与 @Column 注解相类似,但是没有了 length、precision、scale,特有属性:

        • referencedColumnName:指定要关联哪一列为外键

        • foreignKey:没找到资料,这是源码中 Java doc 中的注释

          • The foreign key constraint specification for the join column. This is used only if table generation is in effect.  Default is provider defined.
            
          • 有道词典的翻译:联接列的外键约束规范。只有在表生成生效时才使用此方法。默认是提供程序定义的。

          • 其值的类型是:@ForeignKey,这个注解的属性

            • name:外键名
  • foreignKeyDefinition:外键类型
    • value:是否应用约束,取值有三个
    • ConstraintMode.CONSTRAINT:应用约束。默认值
      • ConstraintMode.NO_CONSTRAINT:不应用约束
    • ConstraintMode.PROVIDER_DEFAULT:使用JPA厂商的默认行为
  1. 操作注意

    1. 保存:建议先保存的一方,再保存的一方,否则会多执行update语句,因为是一的一方在维护关联关系
    2. 查询:因为JPA默认是立即加载,所以在查询多的一方的时候,默认会使用左外连接
    3. 修改:默认是可以级联修改的
    4. 删除:多的一方可以直接删除,但是一的一方因为有外键约束,所以不能删除

2. 单向一对多(使用用户和订单为例)

  1. 使用注解
    • @OneToMany
      • 与 @ManyToOne类似,但是没有optional,特有属性:
        • mappedBy:用在双向关联中。如果关系是双向的,则需定义此参数。用于标注谁来维护外键
        • orphanRemoval
    • @JoinColumn
  2. 操作注意:
    1. 保存:因为是一的一方在维护关联关系,所以在保存时,一定会多执行update语句
    2. 查询:FetchType fetch() default LAZY默认使用懒加载,发送多条sql,可修改为立即加载
    3. 修改:默认是可以级联修改的
    4. 删除:若删除的一端,默认先将关联外键置空,然后删除记录。可以通过修改@OneToMany的cascade改变

3. 双向一对多(使用用户和订单为例)

  1. 使用注解:

    • 一对多和多对一结合即可
  2. 操作注意:

    1. 保存:双向一对多双方都在维护外键关系,所以在保存时,如果先保存一的一方,会执行n次update,先保存多的一方,会执行2n次update

      • 我们可以设置一的一方不维护关联关系,通过@OneToManymappedBy来设置有哪个属性来维护

        @OneToMany(targetEntity = Order.class, mappedBy = "user")
        // 表示由Order类的user属性来维护外键,但是设置了mappedBy属性后,就不能设置@JoinColumn或@JoinTable了
        private List<Order> orders = new ArrayList<>();
        

4. 双向一对一映射

  1. 使用注解
    • @OneToOne
    • @JoinColumn
  2. 操作注意
    1. 一对一关系需要在外键列添加唯一约束
    2. 建议设置一方放弃维护关联关系
    3. 保存:建议先保存没有外键的一方,再保存有外键的一方,这样不会多出update操作
    4. 查询:
      1. 若获取维护关联关系(有外键)的一方
        • 默认会通过左外连接获取,即:默认是立即加载
        • 若修改为懒加载,会发送两次sql语句,但是获取到的关联对象是代理对象
      2. 若获取不维护关联关系(没有外键)的一方
        • 默认会通过左外连接获取,即:默认是立即加载
        • 改为懒加载以后,会发现,他发了两次sql语句,同样把关联对象查出来了,所以,修改它的加载策略并没有什么意义
    5. 疑点?
      1. 为什么有外键的一方使用关联对象时,会多发送一条sql语句?
      2. 为什么没有外键的一方一定会查出关联对象?

5. 双向多对多映射

  1. 使用注解

    • @ManyToMany:属性还是那些
  • @JoinTable:与@Table类似,但是多了下列属性
    • joinColumns:表示表中的外键列,该外键参照源实体(本对象)的主键。
    • inverseJoinColumns:与joinColumns类似,但是该外键参照目标实体(关联对象)的主键。
    • foreignKey:用于生成表时定义 joinColumns 参数的外键约束
    • inverseForeignKey:用于生成表时定义 inverseJoinColumns 参数的外键约束
  1. 操作注意:
    • 多对多必须有一方放弃维护外键关系
    • 多对多的级联删除慎重考虑

6. JPA二级缓存

  1. 因为实际上使用的是实现厂商的二级缓存,所以,hibernate怎么配置,在JPA配置文件的properties里面还怎么配就好了

    <!-- 二级缓存相关,基于hibernate5 -->
    <property name="hibernate.cache.use_second_level_cache" value="true"/>
    <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
    <property name="hibernate.cache.use_query_cache" value="true"/>
    
  2. class标签下面添加<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

    • 可选项:常用ENABLE_SELECTIVE
      1. ALL:所有实体类都将被缓存
      2. NONE:所有实体类都不被缓存
      3. UNSPECIFIED:默认值。使用JPA产品的默认值
      4. ENABLE_SELECTIVE:标识@Cacheable(true)注解的实体类将被缓存
      5. DISABLE_SELECTIVE:缓存除了标识@Cacheable(false)注解的所有实体类
  3. 记得导你使用的缓存产品的jar包

    <!-- hibernate-ehcache -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
        <version>5.0.7.Final</version>
    </dependency>
    

本节代码点击此处

posted @ 2019-12-11 14:04  _ann  阅读(968)  评论(0编辑  收藏  举报