当前位置: 首页 > article >正文

spring-data-jpa 一对多,多对一,多对多

spring-data-jpa 一对多,多对一,多对多

首先介绍几个主要用到的注解

  • @ManyToOne 多对一
  • @ManyToMany 多对多
  • @OneToMany 一对多
  • @JoinColumn 两表之间的关联
  • @JsonIgnoreProperties 忽略属性(避免Jason套娃)

比如我有两张表:customerbill,一个customer数据对应bill中多条数据,两表通过 customer.idbill.customer_id 关联

实体如下

@Entity
@Table(name = "bill")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Bill {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "customer_id")
    private Long customerId;
    @Column(name = "bill_no")
    private String billNo;
    @Column(name = "bill_amount")
    private float billAmount;
    @Column(name = "bill_date")
    private LocalDate billDate;
}
@Entity
@Table(name = "customer")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "customer_name")
    private String customerName;
    @Column(name = "customer_age")
    private Integer customerAge;
    @Column(name = "customer_account")
    private String customerAccount;
    @Column(name = "customer_password")
    private String customerPassword;
}

为了使两张表关联起来,需要在实体中加入关联的逻辑

customer.java 中加入

@OneToMany( targetEntity = Bill.class, fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
@JsonIgnoreProperties(value = {"customer"})
@JoinColumn(name = "customer_id",
        referencedColumnName = "id",
        insertable = false,
        updatable = false )
private List<Bill> bills;

Bill.java 中加入

@ManyToOne(targetEntity = Customer.class, fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
@JsonIgnoreProperties(value = {"bills"})
@JoinColumn(name = "customer_id",
        referencedColumnName = "id",
        insertable = false,
        updatable = false )
private Customer customer;

下面说说如何配置使用

@ManyToOne,@ManyToMany,@OneToMany

意义就不解释了,通过注解名称就可以看懂,只说明属性

  • targetEntity

    类型:Class<?>

    指定关系的另一端实体的类型。比如上述代码中,customer实体类与bill实体关联,所以我在customer类的bills属性上的注解@OneToMany的targetEntity属性赋值Bill.class;这个属性是可选的,如果不指定,spring-data-jpa 将根据字段的类型来确定目标实体类,建议写上。

  • fetch

    类型:javax.persistence.FetchType

    指定加载策略:立即加载(FetchType.EAGER)和 延迟加载(FetchType.LAZY)

    • 立即加载:加载主实体时,其关联的实体或集合也会同时被加载。这种策略通过减少数据库查询次数来提高性能,因为它尝试在一个查询中获取所有关联实体的数据

    • 延迟加载:加载主实体时,其关联的实体或集合不会立即被加载,而是在第一次访问关联属性时才进行加载。这种策略可以减少不必要的数据库查询,因为只有在实际需要数据时才会进行加载

      使用延迟加载,我遇到了一个坑,这里顺便记录,有时一条a表数据对应几十万条b表数据,使用立即加载肯定是不合适的,故而用了延迟加载,使用延迟加载的时候,报错如下

       No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: java.util.ArrayList[0]->com.train.spr.entities.Bill["customer"]->com.train.spr.entities.Customer$HibernateProxy$g4FqEJel["hibernateLazyInitializer"])
      

      如果你也遇到同样的问题,用如下方式解决
      在实体类名上加一句代码,如下

      @JsonIgnoreProperties(value = {"hibernateLazyInitializer"})
      public class Bill {
      // 实现(略)
      }
      
  • cascade

    类型:javax.persistence.CascadeType[]

    级联操作,定义哪些持久化操作(如保存、更新、删除)应该被级联到关系的另一端实体。CascadeType是枚举类,可选值如下

    • CascadeType.ALL:表示所有的持久化操作都会级联到关系的另一端实体。这包括:PERSIST、MERGE、REMOVE、REFRESH 和 DETACH
    • CascadeType.PERSIST:当实体的对象被创建时,相关的实体也会被级联保存
    • CascadeType.MERGE:当实体被合并到当前持久化上下文时,相关的实体也会被级联合并
    • CascadeType.REMOVE:当实体被删除时,相关的实体也会被级联删除(删customer表中一条数据,jpa自动删除bill表中关联数据)
    • CascadeType.REFRESH:当实体被刷新时,相关的实体也会被级联刷新
    • CascadeType.DETACH:当实体被分离出持久化上下文时,相关的实体也会被级联分离

@JoinColumns 关联关系集合

若两张表之间通过多个字段相关联,比如A表和B表通过A.CREATE_DATE = B.CREATE_DATE AND A.ID = B.A_ID相关联,使用 @JoinColumns 包裹 @JoinColumn 集合

@JoinColumn 关联关系

定义两个实体之间以什么字段相关联;属性如下

  • name

    类型:string

    指定本表关联其他表的本表列名称

  • referencedColumnName

    类型:string

    指定本表关联其他表的其他表列名称(其他表的列名称也叫做外键)

  • unique

    类型:bool

    指定外键列是否具有唯一性约束(可选,默认false),拿我给的例子来说,一个customer可以对应多个bill,但是一个bill仅能对应一个customer,所以bill类中customer属性的@JoinColumn注解的属性改为true,表示customer中仅能有唯一一个实体与之对应

  • nullable

    类型:bool

    指定外键列是否可以为 NULL(可选,默认true),表示列可以为 NULL

  • insertable

    类型:bool

    指定外键列是否在插入操作时可被插入(可选,默认true)

  • updatable

    类型:bool

    指定外键列是否在更新操作时可被更新(可选,默认true)

  • columnDefinition

    类型:string

    指定外键列的 SQL 类型定义。这允许你自定义列的 SQL 类型和大小等详细信息(可选)

  • table

    类型:string

    指定外键列所在的表的名称。这在多表继承的场景中使用

  • foreignKey

    类型:String

    指定外键约束的名称。如果未指定,spring-data-jpa根据实体关系自动生成一个外键约束名称(可选)

@JsonIgnoreProperties JSON属性忽略

如果实体类的关联属性上不加此注解,那么你查出来的json数据结构绝对是“套娃”;属性如下

  • value

    类型:string[]

    指定忽略对方实体类中的某个属性转换为json,比如我上述例子中 customer.java 中有属性 bills,而bill.java中又有customer,所以他俩得互相忽略对方实体类中对自己引用的属性名,故而customer实体中忽略bill中的customer,bill实体中忽略customer中的bills。这么说有点抽象哈,不过你自己试一试就很轻松能明白了

  • ignoreUnknown

    类型:boolean

    ignoreUnknown 属性只适用于从 JSON 数据到 Java 对象的反序列化过程,当设置为 true 时,如果 JSON 中包含未在 Java 类中定义的属性,这些属性将被忽略。这有助于处理 JSON 数据中可能存在的额外字段,而不会抛出异常(可选)

  • allowGetters

    类型:boolean

    当设置为 true 时,即使属性没有 setter 方法,也可以通过 getter 方法访问。这通常用于只读属性(可选)

  • allowSetters

    类型:boolean

    当设置为 true 时,即使属性没有 getter 方法,也可以通过 setter 方法设置值。这通常用于只写属性(可选)


暂且写到这儿,后续有总结再补


http://www.kler.cn/a/383450.html

相关文章:

  • “高精度算法”思想 → 大数阶乘
  • 浅谈TARA在汽车网络安全中的关键角色
  • MySQL索引为什么是B+树
  • Java重要面试名词整理(四):并发编程(下)
  • kimi搜索AI多线程批量生成txt原创文章软件-不需要账号及key
  • idea设置控制台日志输出自动换行
  • PathVariable annotation was empty on param 0.问题解决
  • 《C语言程序设计现代方法》note-3 选择语句 循环语句
  • C++(一)
  • 开学轻松逆袭孩子的学习利器培养自律习惯,提高学习效率❗❗让习惯养成更轻松~
  • 【Rust Crate之Actix Web(一)】
  • Sigrity Power SI 3D-EM Inductance Extraction模式如何进行电感的提取操作指导(一)
  • 计算机体系结构知识(二)-gdb和args
  • Linux -- 初识线程
  • 【鉴权】OAuth 2.0: 高度灵活与安全的身份认证框架
  • 百度实习生内推
  • Java实战项目-基于微信小程序的校园生活互助服务小程序
  • 供热的一些基础技术数据
  • 2024年10月全球人工智能领域的重大事件盘点
  • Prompt Engineering介绍
  • AI大模型重塑软件开发流程:定义、应用场景、优势、挑战及未来展望
  • 父组件调用函数式子组件,并向子组件传递函数参数。
  • Web3中的区块链技术:从基础设施到应用的演变
  • Python Matplotlib:基本图表绘制指南
  • 社交电商全球化:开源链动模式的引领与挑战
  • uniapp 整合 OpenLayers - 测距测面