为了维护数据库的历史记录或跟踪数据库表行的修改,我们创建了一个版本表,其中包含与原始表相同的字段。每当原始表被更改时,我们都会在版本表中创建另一个条目。 因此,对于每个更新查询,我们都必须在版本表中编写一个插入查询。 休眠中有一个模块可以管理对象的简单审核,而我们不必自己编写单独的插入查询。
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)@NotAuditedprivate 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 tablesession.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 @notAuditedsession.beginTransaction();amitabh = (User)session.get(User.class,1l);amitabh.setPassword("NotGod");session.getTransaction().commit();//get specific revisionAuditReader 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 revisionList 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 intoUser(firstName, lastName, password) values(?, ?, ?)
Hibernate: insert intoREVINFO(REVTSTMP) values(?)
Hibernate: insert intoUser_AUD(REVTYPE, firstName, lastName, id, REV) values(?, ?, ?, ?, ?)
Hibernate: updateUser setfirstName=?,lastName=?,password=? whereid=?
Hibernate: insert intoREVINFO(REVTSTMP) values(?)
Hibernate: insert intoUser_AUD(REVTYPE, firstName, lastName, id, REV) values(?, ?, ?, ?, ?)
Hibernate: updateUser setfirstName=?,lastName=?,password=? whereid=?
Hibernate: selectuser_aud0_.id as id4_,user_aud0_.REV as REV4_,user_aud0_.REVTYPE as REVTYPE4_,user_aud0_.firstName as firstName4_,user_aud0_.lastName as lastName4_ fromUser_AUD user_aud0_ whereuser_aud0_.REV=(selectmax(user_aud1_.REV) fromUser_AUD user_aud1_ whereuser_aud1_.REV<=? and user_aud0_.id=user_aud1_.id) and user_aud0_.REVTYPE<>? and user_aud0_.id=?
Abhishek bachhan
Hibernate: selectuser_aud0_.REV as col_0_0_ fromUser_AUD user_aud0_ cross joinREVINFO defaultrev1_ whereuser_aud0_.id=? and user_aud0_.REV=defaultrev1_.REV order byuser_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