问题我在JPA中使用hibernate envers(@Auded)并具有以下行为。如果在两次更新之间对实体进行了搜索,它似乎会跳过历史表中的一个版本。
使用Hibernate 5.5.7、MSSQL Server 15、Java1.8
以下是步骤
预期结果在我的历史记录表中,应该有相同数量的记录与我的版本列中的数字匹配。(例如,如果版本为2,则应该有3条记录用于0、1和2)
实际结果历史表中只有两行一个版本=0,另一个版本=2所以审计表中缺少版本1。
更多想法这似乎正在发生,因为在第3步中,Hibernate在我们搜索时会自动刷新。当有自动刷新时,我的实体版本会更新,因为它发生了变化。但是对于那个版本,没有生成历史记录。
是否有一些解决方法来获取历史表中的“缺失”版本?或者,在设置@审核表时,我可能缺少一些步骤。
这是项目的链接:
这是我的代码Main.java
package se.navod.platform.test.hibernate;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
public class Main {
private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("PlatformTest");
public static void main(String[] args) {
EntityTransaction transaction = null;
try {
int id = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE - 1);
String name = "Name_" + id;
create(id, name, 10);// Create the student
EntityManager manager = entityManagerFactory.createEntityManager();
transaction = manager.getTransaction();
transaction.begin();// Start the transaction
Student student1 = findStudentByPropertyValue(manager, name, "name");// Retrieve the student by name
student1.setName("NewName");// Change the name
// Retrieve the same student again (by id)
Student student2 = findStudentByPropertyValue(manager, "" + id, "studentId");
student2.setAge(50);// Change the age
manager.persist(student2);// Persist and commit
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
if (transaction != null) {
transaction.rollback();
}
} finally {
if (entityManagerFactory != null) {
entityManagerFactory.close();
}
}
}
public static Student create(int id, String name, int age) {
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = null;
try {
transaction = manager.getTransaction();
transaction.begin();
Student stu = new Student(id, name, age);
manager.persist(stu);
transaction.commit();
return stu;
} catch (Exception ex) {
if (transaction != null) {
transaction.rollback();
}
ex.printStackTrace();
throw ex;
} finally {
manager.close();
}
}
private static Student findStudentByPropertyValue(EntityManager manager, String value, String property) {
CriteriaBuilder criteriaBuilder = manager.getCriteriaBuilder();
CriteriaQuery<Student> criteriaQuery = criteriaBuilder.createQuery(Student.class);
Root<Student> itemRoot = criteriaQuery.from(Student.class);
Predicate predicate = criteriaBuilder.equal(itemRoot.get(property), value);
criteriaQuery.where(predicate);
criteriaQuery.orderBy(criteriaBuilder.asc(itemRoot.get("id")));
List<Student> items = manager.createQuery(criteriaQuery).getResultList();
return items.size() == 0 ? null : items.get(0);
}
}
实体:Student.java
package se.navod.platform.test.hibernate;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
import org.hibernate.envers.Audited;
@Entity
@Table(name = "student")
@Audited
public class Student implements Serializable {
private static final long serialVersionUID = -834531085311709309L;
@Column(name = "student_id", unique = true)
private int studentId;
@Id
@Column(name = "primaryKey")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "student_name", nullable = false)
private String name;
@Column(name = "student_age", nullable = false)
private int age;
@Version
private long version;
public Student() {
super();
}
public Student(int studentId, String name, int age) {
super();
this.studentId = studentId;
this.name = name;
this.age = age;
}
public void setId(int id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return id + "\t" + name + "\t" + age;
}
}
上一页. xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="PlatformTest"
transaction-type="RESOURCE_LOCAL">
<!-- Persistence provider -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- Entity classes -->
<class>se.navod.platform.test.hibernate.Student</class>
<properties>
<property name="javax.persistence.jdbc.url"
value="jdbc:jtds:sqlserver://localhost:1433/Test;prepareSQL=0;" />
<!-- The database username -->
<property name="javax.persistence.jdbc.user" value="spider3" />
<!-- The database password -->
<property name="javax.persistence.jdbc.password"
value="spider3" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.SQLServer2012Dialect" />
<property name="org.hibernate.envers.audit_table_suffix"
value="_History" />
<property
name="org.hibernate.envers.do_not_audit_optimistic_locking_field"
value="false" />
<property name="org.hibernate.envers.revision_field_name"
value="revision" />
<property
name="org.hibernate.envers.revision_type_field_name"
value="revisionType" />
</properties>
</persistence-unit>
</persistence>
DB表脚本
USE [Test]
GO
/****** Object: Table [dbo].[student] Script Date: 9/13/2021 12:07:13 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[student](
[student_id] [int] NULL,
[student_name] [nchar](1000) NULL,
[student_age] [int] NULL,
[primaryKey] [bigint] IDENTITY(1,1) NOT NULL,
[version] [bigint] NOT NULL,
CONSTRAINT [PK_persionId] PRIMARY KEY NONCLUSTERED
(
[primaryKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[student_History](
[student_id] [int] NULL,
[student_name] [nchar](1000) NULL,
[student_age] [int] NULL,
[primaryKey] [bigint] NOT NULL,
[version] [bigint] NOT NULL,
[revision] [int] NOT NULL,
[revisionType] [tinyint] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[REVINFO](
[id] [int] NULL,
[REVTSTMP] [bigint] NOT NULL
) ON [PRIMARY]
GO
这是意料之中的。如果您希望创建多个版本,请查看以下讨论:https://discourse.hibernate.org/t/envers-create-multiple-revisions-in-one-transaction/5138/2