为了维护数据库的历史记录或跟踪数据库表行的修改,我们创建了一个版本表,其中包含与原始表相同的字段。每当原始表被更改时,我们都会在版本表中创建另一个条目。 因此,对于每个更新查询,我们都必须在版本表中编写一个插入查询。 休眠中有一个模块可以管理对象的简单审核,而我们不必自己编写单独的插入查询。
Hibernate Envers提供了内置的机制来维护数据库中对象的历史记录。 Envers是Hibernate的库,它将帮助我们轻松实现审核功能。 这是由Adam Warski创建的。 从Hibernate 3.5开始,Envers作为Hibernate核心模块包含在内。 让我们举一个例子,说明如何使用Envers维护对象的历史记录。
这是Envers的pom依赖关系(版本将与您的休眠核心和实体管理器相同):
<dependency> <groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
<version>4.0.1.Final</version>
</dependency>
您必须在hibernate.cfg.xml中配置侦听器。
<mapping class="com.javaroots.model.User" />
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-insert"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-delete"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-update"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="pre-collection-remove"/>
<listener class="org.hibernate.envers.event.AuditEventListener" type="post-collection-recreate"/>
让我们以User类为例。 我们要跟踪用户字段的更新。 要为用户对象启用历史记录,我们需要使用@Audited批注。 如果在类级别上使用,则该类中的所有字段都将被视为可审计的,并且任何字段中的更改将在audit table中具有新条目。 如果我们希望某些字段不包含在历史记录中,则可以使用@NotAudited批注。 如果更改了NotAudited字段,那么审计表中将没有任何条目。这是用户类:
package com.javaroots.model;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Entity;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
/**
*
*
* @author Abhishek Somani
*
*/
@Entity
@Audited
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(length = 20)
private String firstName;
@Column(length = 20)
private String lastName;
@Column(length = 20)
@NotAudited
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
这是测试类,我们在其中创建用户表中的条目,然后更新它的field。
package com.javaroots.main;
import org.hibernate.Session;
import com.javaroots.model.User;
import com.javaroots.util.HibernateUtil;
public class HibernateTest {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
//one entry will be created in user table
//and audit entry created in user_aud table
session.beginTransaction();
User u = new User();
u.setFirstName("Amitabh");
u.setLastName("bachhan");
u.setPassword("God");
session.save(u);
session.getTransaction().commit();
session.beginTransaction();
User amitabh = (User)session.get(User.class,1l);
amitabh.setFirstName("Abhishek");
session.getTransaction().commit();
//no entry in audit table if we change password field
//because this field is marked as @notAudited
session.beginTransaction();
amitabh = (User)session.get(User.class,1l);
amitabh.setPassword("NotGod");
session.getTransaction().commit();
//get specific revision
AuditReader reader = AuditReaderFactory.get(HibernateUtil.getSessionFactory().openSession());
User abhishek = (User) reader.find(User.class, new Long(1), 2);
System.out.println(abhishek.getFirstName() + " " + abhishek.getLastName());
//get all revision
List versions = reader.getRevisions(User.class, new Long(1));
for (Number number : versions) {
System.out.print(number + " ");
}
}
}
首先,在用户表中创建一个用户行。在user_aud中创建一个具有修订ID和用户表字段的行。 在revinfo表中使用修订ID和时间戳创建一行。 这两个条目由envers自动完成。 这是sql查询和表结构:
Hibernate:
insert
into
User
(firstName, lastName, password)
values
(?, ?, ?)
Hibernate:
insert
into
REVINFO
(REVTSTMP)
values
(?)
Hibernate:
insert
into
User_AUD
(REVTYPE, firstName, lastName, id, REV)
values
(?, ?, ?, ?, ?)
Hibernate:
update
User
set
firstName=?,
lastName=?,
password=?
where
id=?
Hibernate:
insert
into
REVINFO
(REVTSTMP)
values
(?)
Hibernate:
insert
into
User_AUD
(REVTYPE, firstName, lastName, id, REV)
values
(?, ?, ?, ?, ?)
Hibernate:
update
User
set
firstName=?,
lastName=?,
password=?
where
id=?
Hibernate:
select
user_aud0_.id as id4_,
user_aud0_.REV as REV4_,
user_aud0_.REVTYPE as REVTYPE4_,
user_aud0_.firstName as firstName4_,
user_aud0_.lastName as lastName4_
from
User_AUD user_aud0_
where
user_aud0_.REV=(
select
max(user_aud1_.REV)
from
User_AUD user_aud1_
where
user_aud1_.REV<=?
and user_aud0_.id=user_aud1_.id
)
and user_aud0_.REVTYPE<>?
and user_aud0_.id=?
Abhishek bachhan
Hibernate:
select
user_aud0_.REV as col_0_0_
from
User_AUD user_aud0_ cross
join
REVINFO defaultrev1_
where
user_aud0_.id=?
and user_aud0_.REV=defaultrev1_.REV
order by
user_aud0_.REV asc
mysql> select * from user;
+----+-----------+----------+---------------+
| id | firstName | lastName | password |
+----+-----------+----------+---------------+
| 1 | Amitabh | bachchan | God|
+----+-----------+----------+---------------+
1 row in set (0.03 sec)
mysql> select * from user_aud;
+----+-----+---------+-----------+----------+
| id | REV | REVTYPE | firstName | lastName |
+----+-----+---------+-----------+----------+
| 1 | 1 | 0 | Amitabh | bachchan |
+----+-----+---------+-----------+----------+
1 row in set (0.00 sec)
mysql> select * from revinfo;
+-----+---------------+
| REV | REVTSTMP |
+-----+---------------+
| 1 | 1375956506278|
+-----+---------------+
1 row in set (0.00 sec)
mysql> select * from user;
+----+-----------+----------+----------------+
| id | firstName | lastName | password |
+----+-----------+----------+----------------+
| 1 | Amitabh | bachchan| NotGod |
+----+-----------+----------+----------------+
1 row in set (0.00 sec)
mysql> select * from user_aud;
+----+-----+---------+-----------+----------+
| id | REV | REVTYPE | firstName | lastName |
+----+-----+---------+-----------+----------+
| 1 | 1 | 0 | Amitabh | bachchan |
| 1 | 2 | 1 | Abhishek | bachchan|
+----+-----+---------+-----------+----------+
2 rows in set (0.00 sec)
mysql> select * from revinfo;
+-----+---------------+
| REV | REVTSTMP |
+-----+---------------+
| 1 | 1375956506278|
| 2 | 1375956506328|
+-----+---------------+
2 rows in set (0.00 sec)
翻译自: https://www.javacodegeeks.com/2013/09/how-to-maintain-history-of-tables-in-hibernate.html