2009-05-22 80 views
19

我正在將envers添加到現有的hibernate實體中。到目前爲止,審計工作一切正常,但查詢是一個不同的問題,因爲修訂表沒有填充現有數據。其他人是否已經解決了這個問題?也許你已經找到了一些方法來用現有的表格填充修訂表格?只是想我會問,我相信別人會覺得它有用。使用現有數據從Hibernate實體填充envers修訂表

+0

你是如何獲取的審計工作?我什至不能得到那麼遠:( – 2009-06-04 16:07:25

+1

這真的很簡單,只是閱讀相當簡短的手冊:http://www.jboss.org/files/envers/docs/index.html – danieljimenez 2009-06-05 05:29:50

+0

我想知道這件事,但我需要有關環境的審計信息。哪個用戶和他們「做了些什麼」改變 - 他們正在做哪些高級用戶操作,從而觸發了這種變化。這對於能夠看到明顯的變化與「副作用」變化很重要。你知道恩維爾是否處理這種需求? – Pat 2009-06-15 22:48:41

回答

5

你不需要。
AuditQuery允許你通過得到兩個RevisionEntity和數據修訂:

AuditQuery query = getAuditReader().createQuery() 
       .forRevisionsOfEntity(YourAuditedEntity.class, false, false); 

這將構建一個查詢返回的對象[3]的列表。 Fisrt元素是您的數據,第二個是修訂實體,第三個是修訂類型。

1

看看http://www.jboss.org/files/envers/docs/index.html#revisionlog

基本上你可以使用@RevisionEntity註釋, 定義自己的修訂類型「,然後實施RevisionListener接口插入你額外的審計數據, 像當前用戶和高級操作。通常這些是從ThreadLocal上下文中提取的。

12

我們通過運行一系列原始SQL查詢來填充初始數據,以模擬「插入」所有現有實體,就好像它們剛剛在同一時間創建一樣。例如:

insert into REVINFO(REV,REVTSTMP) values (1,1322687394907); 
-- this is the initial revision, with an arbitrary timestamp 

insert into item_AUD(REV,REVTYPE,id,col1,col1) select 1,0,id,col1,col2 from item; 
-- this copies the relevant row data from the entity table to the audit table 

注意,REVTYPE值爲以指示刀片(相對於變形例)。

2

我們已經解決了與現有數據填充審計日誌的問題如下:

SessionFactory defaultSessionFactory; 

// special configured sessionfactory with envers audit listener + an interceptor 
// which flags all properties as dirty, even if they are not. 
SessionFactory replicationSessionFactory; 

// Entities must be retrieved with a different session factory, otherwise the 
// auditing tables are not updated. (this might be because I did something 
// wrong, I don't know, but I know it works if you do it as described above. Feel 
// free to improve) 

FooDao fooDao = new FooDao(); 
fooDao.setSessionFactory(defaultSessionFactory); 
List<Foo> all = fooDao.findAll(); 

// cleanup and close connection for fooDao here. 
.. 

// Obtain a session from the replicationSessionFactory here eg. 
Session session = replicationSessionFactory.getCurrentSession(); 

// replicate all data, overwrite data if en entry for that id already exists 
// the trick is to let both session factories point to the SAME database. 
// By updating the data in the existing db, the audit listener gets triggered, 
// and inserts your "initial" data in the audit tables. 
for(Foo foo: all) { 
    session.replicate(foo, ReplicationMode.OVERWRITE); 
}  

(通過Spring)的我的數據源配置:

<bean id="replicationDataSource" 
     class="org.apache.commons.dbcp.BasicDataSource" 
     destroy-method="close"> 
    <property name="driverClassName" value="org.postgresql.Driver"/> 
    <property name="url" value=".."/> 
    <property name="username" value=".."/> 
    <property name="password" value=".."/> 
    <aop:scoped-proxy proxy-target-class="true"/> 
</bean> 

<bean id="auditEventListener" 
     class="org.hibernate.envers.event.AuditEventListener"/> 

<bean id="replicationSessionFactory" 
     class="o.s.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> 

    <property name="entityInterceptor"> 
    <bean class="com.foo.DirtyCheckByPassInterceptor"/> 
    </property> 

    <property name="dataSource" ref="replicationDataSource"/> 
    <property name="packagesToScan"> 
    <list> 
     <value>com.foo.**</value> 
    </list> 
    </property> 

    <property name="hibernateProperties"> 
    <props> 
     .. 
     <prop key="org.hibernate.envers.audit_table_prefix">AUDIT_</prop> 
     <prop key="org.hibernate.envers.audit_table_suffix"></prop> 
    </props> 
    </property> 
    <property name="eventListeners"> 
    <map> 
     <entry key="post-insert" value-ref="auditEventListener"/> 
     <entry key="post-update" value-ref="auditEventListener"/> 
     <entry key="post-delete" value-ref="auditEventListener"/> 
     <entry key="pre-collection-update" value-ref="auditEventListener"/> 
     <entry key="pre-collection-remove" value-ref="auditEventListener"/> 
     <entry key="post-collection-recreate" value-ref="auditEventListener"/> 
    </map> 
    </property> 
</bean> 

攔截:

import org.hibernate.EmptyInterceptor; 
import org.hibernate.type.Type; 
.. 

public class DirtyCheckByPassInterceptor extends EmptyInterceptor { 

    public DirtyCheckByPassInterceptor() { 
    super(); 
    } 


    /** 
    * Flags ALL properties as dirty, even if nothing has changed. 
    */ 
    @Override 
    public int[] findDirty(Object entity, 
         Serializable id, 
         Object[] currentState, 
         Object[] previousState, 
         String[] propertyNames, 
         Type[] types) { 
    int[] result = new int[ propertyNames.length ]; 
    for (int i = 0; i < propertyNames.length; i++) { 
     result[ i ] = i; 
    } 
    return result; 
    } 
} 

ps:請記住,這是一個簡化的例子。它不會開箱即用,但它會引導您找到一個可行的解決方案。

5

如果您正在使用Envers ValidityAuditStrategy並且創建的數據不是啓用了Envers,那麼您將會遇到此類別的問題。 (Hibernate 4.2.8.Final)基本對象更新拋出「無法更新實體和以前的修訂」(記錄爲[org.hibernate.AssertionFailure] HHH000099)。

我花了一段時間來找到這個討論/解釋這樣交叉發佈:

ValidityAuditStrategy with no audit record

相關問題