记一次TransactionSynchronization.afterCommit导致的no transaction is in progress问题

有一个逻辑希望事务提交后才去执行,具体实现如下

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  @Override
  public void afterCommit() {
    Manager.save(param)
  }
});

afterCommit 调用带有@Transaction的save方法

public class ManagerImpl implements Manager {
  @Transactional
  public void save(...) { ... }
}

web 调用后会报错

javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
at sun.reflect.GeneratedMethodAccessor2083.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:293)
at com.sun.proxy.$Proxy147.flush(Unknown Source)

查询资料发现:当#afterCommit()调用该方法时,Spring可能仍会看到上下文已绑定到现有事务。
如果想运行需要事务的其他代码,则需要强制Spring生成一个新的传播事务。因此Manager#save,所以需要更改方法:

public class ManagerImpl implements Manager {
  @Transactional(propagation = PROPAGATION_REQUIRES_NEW) 
  public void save( ... ) {
  }
}

propagation = PROPAGATION_REQUIRES_NEW很容易误用,不太建议。所以我在save这里再包装了一层,使他可以异步调用

你可能感兴趣的:(记一次TransactionSynchronization.afterCommit导致的no transaction is in progress问题)