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
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 );
}
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;
}
}
5 回答
你不需要 .
AuditQuery允许您通过以下方式获取RevisionEntity和数据修订:
这将构造一个返回Object [3]列表的查询 . Fisrt元素是您的数据,第二个是修订实体,第三个是修订类型 .
我们通过运行一系列原始SQL查询来填充初始数据,以模拟“插入”所有现有实体,就像它们刚刚同时创建一样 . 例如:
请注意, REVTYPE 值为 0 表示插入(与修改相对) .
如果您使用Envers ValidityAuditStrategy并且已创建除启用Envers之外的数据,则此类别中存在问题 .
在我们的例子中(Hibernate 4.2.8.Final),基本对象更新抛出“无法更新实体的先前版本和”(记录为[org.hibernate.AssertionFailure] HHH000099) .
花了一些时间才发现这个讨论/解释,所以交叉发布:
ValidityAuditStrategy with no audit record
我们已经解决了使用现有数据填充审计日志的问题,如下所示:
我的数据源配置(通过Spring):
拦截器:
ps:请记住,这是一个简化的例子 . 它不会开箱即用,但它会指导您找到一个有效的解决方案 .
看看http://www.jboss.org/files/envers/docs/index.html#revisionlog
基本上,您可以使用@RevisionEntity批注定义自己的“修订类型”,然后实现RevisionListener接口以插入您的其他审计数据,如当前用户和高级操作 . 通常这些是从ThreadLocal上下文中提取的 .