大家好,一段时间没见面了,主要是前些时间由于工作原因项目重构,一直没来得及更文,不过现在告一段落了,而且今天是“杨妹妹”夺冠的一天,所以无论如何我也要更文,也要努力学习的!

,好啦废话不多说,我们进入正题吧
前言
我们都知道spring事务分为2种,分别是声明式事务和编程式事务。
- 声明式事务基于 AOP机制,将具体业务逻辑与事务处理解耦,声明式事务只需要提供@Transactional的注解,然后事务的开启,事务的提交/回滚以及资源的清理就都由spring来管控,我们只需要关注业务代码即可;
- 编程式事务指的是通过编码方式实现事务,编程式事务则需要使用spring提供的模板,如TransactionTemplate,或者直接使用底层的PlatformTransactionManager。
而声明式事务的最大优点就是对代码的侵入性较小,只需要在方法上加@Transactional的注解就可以实现事务;编程式事务的最大优点就是事务的管控粒度较细,可以实现对某个代码块加事务。
简单地对spring事务进行回顾之后,我们接下来引入TransactionSynchronizationManager的使用。在我们平常搬砖的日常生活中,当我们需要在事务提交前后进行某一项或者某一系列的业务操作的时候,我们就可以使用TransactionSynchronizationManager,即“事务同步管理器”,它的实现思路是通过spring的AOP机制将需要进行后置业务处理的操作,提交给Spring的处理机制,并且切入到事务处理的前面/后面。TransactionSynchronizationManager是一个事务同步管理的核心类,它实现了事务同步管理的职能,包括记录当前连接持有connection holder。
如何在spring事务提交之后进行一些操作,这些操作必须得在该事务成功提交后才执行,回滚则不执行。
入门使用案例
在我们做订单业务的场景中, 一般都是当订单成功之后,发送一条通知消息到 MQ 当中去。由于事务是和数据库连接相绑定的,如果把发送消息和数据库操作放在一个事务里面。当发送消息时间过长时会占用数据库连接,所以就要把数据库操作与发送消息到 MQ 的过程给解耦开来。可以利用 TransactionSynchronization的afterCommit 的这个方法,当数据成功保存到数据库并且事务提交了就可以把消息发送到 MQ 里面。
@Transactional //加上事务注解
public void bussiness(){
// 处理我们自己的主干订单业务业务
System.out.println("doBussiness");
//........
// 下面的代码在事务提交后才执行
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
//例如发送mq消息
mqClient.send(mqMessage);
System.out.println("send email after transaction commit...");
}
});
}
TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
// 事务资源:map<key,value> 两种数据对。Connection 或 Session 等资源
// 1.会话工厂和会话key=SqlsessionFactory value=SqlSessionHolder
// 2.数据源和连接key=DataSource value=ConnectionHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
//事务同步器,是Spring交由程序员进行扩展的代码,每个线程可以注册N个事务同步器。
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 用于保存当前事务名称,默认为空
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 用于保存当前事务是否只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 用来保存当前事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 事务是否开启
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
...
省略代码
...
//这个函数用于初始化事务同步器synchronizations
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
} else {
synchronizations.set(new LinkedHashSet());
}
}
//该方法用于判断是否已启用TransactionSynchronization,即使没有注册任何TransactionSynchronization实例.
//Set<TransactionSynchronization>非null即可,并不要求其中有TransactionSynchronization实例。
public static boolean isSynchronizationActive() {
return synchronizations.get() != null;
}
//该方法用于判断实际的Transaction对象是否处于活动状态.
//检测是否Spring事务处于活动状态的可靠方法
public static boolean isActualTransactionActive() {
return actualTransactionActive.get() != null;
}
//绑定资源 在事务由挂起状态恢复正常时,其实就是绑定对应的Map<DataSource,ConnectionHolder>绑到当前线程中
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
// Transparently suppress a ResourceHolder that was marked as void...
if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
oldValue = null;
}
if (oldValue != null) {
throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
}
if (logger.isTraceEnabled()) {
logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +
Thread.currentThread().getName() + "]");
}
}
//当事务被挂起时,会调用这个函数来解绑
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
// Transparently suppress a ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
value = null;
}
if (value != null && logger.isTraceEnabled()) {
logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
//下面这个方法帮助我们在事务commit/completion前后进行一些自定义的操作。
public static void registerSynchronization(TransactionSynchronization synchronization) throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
Set<TransactionSynchronization> synchs = (Set)synchronizations.get();
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
} else {
synchs.add(synchronization);
}
}
}
TransactionSynchronization回调方法
TransactionSynchronization接口定义了一系列的回调方法,对应一个事务执行的不同阶段:挂起、恢复、flush、提交(前、后)、完成(事务成功或失败)等。当事务运行到对应阶段时,事务管理器会从TransactionSynchronizationManager维护的synchronizations中拿出所有的回调器,逐个回调执行相应的对应方法。
这个接口的案例代码如下:
/**
* @author JavaAlliance
* @version 1.0
* @description //事务管理器
* @Date 2021/7/24
**/
@Service
public class TestTransaction {
@Transactional
public void doBussiness() {
System.out.println("doBussiness");
// 处理业务
// ---
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
//事务挂起时调用
@Override
public void suspend() {
super.suspend();
System.out.println("suspend");
}
//挂起事务抛出异常的时候 会触发 //开启新事务失败时会调用
@Override
public void resume() {
super.resume();
System.out.println("resume");
}
//flush
@Override
public void flush() {
super.flush();
System.out.println("flush");
}
// 事务提交前会调用
@Override
public void beforeCommit(boolean readOnly) {
super.beforeCommit(readOnly);
System.out.println("beforeCommit");
}
//事务提交前会调用,在beforeCommit之后
@Override
public void beforeCompletion() {
super.beforeCompletion();
System.out.println("beforeCompletion");
}
//事务提交后会调用
@Override
public void afterCommit() {
//例如发送mq
//mqClient.send(mqMessage);
System.out.println("afterCommit");
}
//事务提交后会调用,在afterCommit之后
@Override
public void afterCompletion(int status) {
super.afterCompletion(status);
System.out.println("afterCompletion");
}
});
}
}
运行结果如下:

TransactionSynchronizationAdapter
TransactionSynchronizationAdapter是一个适配器:它实现了TransactionSynchronization接口,并为每一个接口方法提供了一个空的实现。这类适配器的基本思想是:接口中定义了很多方法,然而业务代码往往只需要实现其中一小部分。利用这种“空实现”适配器,我们可以专注于业务上需要处理的回调方法,而不用在业务类中放大量而且重复的空方法。
具体源代码如下所示
public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
//事务挂起时调用
public void suspend() {
}
//挂起事务抛出异常的时候 会触发 //开启新事务失败时会调用
public void resume() {
}
public void flush() {
}
// 事务提交前会调用
public void beforeCommit(boolean readOnly) {
}
//事务提交前会调用,在beforeCommit之后执行
public void beforeCompletion() {
}
//事务提交后会调用
public void afterCommit() {
}
//事务提交后会调用,在afterCommit之后
//顺带提一下,TransactionSynchronization中没有afterRollback()。如果需要在事务回滚后做某些处理,需要在afterCompletion(int)方法中判断入参的值,然后再做处理。
/** 事务提交状态 int STATUS_COMMITTED = 0;
事务回滚状态
int STATUS_ROLLED_BACK = 1;
系统异常状态
int STATUS_UNKNOWN = 2;**/
public void afterCompletion(int status) {
}
}
行百里者半九十,你知道的越多,你不知道的越多!拜拜!,下期再见!

















