当我们有业务需要在事务提交过后进行某一项或者某一系列的业务操作时候我们就可以使用TransactionSynchronizationManager
通过spring的aop机制将需要进行后置业务处理的操作,提交给spring的处理机制,并且切入到事务处理的后面
TransactionSynchronizationManager这个类中由一系列的ThreadLocal ,我们需要关注的是synchronizations,在后面使用到的TransactionSynchronizationManager.isSynchronizationActive()、TransactionSynchronizationManager.registerSynchronization()和new TransactionSynchronizationAdapter(),都与它密切有关。
在Spring在开启数据库事务(无论是使用@Transactional注解,还是用xml配置)时,都会向其中写入一个实例,用于自动处理Connection的获取、提交或回滚等操作。
再看isSynchronizationActive()方法,判断了synchronizations中是否有数据(Set
再看registerSynchronization()方法,首先调用isSynchronizationActive()做一个校验;然后将入参synchronization添加到synchronizations 中。入参synchronization中的方法不会在这里执行,而是要等到事务执行到特定阶段时才会被调用。
TransactionSynchronizationAdapter是一个适配器:它实现了TransactionSynchronization接口,并为每一个接口方法提供了一个空的实现。这类适配器的基本思想是:接口中定义了很多方法,然而业务代码往往只需要实现其中一小部分。利用这种“空实现”适配器,我们可以专注于业务上需要处理的回调方法,而不用在业务类中放大量而且重复的空方法。
结合TransactionSynchronizationManager和TransactionSynchronizationAdapter利用ThreadPoolExecutor实现一个事务后多线程处理功能。
package com.*.module.spring.support;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* 事务提交异步线程
*
* @author ly
*/
public class TransactionAfterCommitExecutor extends ThreadPoolExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class);
public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
private ThreadLocal> currentRunables = new ThreadLocal
>(){
@Override
protected List
return new ArrayList<>(5);
}
};
private ThreadLocal
@Override
protected Boolean initialValue() {
return false;
}
};
/**
* 默认策略丢弃最老的数据
*/
public TransactionAfterCommitExecutor() {
this(
50, 500,
500L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue
new ThreadFactoryBuilder().setNameFormat("transaction-after-commit-call-pool-%d").build(),
new ThreadPoolExecutor.DiscardOldestPolicy());
}
@Override
public void execute(final Runnable runnable) {
//如果事务同步未启用则认为事务已经提交,马上进行异步处理
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
super.execute(runnable);
} else {
//同一个事务的合并到一起处理
currentRunables.get().add(runnable);
//如果存在事务则在事务结束后异步处理
if(!registed.get()){
TransactionSynchronizationManager.registerSynchronization(new AfterCommitTransactionSynchronizationAdapter());
registed.set(true);
}
}
}
@Override
public Future> submit(final Runnable runnable) {
//如果事务同步未启用则认为事务已经提交,马上进行异步处理
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
return super.submit(runnable);
} else {
final RunnableFuture
//如果存在事务则在事务结束后异步处理
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
TransactionAfterCommitExecutor.super.submit(ftask);
}
});
return ftask;
}
}
private class AfterCommitTransactionSynchronizationAdapter extends TransactionSynchronizationAdapter{
@Override
public void afterCompletion(int status) {
final List
currentRunables.remove();
registed.remove();
if(status == STATUS_COMMITTED){
TransactionAfterCommitExecutor.super.execute(new Runnable() {
@Override
public void run() {
for (Runnable runnable : txRunables) {
try {
runnable.run();
} catch (Exception e) {
LOGGER.error("ex:",e);
}
}
}
});
}
}
}
}