大数跨境
0
0

强大!Spring Boot + JPA 实体类设计五大实战技巧

强大!Spring Boot + JPA 实体类设计五大实战技巧 Spring全家桶实战案例
2025-04-02
2
导读:实体类设计五大要点
Spring Boot 3实战案例锦集PDF电子书已更新至100篇!

🎉🎉《Spring Boot实战案例合集》目前已更新111个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

现在就订阅合集




环境:SpringBoot3.4.2



1. 简介

项目开发中,实体类的有效设计和实现对于构建健壮且易于维护的应用程序至关重要。JPA与Spring Boot的强大功能相结合,使开发人员能够简化数据库操作并创建高度功能化的应用程序。
本篇文章我们将深入探讨基于Spring Boot项目开发时,如何利用JPA设计实体类的重要最佳实践。通过遵循这些最佳实践,开发人员可以确保应用程序的完整性、性能和可扩展性。
2. 最佳实践

2.1 实体类与继承

  • 使用@Entity注解来标记您的实体类,以表明它们是JPA实体

  • 如果表名与类名不同,请使用@Table注解来指定表名

  • 对于应由多个实体继承的公共属性,可以考虑使用@MappedSuperclass

     

实体类基类设计

@MappedSuperclasspublic abstract class BaseEntity implements Serializable {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long id;  // 其它公共属性  @Temporal(TemporalType.TIMESTAMP)  private Date createTime ;  //getters, setters}

BaseEntity类被注解为@MappedSuperclass。它包含了你希望在多个实体类之间共享的公共字段。Employee类继承自BaseEntity,也就从超类继承了id, createTime字段。通过基类的设计实现了代码的复用性,并保持了实体层次的清晰和结构化。

具体实体类

@Entity@Table(name = "t_employees")public class Employee extends BaseEntity {    private String name ;  private String address ;  // getters, setters}

主键说明

  • 主键字段使用@Id注解

  • 主键生成策略使用@GeneratedValue注解(该注解有多种生成策略,如:GenerationType.IDENTITY、GenerationType.SEQUENCE等)

     

关联关系

  • 使用@OneToOne@OneToMany@ManyToOne@ManyToMany来定义实体之间的关系

  • 使用fetch属性来控制加载行为(例如,LAZY(延迟加载)或EAGER(急切加载))

  • 利用mappedBy来定义双向关联中的拥有方

     

@Entity@Table(name = "t_department")public class Department extends BaseEntity {  private String name;  private String code ;  @OneToMany(mappedBy = "department")  private List<Employee> employees = new ArrayList<>() ;  // getters, setters}@Entity@Table(name = "t_employee")public class Employee extends BaseEntity {  // ...  @ManyToOne  @JoinColumn(name = "department_id")  private Department department;  // getters, setters}

级联操作

  • 使用cascade属性来指定级联操作(例如,CascadeType.ALL、CascadeType.PERSIST)

  • 在使用级联删除(CascadeType.DELETE)时要特别小心,以避免意外丢失数据

     

public class Department extends BaseEntity {  // ...  @OneToMany(mappedBy = "department"    cascade = {      CascadeType.REFRESH      CascadeType.PERSIST      CascadeType.REMOVE    },    orphanRemoval = true  )  private List<Employee> employees = new ArrayList<>() ;}

说明:

  • 如果你将级联操作设置为CascadeType.ALL,所有操作(例如,持久化、合并、删除)都应该从父实体(Department)级联到子实体(Employee)

  • orphanRemoval = true:此选项指定当从Department集合中移除对某个Employee实体的引用时,这个孤立的Employee实体也应该从数据库中删除

     

如下示例,保存Department时会级联保存所有的Employee。

@Resourceprivate DepartmentRepository departmentRepository ;@Testpublic void testSave() {  Department department = new Department() ;  department.setCode("S0001") ;  department.setName("研发部") ;  Employee e1 = new Employee("张三""SC") ;  e1.setDepartment(department) ;  Employee e2 = new Employee("Pack""XJ") ;  e2.setDepartment(department) ;  department.setEmployees(List.of(e1, e2)) ;      this.departmentRepository.saveAndFlush(department) ;}

控制台输出

同样也适用于其它的级联操作。

2.2 有效性验证

  • 使用验证注解(如@NotNull@Size等)直接在实体类中强制实施数据完整性约束。

  • 将JPA验证与Spring的@Valid注解结合使用,以自动验证传入的数据。

     

@Entity@Table(name = "t_department")public class Department extends BaseEntity {  @NotEmpty(message = "部门名称不能为空")  @Length(min = 2)  private String name;  @NotEmpty(message = "部门代码不能为空")  private String code ;}

当我们执行如下代码时程序将抛出异常

@Testpublic void testSave() {  Department department = new Department() ;  department.setCode("S0001") ;  // 没有设置name属性  this.departmentRepository.saveAndFlush(department) ;}

注意,你需要开启如下配置:

spring:  jpa:    properties:      hibernate:        '[javax.persistence.validation.mode]': auto

2.3 审计

  • 通过添加如@CreatedBy@CreatedDate@LastModifiedBy@LastModifiedDate等字段来实现实体审计,以跟踪是哪个用户何时创建或修改了实体

  • 利用Spring的@EntityListeners来管理审计行为

     

如下比较完善的一个实体基类

@MappedSuperclass@EntityListeners(AuditingEntityListener.class)public abstract class AuditableEntity implements Serializable {  private static final long serialVersionUID = 1L;    @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long id ;  @Temporal(TemporalType.TIMESTAMP)  private Date createTime = new Date() ;  @CreatedBy  protected String createdBy;  @CreatedDate  @Column(nullable = false, updatable = false)  protected LocalDateTime createdDate;  @LastModifiedBy  protected String lastModifiedBy;  @LastModifiedDate  protected LocalDateTime lastModifiedDate;}

如上我们又定义了一个可以审计的实体基类;如果哪个实体需要被审计那么就继承该类即可。

@Entity@Table(name = "t_product")public class Product extends AuditableEntity {
  private String name;  private Double price;  // getters, setters}

注意,要使得审计功能生效,我们还需要做如下配置:

开启审计功能

@Configuration@EnableJpaAuditingpublic class JpaConfig {}

当前审计人Bean

我们需要提供一个你当前操作的人是谁的bean

@Componentpublic class SystemAuditorAware implements AuditorAware<String> {  @Override  public Optional<StringgetCurrentAuditor() {    return Optional.of("Pack") ;  }}

这里你需要根据自己的实际情况来编写。

2.4 DTO映射

  • 当查询数据时,考虑使用DTO投影来仅查询需要的字段,从而提高性能

  • 使用Spring Data JPA的@Query注解或查询方法来创建自定义投影

     

如下实体类

@Entity@Table(name = "t_author")public class Author extends BaseEntity {  private String name ;  private Integer age ;  private String address ;  private String sex ;  private String email ;}

该实体字段表多,我们可能只需要部分字段,如:name,sex,那么我们可以定义如下的投影:

public interface AuthorProjection {    String getName();  String getSex();}

使用@Query查询

public interface AuthorRepository extends JpaRepository<AuthorLong> {
  @Query("select e.name as name, e.sex as sex from Author e")  List<AuthorProjection> queryAuthors() ;}

注意,你需要在sql中使用 as 别名。

2.5 索引

在实体类上我们可以通过@Table注解的indexes属性指定列来创建索引。

@Entity@Table(name = "t_author", indexes = {    @Index(columnList = "name, sex")})public class Author extends BaseEntity {}

当服务启动时,会自动创建基于 "name", "sex" 2个字段的联合索引。

索引对于提高查询性能至关重要,尤其是在处理大型数据集时。根据你应用程序的查询模式,仔细选择哪些列要创建索引是非常关键的。



以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

在 Spring Boot 中加载属性文件的7种方法

这6个Spring高级开发技巧掌握了吗?

优雅!基于Spring Boot字段加密后的模糊查询,支持MyBatis, JPA

SpringBoot+Nginx+Lua接口性能提升N倍

高级版@ResponseBody,接口响应数据格式完全自定义

在SpringBoot项目中这几个注解你们还用吗?

优雅重构Spring Boot代码,我用这6种策略消灭if else

提升性能:Java工程师必备的20条SQL最佳实践

有多少人用过Spring的@Lookup注解?

性能排名第一的模板引擎 JTE 在 Spring Boot 中的应用

Spring Boot超大文件上传的正确方式

简单到离谱!Spring Boot三行代码实现邮件发送

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读195
粉丝0
内容832