事务中异步操作数据
前言
在业务中,经常会有这样的需求,再添加一个数据后,然后要去异步操作这条新增的数据。
在@Transactional注解下的方法,添加数据后去通过这条数据的id去查询这条数据是可以查询到的,但是如果是添加数据后,使用异步去通过这个数据的id去查询这条数据是查询不到的。
一、使用TransactionSynchronizationManager 事务管理器
使用spring的 TransactionSynchronizationManager 来保证在当前事务提交成功后执行异步操作
@Transactional(rollbackFor = Exception.class)
public void create() {
// 业务操作
// ...
// 需要异步操作新添加的数据
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
//异步操作
doWork();
}
}
);
}
二、注解方式
1.创建@PostCommit 注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PostCommit {
}
2.创建 事务注册 操作类
@Slf4j
@Component
public class PostCommitAdapter extends TransactionSynchronizationAdapter {
private static final ThreadLocal<List<Runnable>> RUNNABLE = new ThreadLocal<>();
// 为提交后执行注册一个新的 runnable
public void execute(Runnable runnable) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
List<Runnable> runnables = RUNNABLE.get();
if (runnables == null) {
runnables = new ArrayList<>();
RUNNABLE.set(runnables);
TransactionSynchronizationManager.registerSynchronization(this);
}
return;
}
// 如果事务同步未激活
runnable.run();
}
@Override
public void afterCommit() {
List<Runnable> runnables = RUNNABLE.get();
runnables.forEach(Runnable::run);
}
@Override
public void afterCompletion(int status) {
RUNNABLE.remove();
}
}
3.创建 @PostCommit 环绕切面操作类
@Aspect
@Slf4j
@AllArgsConstructor
@Configuration
public class PostCommitAnnotationAspect {
private final PostCommitAdapter postCommitAdapter;
@Pointcut("@annotation(com.ahshumei.pluto.module.common.annotation.PostCommit)")
private void postCommitPointCut(){}
@Around("postCommitPointCut()")
public Object aroundAdvice(final ProceedingJoinPoint pjp) {
postCommitAdapter.execute(new PjpAfterCommitRunnable(pjp));
return null;
}
private static final class PjpAfterCommitRunnable implements Runnable {
private final ProceedingJoinPoint pjp;
public PjpAfterCommitRunnable(ProceedingJoinPoint pjp) {
this.pjp = pjp;
}
@Override
public void run() {
try {
pjp.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
}
4.使用
@Transactional(rollbackFor = Exception.class)
public void create() {
// 业务操作
// ...
// 异步业务操作
doWork();
}
@PostCommit
public void doWork() {
// 异步的业务操作
}
三、TransactionSynchronizationManager 事务管理器 以及 TransactionSynchronization 对象
1、TransactionSynchronizationManager
- TransactionSynchronizationManager.isSynchronizationActive() 获取到当前是否存在事务
- TransactionSynchronizationManager.registerSynchronization() 事务提供的注册回调接口(传入对象TransactionSynchronization)
2、 TransactionSynchronization
public interface TransactionSynchronization extends Ordered, Flushable {
/** 事务提交状态 */
int STATUS_COMMITTED = 0;
/** 事务回滚状态 */
int STATUS_ROLLED_BACK = 1;
/**系统异常状态 */
int STATUS_UNKNOWN = 2;
@Override
default int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
//在spring开启新事务,获取connection之前会调用(未执行registCustomer)
void suspend();
//开启新事务失败时会调用(未执行registCustomer)
void resume();
//没调用
void flush();
// 事务提交之前
void beforeCommit(boolean readOnly);
// 事务成功或者事务回滚之前
void beforeCompletion();
// 事务成功提交之后
void afterCommit();
// 操作完成之后(包含事务成功或者事务回滚)
void afterCompletion(int status);
}