測試版本:
Hibernate 3.3.2
Hibernate envers 1.2.2.ga-hibernate-3.3
介紹:
Hibernate Envers目的是根據(jù)對實(shí)體的設(shè)置,提供記錄執(zhí)行數(shù)據(jù)變更歷史的功能(數(shù)據(jù)變更版本)。它實(shí)現(xiàn)原理是通過對Hibernate的操作事件監(jiān)聽并根據(jù)
基于Annoatation的配置來記錄修改數(shù)據(jù)的內(nèi)容。
1. 配置方法
基于Spring的配置內(nèi)容如下:
1.1 配置Envers事件監(jiān)聽器
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" />
所有的監(jiān)聽事件都由 AuditEventListener 來處理。
1.2 配置 Envers相關(guān)屬性
org.hibernate.envers.audit_table_prefix 配置數(shù)據(jù)修改記錄表名的前綴規(guī)則 默認(rèn)值:空
org.hibernate.envers.audit_table_suffix 配置數(shù)據(jù)修改記錄表名的后綴規(guī)則 默認(rèn)值:_AUD
org.hibernate.envers.revision_field_name 配置數(shù)據(jù)修改記錄表版本號字段名 默認(rèn)值: REV
org.hibernate.envers.revision_type_field_name 配置數(shù)據(jù)修改記錄表修改類型字段名 默認(rèn)值: REVTYPE . 0表示新增加,1修改 2刪除
org.hibernate.envers.revision_on_collection_change 配置是否支持關(guān)聯(lián)表修改時記錄修改記錄 默認(rèn)值:true
org.hibernate.envers.do_not_audit_optimistic_locking_field 配置是否不對樂觀鎖字段修改時記錄修改記錄,即使用(@Version)字段 默認(rèn)值:true
org.hibernate.envers.store_data_at_delete 配置是否在刪除操作時,只保存id值還是全部的值。 默認(rèn)值:false 只記錄id
org.hibernate.envers.default_schema 配置數(shù)據(jù)修改記錄表的schema 默認(rèn)值:null
org.hibernate.envers.default_catalog 配置數(shù)據(jù)修改記錄表的catalog 默認(rèn)值: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功能,自動創(chuàng)建數(shù)據(jù)修改記錄表
在hibernate.cfg.xml 加入以下內(nèi)容
<property name="hibernate.hbm2ddl.auto">update</property>
2. 代碼開發(fā)
Envers目前提供的常用幾類API如下:
@Audited 標(biāo)記該Entity類或?qū)傩灾С謹(jǐn)?shù)據(jù)修改記錄支持。 Target(value={java.lang.annotation.ElementType.TYPE,java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD}
@NotAudited 標(biāo)記該屬性不支持?jǐn)?shù)據(jù)修改記錄支持 Target(value={java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.FIELD})
@RevisionEntity 實(shí)現(xiàn)為數(shù)據(jù)修改記錄表保存其它自定義內(nèi)容實(shí)現(xiàn)。如修改時間,操作人等。該類必須是一個實(shí)體類,會將數(shù)據(jù)存放一個單獨(dú)表中。
@RevisionTimestamp 記錄修改時間 必須配合 @RevisionEntity使用
@RevisionNumber 修改記錄表的版本id 通常是配置成主鍵
2.1 演示示例
有一個student實(shí)體。添了@Audited設(shè)置
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 }
生成對應(yīng)的數(shù)據(jù)修改記錄表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修改記錄內(nèi)容擴(kuò)展保存一些其它內(nèi)容實(shí)現(xiàn)如下:
增加 SimpleRevEntity 實(shí)體類
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生成的數(shù)據(jù)庫表腳本如下:
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. 數(shù)據(jù)庫版本修改信息查詢
1 #獲得 AuditReader
2 AuditReader reader = AuditReaderFactory.get(session);
3
4 #根據(jù)版本號, 實(shí)體主鍵,找到修改之前該版本的數(shù)據(jù)
5 Person oldPerson = reader.find(Person.class, personId, revision)
6
7
8 #得到某條記錄的所有修改的版本號
9 List<Number> revisions = reader.getRevisions(Person.class, personId);
10
11 #根據(jù)修改版本號,得到修改時間
12 Date date = reader.getRevisionDate(revision)
13
14 #根據(jù)時間,得到修改的版本號
15 Number revision = reader.getRevisionNumberForDate(date)
16
17 #得到當(dāng)前最新的版本號. persist參數(shù)據(jù),當(dāng)為true時,當(dāng)前的revisionEntityClass如果未進(jìn)行持久操作,則進(jìn)行持久操作
18 <T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist);
Good Luck!
Yours Matthew!