【发布时间】:2013-07-09 09:01:54
【问题描述】:
有没有办法监听事件 *after*AfterTransactionCompletion (2 time after) ?
我正在开发一个用户可以修改实体并保存它的应用程序:
tx.begin();
entity.name = "Archimede";
em.merge(entity);
tx.commit();
我想拦截提交,并“纠正”实体。假设:如果 name.equal("Archimede") 那么拦截器应该更改 surname = "Pitagorico"。
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
changedEntities.add(entity); //register all changing entities
}
public void afterTransactionCompletion(Transaction tx) {
for(T entity : changedEntities) {
if(entity.name.euqual("Archimede")) {
em.getTransaction().begin();
entity.surname = "Pitagorico";
sendNotificationToUser();
em.getTransaction().commit();
}
}
}
问题是不允许在拦截器中使用 entityManager 或事务,这将失败并显示如下内容:
org.hibernate.TransactionException: reuse of Transaction instances not supported
有罪的人在这里(org.hibernate.engine.transaction.spi.AbstractTransactionImpl):
@Override
public void commit() throws HibernateException {
if ( localStatus != LocalStatus.ACTIVE ) {
throw new TransactionException( "Transaction not successfully started" );
}
LOG.debug( "committing" );
beforeTransactionCommit();
try {
doCommit();
localStatus = LocalStatus.COMMITTED;
afterTransactionCompletion( Status.STATUS_COMMITTED ); //<-------
}
catch ( Exception e ) {
localStatus = LocalStatus.FAILED_COMMIT;
afterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException( "commit failed", e );
}
finally {
invalidate(); //<-------
afterAfterCompletion(); //<-------
}
}
拦截器由afterTransactionCompletion(Status.STATUS_COMMITTED);调用,但这是在invalidate();之前,事务仍处于COMMIT状态。 就在下一行它调用 afterAfterCompletion();,此时事务应该是有效的并且准备好.begin()。
我想这里有一个拦截器方法,所以前面的代码应该没有问题。
有人知道方法吗?还是我的方法不对? (有更好的吗?)
【问题讨论】:
-
你为什么不使用@PrePersist注解?
-
同样在@PrePersist 中我不应该使用EntityManager 或Transaction,并且我只想在事务实际提交时(而不是回滚)“更正”实体。此外,交易不应该依赖于“更正”(如果更正失败,只是更正交易应该失败,而不是第一个)。它们应该是两个独立的事务。
-
为什么我有一种看到并发代码不安全的感觉?将实体作为实例字段会使您变得糟糕。你怎么看?
-
为什么不在 onFlushDirty 期间更正实体?
标签: java hibernate jpa interceptor