问题
在事务中调用MQ的情况,可能存在事务失败但是提交MQ成功的可能
但是如果是在事务提交之后,再调用MQ
解决方法
使用spring事务扩展TransactionSynchronization
public interface TransactionSynchronization extends Flushable {
/** 事务提交状态 */
int STATUS_COMMITTED = 0;
/** 事务回滚状态 */
int STATUS_ROLLED_BACK = 1;
/**系统异常状态 */
int STATUS_UNKNOWN = 2;
void suspend();
void resume();
void flush();
// 事务提交之前
void beforeCommit(boolean readOnly);
// 事务成功或者事务回滚之前
void beforeCompletion();
// 事务成功提交之后
void afterCommit();
// 操作完成之后(包含事务成功或者事务回滚)
void afterCompletion(int status);
}
重写afterCompletion方法,调用业务代码
之后将其注册进入TransactionSynchronizationManager
了解TransactionSynchronizationManager
演示代码
public class TransactionUtils {
public static void doAfterTransaction(Runnable runnable) {
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new DoTransactionCompletion(runnable));
}
}
@Transactional
public void testMain(){
// start tx
TransactionUtils.doAfterTransaction(()->{
//send MQ / RPC
});
// end tx
}
}
class DoTransactionCompletion implements TransactionSynchronization {
private Runnable runnable;
public DoTransactionCompletion(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void afterCompletion(int status) {
if (status == TransactionSynchronization.STATUS_COMMITTED){
this.runnable.run();
}
}
}
其他方式
使用@TransactionalEventListener