在开发过程中大家一定遇到过一种业务场景,需要在事务执行结束后再执行的代码逻辑,这个代码不受事务成败与否的影响,spring也为我们提供了这种功能那就是TransactionSynchronization。
为了方便使用我们直接封装成一个工具类,使用ThreadLoal对方法与线程进行绑定。
package com.casa.leetcode.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
/**
* 用于处理一些必须要等待事务提交后执行的操作
*
* save操作整个流程链
* - 2022-08-16 10:04:15,586 [http-nio-8089-exec-1] ERROR c.c.l.u.TransactionLifeCycleUtils - TransactionLifeCycleUtils --- beforeCommit
* - 2022-08-16 10:04:15,586 [http-nio-8089-exec-1] ERROR c.c.l.u.TransactionLifeCycleUtils - TransactionLifeCycleUtils --- beforeCompletion
* - 2022-08-16 10:04:15,648 [http-nio-8089-exec-1] ERROR c.c.l.u.TransactionLifeCycleUtils - TransactionLifeCycleUtils --- afterCommit
* - 2022-08-16 10:04:15,648 [http-nio-8089-exec-1] ERROR c.c.l.u.TransactionLifeCycleUtils - TransactionLifeCycleUtils --- afterCompletion --- 0
*
*/
@Slf4j
public class TransactionLifeCycleUtils {
private static ThreadLocal<List<Runnable>> threadLocalRunnableList = new ThreadLocal<>();
private static TransactionSynchronization action = new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
List<Runnable> runnableList = threadLocalRunnableList.get();
threadLocalRunnableList.remove();
runnableList.forEach(Runnable::run);
}
TransactionSynchronization.super.afterCompletion(status);
}
};
/**
* 单例
* @param command
*/
public static void afterCommitSuccessCallback(Runnable command) {
ThreadLocal<List<Runnable>> local = threadLocalRunnableList;
Optional.ofNullable(local.get()).ifPresentOrElse(
list -> list.add(command),
() -> {
LinkedList<Runnable> list = new LinkedList<>();
list.add(command);
local.set(list);
TransactionSynchronizationManager.registerSynchronization(action);
}
);
}
}
那我们如何使用呢
@Transactional
public Object save(SystemConfig config){
TransactionLifeCycleUtils.afterCommitSuccessCallback(
() -> log.info("save jpa success.")
);
return repository.saveAndFlush(config);
}
再说说如果不使用TransactionSynchronization我们想在事务之外执行代码是怎么实现的。
public void saveConfig(SystemConfig config){
this.save(config);
//事务之外的逻辑
log.info("save jpa success.")
}
@Transactional
public Object save(SystemConfig config){
return repository.saveAndFlush(config);
}
有问题欢迎讨论i❣