3个月学会Java开发!Spring事务扩展机制


private static final ThreadLocal<Map<Object, Object>> resources =
   		new NamedThreadLocal<Map<Object, Object>>("Transactional resources");

   private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
   		new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");

   private static final ThreadLocal<String> currentTransactionName =
   		new NamedThreadLocal<String>("Current transaction name");

   private static final ThreadLocal<Boolean> currentTransactionReadOnly =
   		new NamedThreadLocal<Boolean>("Current transaction read-only status");

   private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
   		new NamedThreadLocal<Integer>("Current transaction isolation level");

   private static final ThreadLocal<Boolean> actualTransactionActive =
   		new NamedThreadLocal<Boolean>("Actual transaction active");

这个对象里面通过 ThreadLocal 保存了线程需要状态以及资源对象。

  • resources:保存连接资源,因为一个方法里面可能包含两个事务(比如事务传播特性为:TransactionDefinition#PROPAGATION_REQUIRES_NEW),所以就用 Map 来保存资源.

  • synchronizations在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用 Spring 框架只需要在方法上添加 @Transactional 注解这个方法就具有事务特性了。而且 Spring 也事务操作给开发者提供了很方便的扩展。:线程同步器,这个就是对 Spring 事务的扩展,通过 TransactionSynchronizationManager#registerSynchronization 来注册,我们稍后来分析这个对象在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用 Spring 框架只需要在方法上添加 @Transactional 注解这个方法就具有事务特性了。而且 Spring 也事务操作给开发者提供了很方便的扩展。

  • currentTransactionReadOnly:用于保存当前事务是否只读

  • 在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用 Spring 框架只需要在方法上添加 @Transactional 注解这个方法就具有事务特性了。而且 Spring 也事务操作给开发者提供了很方便的扩展。

  • currentTransactionName:用于保存当前事务名称,默认为空

  • currentTransactionIsolationLevel:用来保存当前事务的隔离级别

  • actualTransactionActive:用于保存当前事务是否还是 Active 状态

下面我们来分析一下事务操作对于连接资源的处理,也就是事务处理中 TransactionSynchronizationManager 对于资源(resources 属性)的管理。

2、Spring 事务处理

TransactionSynchronizationManager#bindResource绑定连接资源到 TransactionSynchronizationManager 中的 resources 属性当中。下面是绑定时序图:

image

TransactionInterceptor 是 Spring 对于事务方法处理的代理入口,里面对 JDBC 事务的抽象:


// 获取连接
Connection conn = DataSource.getConnection();

// 设置自动提交 false
conn..setAutoCommit(false);

try {
	// 业务操作
	doSomething();
} catch (Exception e) {
	// 回滚事务
	conn.rollback();
}
// 提交事务
conn.commit();

TransactionAspectSupport#invokeWithinTransaction

TransactionAspectSupport#invokeWithinTransaction 是 Spring 对处理的处理。下面我们来大概分析一下它的处理过程:

image

上面的代码逻辑如下:

  • TransactionAttributeSource#getTransactionAttribute 获取事务相关的信息(TransactionAttribute),以注解型事务为例,看方法获取类上有没有标注@Transactional注解。

  • 获取到 Spring 容器中配置的事务管理器 (PlatformTransactionManager),后面就是真正的事务处理

  • 创建事务信息(TransactionInfo),里面包含事务管理器(PlatformTransactionManager) 以及事务相关信息(TransactionAttribute)

  • 后面就是 Spring 对于事务的抽象操作,包含设置自动提交 false、业务操作、异常回滚事务和正常就提交事务

我们回到正题, Spring 通过创建事务信息(TransactionInfo),把数据库连接通过 TransactionSynchronizationManager#bindResource 绑定到 ThreadLocal 变量当中。然后标注到一个事务当中的其它数据库操作就可以通过TransactionSynchronizationManager#getResource 获取到这个连接。

数据库的事务是基于连接的,Spring 对于多个数据库操作的事务实现是基于 ThreadLocal。所以在事务操作当中不能使用多线程

3、Spring 事务的扩展 – TransactionSynchronization

在上面的 TransactionSynchronizationManager 类中我们知道,事务操作的时候它的当前线程还保存了 TransactionSynchronization 对象。而这个对象伴随着 Spring 对 事务处理的各个生命周期都会有相应的扩展。

TransactionSynchronization.java


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);

}

事务的事务扩展项目中的应用场景是当订单成功之后,发送一条消息到 MQ 当中去。由于事务是和数据库连接相绑定的,如果把发送消息和数据库操作放在一个事务里面。当发送消息时间过长时会占用数据库连接,所以就要把数据库操作与发送消息到 MQ 解耦开来。可以利用 TransactionSynchronization#afterCommit 的这个方法,当数据成功保存到数据库并且事务提交了就把消息发送到 MQ 里面。


@Transactional
public void finishOrder(Order order){
	// 修改订单成功
	updateOrderSuccess(order);

	// 发送消息到 MQ
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
       @Override
       public void afterCommit() {
           mqService.send(order);
       }
    });
}

当事务成功提交之后,就会把消息发送给 MQ,并且不会占用数据库连接资源。

4、Spring 事务扩展 – @TransactionalEventListener

在 Spring framework 4.2 之后还可以使用@TransactionalEventListener处理数据库事务提交成功后再执行操作。这种方式比 TransactionSynchronization 更加优雅。它的使用方式如下:


 @Transactional
	public void finishOrder(Order order){
## 总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

![image](https://img-blog.csdnimg.cn/img_convert/c4afa814ad02782f487ab6b526edfb3f.png)

> **[资料领取方式:点击这里免费下载](https://gitee.com/vip204888/java-p7)**

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

A基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

![image](https://img-blog.csdnimg.cn/img_convert/2f37726bc54d7f0fce3af464f881d35b.png)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值