Spring Boot 中 JPA 未自动填充的审计字段
Auditing fields not automatically filled by JPA in Spring Boot
我有以下实体,它反映了某种后台任务并将被更新。我认为使用 JPA 审计会很有用,所以我像这样包含它:
@Entity
@RequiredArgsConstructor
@Getter
@Setter
@Table(name = "FOO")
public class FooJob{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private long id;
@LastModifiedDate
@Column(name = "FINISHED", nullable = false)
private LocalDateTime finished;
...
}
@Repository
public interface FooJobRepository
extends JpaRepository<FooJob, Long>,
JpaSpecificationExecutor<FooJob> {}
并且我在 spring-boot 应用程序
上启用了 @EnableJpaAuditing
spring版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath />
</parent>
但是当运行代码是这样的:
@Service
@Transactional
/*package*/ class FooJobService{
public void run() {
FooJob job = createJob();
....
}
private FooJob createJob(){
FooJob job = new FooJob();
job.setSomeValue("123");
//Do not set "finished" date here
repo.saveAndFlush(job); //THIS LINE THROWS EXCEPTION
}
}
我会得到以下异常:
org.springframework.dao.DataIntegrityViolationException: not-null
property references a null or transient value :
my.package.entity.FooJob.finished; nested exception is
org.hibernate.PropertyValueException: not-null property references a
null or transient value : my.package.entity.FooJob.finished
为什么这不起作用?
您需要为您的实体添加更多注释以便对其进行审核(至少 @Audited
、@AuditTable
和 @EntityListeners
。
示例:
@Entity
@Table(name = "my_table")
@AuditTable("my_table_audit")
@Audited
@EntityListeners(AuditingEntityListener.class)
public class MyEntity{
@Column(name = "created_date", nullable = false)
@CreatedDate
private Date createdDate;
@Column(name = "modified_date")
@LastModifiedDate
private Date modifiedDate;
@Column(name = "created_by")
@CreatedBy
private String createdBy;
@Column(name = "modified_by")
@LastModifiedBy
private String modifiedBy;
@Version
private Long version;
我也不确定 @LastModifiedDate
是否可以与类型 LocalDateTime
一起使用。
您还需要一个审计框架,例如 Hibernate Envers。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
如果您使用的是 Hibernate Envers 和 MySQL,审计应该是这样的:
CREATE TABLE revinfo
(
revision_number integer AUTO_INCREMENT,
REVTSTMP bigint,
CONSTRAINT revinfo_pkey PRIMARY KEY (revision_number)
);
CREATE TABLE IF NOT EXISTS my_table
(
...
created_date datetime DEFAULT now(),
modified_date datetime DEFAULT now(),
created_by VARCHAR(100) NULL,
modified_by VARCHAR(100) NULL,
version INT NULL
);
CREATE TABLE IF NOT EXISTS my_table_audit
(
...
created_date datetime,
modified_date datetime,
created_by VARCHAR(100),
modified_by VARCHAR(100),
version INT,
revision_number integer,
revision_type smallint,
FOREIGN KEY fk_my_table_audit_rev_num (revision_number) REFERENCES REVINFO (revision_number)
);
您需要在主 class 或配置 class 中注释 @EnableJpaAuditing
(class 和 @Configuration
)
并且必须用 @EntityListeners(AuditingEntityListener.class)
.
注释实体 class
如果您只更新完成日期,请将此添加到实体:
@EntityListeners(AuditingEntityListener.class)
我有以下实体,它反映了某种后台任务并将被更新。我认为使用 JPA 审计会很有用,所以我像这样包含它:
@Entity
@RequiredArgsConstructor
@Getter
@Setter
@Table(name = "FOO")
public class FooJob{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
private long id;
@LastModifiedDate
@Column(name = "FINISHED", nullable = false)
private LocalDateTime finished;
...
}
@Repository
public interface FooJobRepository
extends JpaRepository<FooJob, Long>,
JpaSpecificationExecutor<FooJob> {}
并且我在 spring-boot 应用程序
上启用了@EnableJpaAuditing
spring版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath />
</parent>
但是当运行代码是这样的:
@Service
@Transactional
/*package*/ class FooJobService{
public void run() {
FooJob job = createJob();
....
}
private FooJob createJob(){
FooJob job = new FooJob();
job.setSomeValue("123");
//Do not set "finished" date here
repo.saveAndFlush(job); //THIS LINE THROWS EXCEPTION
}
}
我会得到以下异常:
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value : my.package.entity.FooJob.finished; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : my.package.entity.FooJob.finished
为什么这不起作用?
您需要为您的实体添加更多注释以便对其进行审核(至少 @Audited
、@AuditTable
和 @EntityListeners
。
示例:
@Entity
@Table(name = "my_table")
@AuditTable("my_table_audit")
@Audited
@EntityListeners(AuditingEntityListener.class)
public class MyEntity{
@Column(name = "created_date", nullable = false)
@CreatedDate
private Date createdDate;
@Column(name = "modified_date")
@LastModifiedDate
private Date modifiedDate;
@Column(name = "created_by")
@CreatedBy
private String createdBy;
@Column(name = "modified_by")
@LastModifiedBy
private String modifiedBy;
@Version
private Long version;
我也不确定 @LastModifiedDate
是否可以与类型 LocalDateTime
一起使用。
您还需要一个审计框架,例如 Hibernate Envers。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
如果您使用的是 Hibernate Envers 和 MySQL,审计应该是这样的:
CREATE TABLE revinfo
(
revision_number integer AUTO_INCREMENT,
REVTSTMP bigint,
CONSTRAINT revinfo_pkey PRIMARY KEY (revision_number)
);
CREATE TABLE IF NOT EXISTS my_table
(
...
created_date datetime DEFAULT now(),
modified_date datetime DEFAULT now(),
created_by VARCHAR(100) NULL,
modified_by VARCHAR(100) NULL,
version INT NULL
);
CREATE TABLE IF NOT EXISTS my_table_audit
(
...
created_date datetime,
modified_date datetime,
created_by VARCHAR(100),
modified_by VARCHAR(100),
version INT,
revision_number integer,
revision_type smallint,
FOREIGN KEY fk_my_table_audit_rev_num (revision_number) REFERENCES REVINFO (revision_number)
);
您需要在主 class 或配置 class 中注释 @EnableJpaAuditing
(class 和 @Configuration
)
并且必须用 @EntityListeners(AuditingEntityListener.class)
.
如果您只更新完成日期,请将此添加到实体:
@EntityListeners(AuditingEntityListener.class)