Spring事务扩展机制——@Transactional

推荐学习

Spring事务扩展机制——@Transactional

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

1、TransactionSynchronizationManager

操作多个方法 Spring 是如何来进行事务处理的呢?Spring 对于事务的管理都是基于 TransactionSynchronizationManager,下面我们就来简单的分析一下这个类。

TransactionSynchronizationManager.java

<code>	

private

static

final ThreadLocalObject,

Object

>> resources =

new

NamedThreadLocalObject,

Object

>>(

"Transactional resources"

);

private

static

final ThreadLocal> synchronizations =

new

NamedThreadLocal>(

"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 currentTransactionIsolationLevel =

new

NamedThreadLocal(

"Current transaction isolation level"

);

private

static

final ThreadLocal<

Boolean

> actualTransactionActive =

new

NamedThreadLocal<

Boolean

>(

"Actual transaction active"

);/<code>

这个对象里面通过 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 属性当中。下面是绑定时序图:

Spring事务扩展机制——@Transactional

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

<code> 
Connection conn = DataSource.getConnection();

 
conn..setAutoCommit(

false

);

try

{ doSomething(); }

catch

(

Exception

e) { conn.rollback(); } conn.commit();/<code>

TransactionAspectSupport#invokeWithinTransaction

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

Spring事务扩展机制——@Transactional

上面的代码逻辑如下:

  • 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

<code>

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

)

; }/<code>

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

<code> 

public

void

finishOrder

(Order order)

{ updateOrderSuccess(order); TransactionSynchronizationManager.registerSynchronization(

new

TransactionSynchronizationAdapter(){

public

void

afterCommit

()

{ mqService.send(order); } }); }/<code>

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

4、Spring 事务扩展 – @TransactionalEventListener

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

<code>	 
	

public

void

finishOrder

(Order order)

{ updateOrderSuccess(order); applicationEventPublisher.publishEvent(

new

MyAfterTransactionEvent(order)); } 4j

private

static

class

MyTransactionListener

{

private

MqService mqService; (phase = TransactionPhase.AFTER_COMMIT)

private

void

onHelloEvent

(MyAfterTransactionEvent event)

{ Order order = event.getOrder(); mqService.send(order); } }

private

static

class

MyAfterTransactionEvent

extends

ApplicationEvent

{

private

Order order;

public

MyAfterTransactionEvent

(Object source, Order order)

{

super

(source);

this

.order = order; }

public

Order

getOrder

()

{

return

order; } }/<code>

它的实现原理是当 Spring Bean 的方法标注了通过 TransactionalEventListenerFactory#createApplicationListener创建 ApplicationListenerMethodTransactionalAdapter 然后在事件回调当中创建 TransactionSynchronization的实现类TransactionSynchronizationEventAdapter。并且通过 TransactionSynchronizationManager.registerSynchronization
把 TransactionSynchronizationEventAdapter 注册到当前线程当中。

TransactionSynchronizationEventAdapter

<code>	

private

static

class

TransactionSynchronizationEventAdapter

extends

TransactionSynchronizationAdapter

{

private

final

ApplicationListenerMethodAdapter listener;

private

final

ApplicationEvent event;

private

final

TransactionPhase phase;

public

TransactionSynchronizationEventAdapter

(ApplicationListenerMethodAdapter listener, ApplicationEvent event, TransactionPhase phase)

{

this

.listener = listener;

this

.event = event;

this

.phase = phase; }

public

int

getOrder

()

{

return

this

.listener.getOrder(); }

public

void

beforeCommit

(

boolean

readOnly)

{

if

(

this

.phase == TransactionPhase.BEFORE_COMMIT) { processEvent(); } }

public

void

afterCompletion

(

int

status)

{

if

(

this

.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) { processEvent(); }

else

if

(

this

.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) { processEvent(); }

else

if

(

this

.phase == TransactionPhase.AFTER_COMPLETION) { processEvent(); } }

protected

void

processEvent

()

{

this

.listener.processEvent(

this

.event); } }/<code>

上面就是使用@TransactionalEventListener处理数据库事务提交成功后再执行操作的原理。

作者:carl-zhao

原文链接:
https://blog.csdn.net/u012410733/article/details/108659198


分享到:


相關文章: