JPA Hibernate如何将内部Audit类字段映射至实体同一张表?
实现JPA Hibernate将Audit字段映射到同表的两种实用方案
我来帮你搞定这个审计字段的映射问题,结合你的需求(Audit类的字段和实体属性存在同一张数据库表),有两种非常贴合场景的实现方式,下面给你一步步拆解:
方案一:使用@Embeddable + @Embedded(可嵌入组件)
这种方式把Audit定义成一个可复用的嵌入类,实体类直接嵌入这个组件,最终所有字段都会映射到同一张表中,非常适合这种跨实体复用审计字段的场景。
1. 定义Audit嵌入类
先把Audit类标记为@Embeddable,同时给每个字段添加对应的JPA注解,匹配数据库列的定义:
import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import java.time.LocalDateTime; @Embeddable public class Audit { // 创建时间:设置为不可更新,默认值复用数据库的CURRENT_TIMESTAMP @Column(name = "created_time", nullable = false, updatable = false, columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP") private LocalDateTime createdTime; // 创建用户:设置为不可更新,确保创建后不会被修改 @Column(name = "created_user", nullable = false, updatable = false) private Long createdUser; // 更新时间:支持数据库层面自动更新,设置ON UPDATE CURRENT_TIMESTAMP @Column(name = "updated_time", nullable = false, columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private LocalDateTime updatedTime; // 更新用户 @Column(name = "updated_user", nullable = false) private Long updatedUser; // 必须添加无参构造器(JPA规范要求),以及必要的getter/setter public Audit() {} // getter和setter方法... }
2. 在实体类中嵌入Audit组件
比如你的USER表对应的User实体,用@Embedded标记Audit字段,这样Audit的所有字段就会自动映射到USERS表中:
import jakarta.persistence.*; @Entity @Table(name = "USERS") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "display_name", nullable = false, length = 30) private String displayName; @Column(name = "active", nullable = false, columnDefinition = "BOOLEAN NOT NULL DEFAULT FALSE") private Boolean active; // 嵌入Audit组件,所有Audit字段会直接映射到USERS表的对应列 @Embedded private Audit audit; // 无参构造器、getter/setter... }
如果你的Audit字段名和数据库列名不匹配,还可以用@AttributeOverride单独指定列名,比如:
@Embedded @AttributeOverrides({ @AttributeOverride(name = "createdTime", column = @Column(name = "create_time")), @AttributeOverride(name = "updatedTime", column = @Column(name = "modify_time")) }) private Audit audit;
方案二:使用@MappedSuperclass(映射父类)
这种方式把Audit作为所有需要审计的实体的父类,用@MappedSuperclass标记,子类继承后会自动继承父类的字段映射,同样会把所有字段放到同一张表中。
1. 定义Audit父类
import jakarta.persistence.Column; import jakarta.persistence.MappedSuperclass; import java.time.LocalDateTime; @MappedSuperclass public abstract class Audit { @Column(name = "created_time", nullable = false, updatable = false, columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP") private LocalDateTime createdTime; @Column(name = "created_user", nullable = false, updatable = false) private Long createdUser; @Column(name = "updated_time", nullable = false, columnDefinition = "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") private LocalDateTime updatedTime; @Column(name = "updated_user", nullable = false) private Long updatedUser; // 无参构造器、getter/setter... }
2. 实体类继承Audit父类
User实体直接继承Audit,这样USER表就会包含父类的所有审计字段:
import jakarta.persistence.*; @Entity @Table(name = "USERS") public class User extends Audit { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "display_name", nullable = false, length = 30) private String displayName; @Column(name = "active", nullable = false, columnDefinition = "BOOLEAN NOT NULL DEFAULT FALSE") private Boolean active; // 无参构造器、getter/setter... }
额外优化:自动填充审计字段
如果不想每次手动设置createdTime、updatedTime、createdUser、updatedUser,还可以用Hibernate的注解或者Spring Data JPA的审计功能简化操作:
- 用
@CreationTimestamp自动填充创建时间,@UpdateTimestamp自动填充更新时间:@CreationTimestamp @Column(name = "created_time", nullable = false, updatable = false) private LocalDateTime createdTime; @UpdateTimestamp @Column(name = "updated_time", nullable = false) private LocalDateTime updatedTime; - 对于创建/更新用户,可以实现
AuditorAware接口,结合@CreatedBy和@LastModifiedBy注解来自动填充,彻底告别手动赋值的繁琐。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

