测试版本:
Hibernate 3.3.2
Hibernate envers 1.2.2.ga-hibernate-3.3
介绍:
Hibernate Envers目的是根据对实体的设置,提供记录执行数据变更历史的功能(数据变更版本)。它实现原理是通过对Hibernate的操作事件监听并根据
基于Annoatation的配置来记录修改数据的内容。
1. 配置方法
基于Spring的配置内容如下:
1.1 配置Envers事件监听器
1 <bean id="sessionFactory"
2 class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
3 <property name="dataSource">
4 <ref local="dataSource" />
5 </property>
6 <property name="eventListeners">
7 <map>
8 <entry key="post-insert" value-ref="enversEventListener" />
9 <entry key="post-update" value-ref="enversEventListener" />
10 <entry key="post-delete" value-ref="enversEventListener" />
11 <entry key="post-collection-recreate" value-ref="enversEventListener" />
12 <entry key="pre-collection-remove" value-ref="enversEventListener" />
13 <entry key="pre-collection-update" value-ref="enversEventListener" />
14 </map>
15 </property>
16 <property name="configLocation" value="classpath:conf/hibernate.cfg.xml" />
17 </bean>
18
19 <bean name="enversEventListener" class="org.hibernate.envers.event.AuditEventListener" />
所有的监听事件都由 AuditEventListener 来处理。
1.2 配置 Envers相关属性
org.hibernate.envers.audit_table_prefix 配置数据修改记录表名的前缀规则 默认值:空
org.hibernate.envers.audit_table_suffix 配置数据修改记录表名的后缀规则 默认值:_AUD
org.hibernate.envers.revision_field_name 配置数据修改记录表版本号字段名 默认值: REV
org.hibernate.envers.revision_type_field_name 配置数据修改记录表修改类型字段名 默认值: REVTYPE . 0表示新增加,1修改 2删除
org.hibernate.envers.revision_on_collection_change 配置是否支持关联表修改时记录修改记录 默认值:true
org.hibernate.envers.do_not_audit_optimistic_locking_field 配置是否不对乐观锁字段修改时记录修改记录,即使用(@Version)字段 默认值:true
org.hibernate.envers.store_data_at_delete 配置是否在删除操作时,只保存id值还是全部的值。 默认值:false 只记录id
org.hibernate.envers.default_schema 配置数据修改记录表的schema 默认值:null
org.hibernate.envers.default_catalog 配置数据修改记录表的catalog 默认值:null
属性配置方法: hibernate.cfg.xml
<property name="org.hibernate.envers.audit_table_suffix">_Audit</property>
<property name="org.hibernate.envers.audit_table_prefix">log_</property>
<property name="org.hibernate.envers.revision_field_name">rev</property>
<property name="org.hibernate.envers.revision_type_field_name">revtype</property>
<property name="org.hibernate.envers.revision_on_collection_change">true</property>
<property name="org.hibernate.envers.do_not_audit_optimistic_locking_field">true</property>
<property name="org.hibernate.envers.store_data_at_delete">true</property>
<property name="org.hibernate.envers.default_schema"></property>
<property name="org.hibernate.envers.default_catalog"></property>
使用hibernate auto-generate功能,自动创建数据修改记录表
在hibernate.cfg.xml 加入以下内容
<property name="hibernate.hbm2ddl.auto">update</property>
2. 代码开发
Envers目前提供的常用几类API如下:
@Audited 标记该Entity类或属性支持数据修改记录支持。 Target(value={java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD}
@NotAudited 标记该属性不支持数据修改记录支持 Target(value={java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD})
@RevisionEntity 实现为数据修改记录表保存其它自定义内容实现。如修改时间,操作人等。该类必须是一个实体类,会将数据存放一个单独表中。
@RevisionTimestamp 记录修改时间 必须配合 @RevisionEntity使用
@RevisionNumber 修改记录表的版本id 通常是配置成主键
2.1 演示示例
有一个student实体。添了@Audited设置
1 @Audited
2 @Entity
3 public class Student implements Serializable {
4 /**
5 * serial Version UID
6 */
7 private static final long serialVersionUID = 478336850989535510L;
8
9 private int age;
10
11 private int id;
12
13 private String name;
14
15 private byte[] data;
16
17 private int version;
18
19 /**
20 * @return the data
21 */
22 @NotAudited
23 @Column(name="data", length=5000)
24 public byte[] getData() {
25 return data;
26 }
27
28 /**
29 * @param data the data to set
30 */
31 public void setData(byte[] data) {
32 this.data = data;
33 }
34
35 @Override
36 public String toString() {
37 return new ToStringBuilder(this).append("age", age).append("id", id)
38 .append("name", name).toString();
39 }
40
41 @Column(name="age")
42 public int getAge() {
43 return age;
44 }
45
46 @Id
47 @GeneratedValue
48 public int getId() {
49 return id;
50 }
51
52 @Column(name="name", length=100)
53 public String getName() {
54 return name;
55 }
56
57 public void setAge(int age) {
58 this.age = age;
59 }
60
61 public void setId(int id) {
62 this.id = id;
63 }
64
65 public void setName(String name) {
66 this.name = name;
67 }
68
69 /**
70 * @return the version
71 */
72 @Version
73 public int getVersion() {
74 return version;
75 }
76
77 /**
78 * @param version the version to set
79 */
80 public void setVersion(int version) {
81 this.version = version;
82 }
83 }
生成对应的数据修改记录表sql脚本为:
1 CREATE TABLE `log_student_audit` (
2 `id` int(11) NOT NULL,
3 `rev` int(11) NOT NULL,
4 `revtype` tinyint(4) DEFAULT NULL,
5 `age` int(11) DEFAULT NULL,
6 `name` varchar(100) DEFAULT NULL,
7 PRIMARY KEY (`id`,`rev`),
8 KEY `FKD8A956DCF6C3C1B7` (`rev`)
9 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
为 Student修改记录内容扩展保存一些其它内容实现如下:
增加 SimpleRevEntity 实体类
1 @Entity
2 @RevisionEntity(SimpleListener.class)
3 @Table(name = "global_revisions_info")
4 public class SimpleRevEntity {
5 @Id
6 @GeneratedValue
7 @RevisionNumber
8 @Column(name = "revision_id")
9 private int id;
10 @RevisionTimestamp
11 @Column(name = "revision_timestamp")
12 private Date timestamp;
13 /**
14 * @return the id
15 */
16 public int getId() {
17 return id;
18 }
19 /**
20 * @param id the id to set
21 */
22 public void setId(int id) {
23 this.id = id;
24 }
25 /**
26 * @return the timestamp
27 */
28 public Date getTimestamp() {
29 return timestamp;
30 }
31 /**
32 * @param timestamp the timestamp to set
33 */
34 public void setTimestamp(Date timestamp) {
35 this.timestamp = timestamp;
36 }
37 }
SimpleListener 代码如下:
1 public class SimpleListener implements RevisionListener {
2 public void newRevision(Object revisionEntity) {
3 SimpleRevEntity revEnitty = (SimpleRevEntity) revisionEntity;
4 //add your additional info to the SimpleRevEntity here
5 }
6 }
rev entity生成的数据库表脚本如下:
CREATE TABLE `global_revisions_info` (
`revision_id` int(11) NOT NULL AUTO_INCREMENT,
`revision_timestamp` datetime DEFAULT NULL,
PRIMARY KEY (`revision_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
3. 数据库版本修改信息查询
1 #获得 AuditReader
2 AuditReader reader = AuditReaderFactory.get(session);
3
4 #根据版本号, 实体主键,找到修改之前该版本的数据
5 Person oldPerson = reader.find(Person.class, personId, revision)
6
7
8 #得到某条记录的所有修改的版本号
9 List<Number> revisions = reader.getRevisions(Person.class, personId);
10
11 #根据修改版本号,得到修改时间
12 Date date = reader.getRevisionDate(revision)
13
14 #根据时间,得到修改的版本号
15 Number revision = reader.getRevisionNumberForDate(date)
16
17 #得到当前最新的版本号. persist参数据,当为true时,当前的revisionEntityClass如果未进行持久操作,则进行持久操作
18 <T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
Good Luck!
Yours Matthew!