Java Hibernate AfterTransactionCompletion拦截器
是否有办法在交易完成后(2次之后)收听事件 我正在开发一个应用程序,用户可以在其中修改实体并保存它:Java Hibernate AfterTransactionCompletion拦截器,java,hibernate,jpa,interceptor,Java,Hibernate,Jpa,Interceptor,是否有办法在交易完成后(2次之后)收听事件 我正在开发一个应用程序,用户可以在其中修改实体并保存它: tx.begin(); entity.name = "Archimede"; em.merge(entity); tx.commit(); 我想拦截提交,并“更正”实体。假设:如果name.equal(“阿基米德”),那么拦截器应该更改姓氏=“Pitagorico” 问题是不允许在拦截器中使用entityManager或transaction,这将失败,原因如下: org.hibernate.
tx.begin();
entity.name = "Archimede";
em.merge(entity);
tx.commit();
我想拦截提交,并“更正”实体。假设:如果name.equal(“阿基米德”),那么拦截器应该更改姓氏=“Pitagorico”
问题是不允许在拦截器中使用entityManager或transaction,这将失败,原因如下:
org.hibernate.TransactionException: reuse of Transaction instances not supported
罪魁祸首在这里(org.hibernate.engine.transaction.spi.AbstractTransactionImpl):
@覆盖
public void commit()引发HibernateeException{
if(localStatus!=localStatus.ACTIVE){
抛出新TransactionException(“事务未成功启动”);
}
LOG.debug(“提交”);
beforeTransactionCommit();
试一试{
doCommit();
localStatus=localStatus.COMMITTED;
afterTransactionCompletion(Status.Status_COMMITTED);//我会使用一些AOP并使用@Transactions
例:
在此合并方法上添加一些AOP(根据需要添加一些注释或XML声明)
XML:
我会使用一些AOP并使用@Transactions
例:
在此合并方法上添加一些AOP(根据需要添加一些注释或XML声明)
XML:
为什么不使用@PrePersist注释?同样在@PrePersist中,我不应该使用EntityManager或Transaction,我只想在事务实际提交(而不是回滚)时“更正”实体。此外,事务不应该依赖于“更正”(如果更正失败,则更正交易应失败,而不是第一次)。它们应该是两个独立的事务。为什么我会感觉到并发代码不安全?将实体作为实例字段会让它变得很糟糕。你认为呢?为什么不使用@PrePersist注释?在@PrePersist中,我不应该使用EntityManager或transaction,我想“更正”实体仅当事务实际提交时(而不是回滚时)。此外,事务不应依赖于“更正”(如果更正失败,则更正事务应失败,而不是第一个)。它们应该是两个独立的事务。为什么我会感觉到并发代码不安全?将实体作为实例字段会让它变得很糟糕。你认为如何?谢谢,这可能会起作用。但是我没有得到merge方法,我不能只绑定EntityManager#merge()方法上的建议吗?我必须对tx.commit()作出反应但原理是一样的。我使用的是google guice,我希望它的AOP足够。我现在唯一能想到的问题是托管实体更新,如果我不显式调用merge()的话,有没有办法强迫我这么做?编辑:我用一个显式名称更改合并方法。AOP拦截应该在您的服务层或类似的东西上完成。您也可以尝试Entity.merge。我不确定这种情况下的行为。我已经包装了EntityManager,因此可以拦截Persiste、merge、remove和trasaction.commit但是,我刚刚意识到,拦截merge而不是onFlushDirty会丢失currentState、previousState和propertyNames,所以现在我无法分辨哪个属性发生了更改。(而且merge甚至不意味着实体发生了任何更改)。有什么想法吗?在我的示例中,您有一个myEntityBeforeMerge和myEntityAfterMerge。因此,您可以检索已更改的属性。否则,如果没有真正的源代码,我就不知道了。如果我做对了,myEntityBeforeMerge是合并之前的实体(但需要保存修改)myEntityAfterMerge是托管实体,因此内容是相同的。在用户进行任何修改之前,我需要原始实体状态(数据库上的状态)。谢谢,这可能会起作用。但是我没有得到merge方法,我不能只绑定EntityManager#merge()方法上的建议吗?我必须对tx.commit()作出反应但原理是一样的。我使用的是google guice,我希望它的AOP足够。我现在唯一能想到的问题是托管实体更新,如果我不显式调用merge()的话,有没有办法强迫我这么做?编辑:我用一个显式名称更改合并方法。AOP拦截应该在您的服务层或类似的东西上完成。您也可以尝试Entity.merge。我不确定这种情况下的行为。我已经包装了EntityManager,因此可以拦截Persiste、merge、remove和trasaction.commit但是,我刚刚意识到,拦截merge而不是onFlushDirty会丢失currentState、previousState和propertyNames,所以现在我无法分辨哪个属性发生了更改。(而且merge甚至不意味着实体发生了任何更改)。有什么想法吗?在我的示例中,您有一个myEntityBeforeMerge和myEntityAfterMerge。因此,您可以检索已更改的属性。否则,如果没有真正的源代码,我就不知道了。如果我做对了,myEntityBeforeMerge是合并之前的实体(但需要保存修改)myEntityAfterMerge是托管实体,因此内容是相同的。在用户进行任何修改之前,我需要原始实体状态(数据库上的状态)。
org.hibernate.TransactionException: reuse of Transaction instances not supported
@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(); //<-------
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public MyEntity doSaveService(MyEntity myentity){
em.merge(myentity); // not required but easier to read
em.flush(); //not sure if you need it
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
protected Object postMergeProcess(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MyEntity myEntityBeforeMerge = (MyEntity ) proceedingJoinPoint.getArgs()[0];
MyEntity myEntityAfterMerge = (MyEntity ) proceedingJoinPoint.proceed();
myEntityAfterMerge.setWhatever("xxx");
em.merge();
}
<aop:config>
<aop:aspect ref="">
<aop:pointcut id="mergePointCut" expression="execution(* x.y.z.EntityService.merge(..))" />
<aop:around method="postMergeProcess" pointcut-ref="mergePointCut" />
</aop:aspect>
</aop:config>