Backend Development 11 min read

Master Spring Boot 3 Entity Design: Best Practices & Real‑World Examples

This article walks through essential Spring Boot 3 JPA entity design techniques—including inheritance, primary‑key mapping, relationship handling, cascade operations, validation, auditing, DTO projection, and index creation—providing clear code examples and configuration tips for building robust, maintainable backend services.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Spring Boot 3 Entity Design: Best Practices & Real‑World Examples

Environment

Spring Boot 3.4.2

1. Introduction

Effective entity design is crucial for building robust and maintainable applications. Combining JPA with Spring Boot simplifies database operations and enables highly functional applications.

2. Best Practices

2.1 Entity and Inheritance

Mark entity classes with @Entity .

Use @Table when the table name differs from the class name.

Extract common fields into a superclass annotated with @MappedSuperclass .

Example of a base entity:

<code>@MappedSuperclass
public abstract class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // other common fields
    @Temporal(TemporalType.TIMESTAMP)
    private Date createTime;
    // getters, setters
}
</code>

The Employee class extends BaseEntity , inheriting id and createTime :

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

Primary Key

Annotate the primary‑key field with @Id .

Specify generation strategy with @GeneratedValue (e.g., GenerationType.IDENTITY , GenerationType.SEQUENCE ).

Relationships

Define associations using @OneToOne , @OneToMany , @ManyToOne , @ManyToMany .

Control loading behavior with the fetch attribute (LAZY or EAGER).

Use mappedBy to designate the owning side in bidirectional relationships.

Example of a department‑employee relationship:

<code>@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 {
    private String name;
    private String address;
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
    // getters, setters
}
</code>

Cascade Operations

Specify cascade behavior with the cascade attribute (e.g., CascadeType.ALL , CascadeType.PERSIST ).

Be cautious with CascadeType.DELETE to avoid accidental data loss.

Saving a department cascades to its employees:

<code>@Resource
private DepartmentRepository departmentRepository;

@Test
public 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));
    departmentRepository.saveAndFlush(department);
}
</code>

Console output:

2.2 Validation

Apply validation annotations such as @NotNull , @Size directly on entity fields.

Combine JPA validation with Spring's @Valid to automatically validate incoming data.

Example with validation constraints:

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

Saving a department without setting name triggers a validation exception:

<code>@Test
public void testSave() {
    Department department = new Department();
    department.setCode("S0001");
    // name not set
    departmentRepository.saveAndFlush(department);
}
</code>

Enable validation in application.yml (or application.properties ) with:

<code>spring:
  jpa:
    properties:
      hibernate:
        '[javax.persistence.validation.mode]': auto
</code>

2.3 Auditing

Use @CreatedBy , @CreatedDate , @LastModifiedBy , @LastModifiedDate to track who created or modified an entity.

Apply @EntityListeners(AuditingEntityListener.class) to the base class.

Auditable base entity example:

<code>@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditableEntity implements Serializable {
    @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;
}
</code>

Entity extending the auditable base:

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

Enable auditing in a configuration class:

<code>@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
</code>

Provide the current auditor bean:

<code>@Component
public class SystemAuditorAware implements AuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("Pack");
    }
}
</code>

2.4 DTO Projection

Define a projection interface to fetch only required fields:

<code>public interface AuthorProjection {
    String getName();
    String getSex();
}
</code>

Repository query using @Query with aliases:

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

2.5 Indexes

Create database indexes via the indexes attribute of @Table :

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

Indexes improve query performance, especially for large data sets; choose indexed columns based on your query patterns.

backend developmentSpring BootHibernateAuditingJPAEntity Design
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.