Spring持久化支持(一)-Spring事务管理

版权声明:本文为博主原创文章,转载添加原文链接 https://blog.csdn.net/qq_34190023/article/details/82833966

事务管理的目的是保证数据操作的事务性(原子性、一致性、隔离性、持久性ACID),脱离了事务性,DAO照样可以顺利地进行数据操作。

事务是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用

 

Spring事务管理是Spring AOP技术的应用。

 

Spring对事务管理的支持

Spring为事务管理提供了一致的编程模板,在高层次建立了统一的事务抽象。

不管选择Spring JDBC、Hibernate、JPA还是MyBatis,Spring都可让用户用统一的编程模型进行事务管理。

 

Spring为事务管理提供了事务模板类TransactionTemplate。

通过TransactionTemplate并配合使用事务回调TransactionCallback指定具体的持久化操作,就可通过编程方式实现事务管理,无须关注资源获取、复用、释放、事务同步和异常处理等操作

 

事务管理作为一个切面织入目标业务方法的周围,业务方法完全从事务代码中解脱出来,代码的复杂度大大降低。

被织入的事务代码基于Spring事务同步管理器进行工作,事务同步管理器维护着业务类对象线程相关的资源。DAO类需要利用资源获取工具访问底层数据连接,或者直接建立在相应的持久化模板类的基础上。

 

要了解它们的内部机制,就必须事先了解ThreadLocal的工作机制。

 

Spring的事务配置主要提供两方面的信息:

其一,切点信息,用于定位实施事务切面的业务类方法;

其二,控制事务行为的事务属性,这些属性包括事务隔离级别、事务传播行为、超时时间、回滚规则等。

 

Spring通过aop/tx Schema命名空间和@Transactional注解技术,大大简化了声明式事务配置的难度。同时,了解基于TransactionProxyFactoryBean代理类定义声明式事务的工作机制,有助于理解事务增强的内部过程。

 

Spring事务管理:(优点)Spring-tx

提供统一的API接口支持不同的资源:具体的事务源不一样也没问题

提供声明式事务管理:事务代码不需要嵌入代码,AOP

方便与Spring框架继承

多个资源(数据源)的事务管理、同步

 

 

Spring事务管理的亮点在于声明式事务管理。

Spring允许通过声明方式,在IoC配置中指定事务的边界和事务属性,Spring自动在指定的事务边界上应用事务属性。声明式事务是EJB烜赫一时的技术,Spring让这种技术平民化,甚至可以说,Spring的声明事务比EJB的更为强大

 

 

核心接口

Spring事务管理SPI (Service Provider Interface)的抽象层主要包括3个接口,分别是 PlatformTransactionManager、TransactionDefinition 和 TransactionStatus,位于org.springframework.transaction包中

Spring事务管理涉及的接口的联系如下:

根据 TransactionDefinition 提供的事务属性配置信息创建事务,并用TransactionStatus描述这个激活事务的状态

 

PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务。

管理事务过程中,产生一些事务状态:状态由TransactionStatus

 

PlatformTransactionManager:事务管理接口

org.springframework.transaction.PlatformTransactionManager接口是Spring核心事务管理器。

事务的开启、提交、回滚等由具体的事务管理器实现

事务只能被提交或回滚(或回滚到某个保存点后提交)

public interface PlatformTransactionManager {
   TransactionStatus
getTransaction(TransactionDefinition definition) throws TransactionException; //根据事务定义信息从事务环境中返回一个己存在的事务,或者创建一个新的事务,并用TransactionStatus描述这个事务的状态
  
void commit(TransactionStatus status) throws TransactionException; //:根据事务的状态提交事务。如果事务状态已经被标识为rollback-only,则该方法将执行一个回滚事务的操作。
  
void rollback(TransactionStatus status) throws TransactionException; //将事务回滚。当 commit()方法抛出异常时,rollback()方法会被隐式调用。
}

 

Spring不直接管理事务,而是提供了多种事务管理器,将事务管理的职责委托给底层具体的持久化实现框架来完成

Spring事务管理的优点:为不同的事务API提供一致的编程模型,如JTA、JDBC、Hibernate、JPA。

 

Spring为不同的持久化框架提供了不同的PlatformTransactionManager接口实现。

PlatformTransactionManager实现类

说明

org.springframework.jdbc.datasource.

DataSourceTransactionManager

使用spring JDBC或mybatis进行持久化数据时使用

org.springframework.orm.hibernate5.

HibernateTransactionManager

使用Hibernate5版本进行持久化数据

org.springframework.orm.jpa.JpaTransactionManager

Jpa时使用

org.springframework.orm.jdo.JdoTransactionManager

Jdo时使用

org.springframework.transaction.jta.

JtaTransactionManager

使用JTA实现来管理事务,在一个事务跨越多个资源时必须使用

 

事务管理器以普通的 Bean 形式声明在 Spring IOC 容器中

实现事务管理,首先要在Spring中配置好相应的事务管理器,为事务管理器指定数据资源及一些其他事务管理控制属性

 

PlatformTransactionManager提供了统一的API

AbstractPlatformTransactionManager抽象类源码:

public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager,Serializable {
@Override

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

   Object transaction = doGetTransaction();  // 子类对象不同,所以用Object接受。归子类去实现
// Cache debug flag to avoid repeated checks.

   boolean debugEnabled = logger.isDebugEnabled();

   if (definition == null) { // Use defaults if no transaction definition given.

      definition = new DefaultTransactionDefinition();

   }

   if (isExistingTransaction(transaction)) {  // 是否是已存在的事务
     // Existing transaction found -> check propagation behavior to find out how to behave.

      return handleExistingTransaction(definition, transaction, debugEnabled);

   }

   // Check definition settings for new transaction.

   if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {  //  是否超时

      throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());

   }

   // No existing transaction found -> check propagation behavior to find out how to proceed.

   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {

      throw new IllegalTransactionStateException(

            "No existing transaction found for transaction marked with propagation 'mandatory'");

   } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||

         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||

         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {

      SuspendedResourcesHolder suspendedResources = suspend(null);

      try {

         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

         DefaultTransactionStatus status = newTransactionStatus(

               definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);

         doBegin(transaction, definition);

         prepareSynchronization(status, definition);

         return status;

      }   catch (RuntimeException ex) {

         resume(null, suspendedResources);

         throw ex;

      catch (Error err) {

         resume(null, suspendedResources);

         throw err;

      }

   }  else {

      // Create "empty" transaction: no actual transaction, but potentially synchronization. 

      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);

      return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);

   }

}
// 子类实现的模板方法

protected abstract Object doGetTransaction() throws TransactionException;

protected boolean isExistingTransaction(Object transaction) throws TransactionException {
  
return false;
}

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {

// 判断事务传播属性,不同的传播属性不同的行为
   if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
     
throw new IllegalTransactionStateException(
           
"Existing transaction found for transaction marked with propagation 'never'");
  
}
  
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
      Object suspendedResources = suspend(transaction)
;
      boolean
newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return
prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);
  
}
  
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
      SuspendedResourcesHolder suspendedResources = suspend(transaction)
;
      try
{
        
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        
DefaultTransactionStatus status = newTransactionStatus(
               definition
, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        
doBegin(transaction, definition);
        
prepareSynchronization(status, definition);
         return
status;
     
}   catch (RuntimeException beginEx) {
         resumeAfterBeginException(transaction
, suspendedResources, beginEx);
         throw
beginEx;
     
} catch (Error beginErr) {
         resumeAfterBeginException(transaction
, suspendedResources, beginErr);
         throw
beginErr;
     
}
   }
  
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
     
if (!isNestedTransactionAllowed()) {
        
throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - specify 'nestedTransactionAllowed' property with value 'true'");
     
}
     
if (useSavepointForNestedTransaction()) {
         
// Create savepoint within existing Spring-managed transaction,
         // through the SavepointManager API implemented by TransactionStatus.
         // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
        
DefaultTransactionStatus status =
               prepareTransactionStatus(definition
, transaction, false, false, debugEnabled, null);
        
status.createAndHoldSavepoint();
         return
status;
     
} else {
        
// Nested transaction through nested begin and commit/rollback calls.
         // Usually only for JTA: Spring synchronization might get activated here
         // in case of a pre-existing JTA transaction.
        
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        
DefaultTransactionStatus status = newTransactionStatus(
               definition
, transaction, true, newSynchronization, debugEnabled, null);
        
doBegin(transaction, definition);
        
prepareSynchronization(status, definition);
         return
status;
     
}
   }

// 判断事务隔离级别 // Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
   if (isValidateExistingTransaction()) {
     
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
         Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel()
;
         if
(currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
            Constants isoConstants = DefaultTransactionDefinition.
constants;
            throw new
IllegalTransactionStateException("Participating transaction with definition [" + definition + "] specifies isolation level which is incompatible with existing transaction: " +(currentIsolationLevel != null ?isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :"(unknown)"));
        
}
      }
     
if (!definition.isReadOnly()) {  // 是否只读
         if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
           
throw new IllegalTransactionStateException("Participating transaction with definition [" +
                  definition +
"] is not marked as read-only but existing transaction is");
        
}
      }
   }
  
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
   return
prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

protected final DefaultTransactionStatus prepareTransactionStatus( TransactionDefinition definition, Object transaction, boolean newTransaction, boolean newSynchronization, boolean debug, Object suspendedResources) {
   DefaultTransactionStatus status = newTransactionStatus(definition
, transaction, newTransaction, newSynchronization, debug, suspendedResources);
  
prepareSynchronization(status, definition);
   return
status;
}

/**
 * Create a TransactionStatus instance for the given arguments.
 */

protected DefaultTransactionStatus newTransactionStatus( TransactionDefinition definition, Object transaction,boolean newTransaction,boolean newSynchronization,boolean debug, Object suspendedResources) {
  
boolean actualNewSynchronization = newSynchronization &&
         !TransactionSynchronizationManager.isSynchronizationActive()
;
   return new
DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization,
        
definition.isReadOnly(), debug, suspendedResources);
}
/*** Initialize transaction synchronization as appropriate. */
protected void prepareSynchronization(DefaultTransactionStatus status,TransactionDefinition definition) {
  
if (status.isNewSynchronization()) {
      TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction())
;
     
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
            definition.getIsolationLevel() != TransactionDefinition.
ISOLATION_DEFAULT ?
                  definition.getIsolationLevel() :
null);
     
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
     
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
     
TransactionSynchronizationManager.initSynchronization();
  
}
}

 

各个平台框架实现事务管理的机制:

1)DataSourceTransactionManager - JDBC事务

DataSourceTransactionManager是通过调用java.sql.Connection来管理事务,而Connection是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。

如果使用Spring JDBC或MyBatis,由于它们都基于数据源的Connection访问数据库, 只要在Spring中配置DataSourceTransactionManager就可以。

XML配置:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

</bean>

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p: dataSource-ref=“dataSource”/>

 

DataSourceTransactionManager源码:

doGetTransaction()//从ThreadLocal中获取一个Connection(相互对立的)

doBegin()         //开启事务

// 执行业务逻辑

// 根据业务逻辑的执行结果判断是否要提交还是回滚

doCommit()//提交

doRallback() // 回滚

 

2)HibernateTransactionManager - Hibernate事务

HibernateTransactionManager实现细节:将事务管理的职责委托给org.hibernate.Transaction对象,Transaction是从Hibernate Session中获取到的。当事务成功完成时,HibernateTransactionManager会调用Transaction对象的commit(),反之,会调用rollback()。

Hibernate使用org.hibemate.Session封装Connection,所以要一个能够创建Session的SessionFactory

在配置事务管理器时,需要引入sessionFactory属性。

    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

        <property name="sessionFactory" ref="sessionFactory" />

    </bean>

 

3)JpaTransactionManager - Java持久化API事务(JPA)

JpaTransactionManager只需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTransactionManager将与由工厂所产生的JPA EntityManager合作来构建事务。

JPA 通过 javax.persistence.EntityTransaction 管理 JPA 的事务,EntityTransaction 对象可通过 javax.persistence.EntityManager#getTransaction()方法获得,而 EntityManager 又通过一个工厂类方法 javax.persistence.EntityManagerFactory#createEntityManager()获取。

在底层,JPA依然通过JDBC的Connection的事务方法完成最终的控制。因此,要配置一个JPA事务管理器,必须先提供一个DataSource,然后配置一个EntityManagerFactory,最后才配置JpaTransactionManager

 

Java持久化API是Java持久化标准。如果用JPA则需用JpaTransactionManager来处理事务。

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">

        <property name="sessionFactory" ref="sessionFactory" />

    </bean>

<bean id="entityManagerFactory" class=norg.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 

p:dataSource_ref="dataSource”/>

</bean>

<bean id="transactionManager" class=" org.springframework.orm.jpa.JpaTransactionManager "   

p:entityManagerFactory-ref="entityManagerFactory"/>

 

4)JtaTransactionManager - Java原生API事务

JtaTransactionManager将事务管理的责任委托给javax.transaction.UserTransaction和javax.transaction.TransactionManager对象,事务成功完成通过UserTransaction.commit()方法提交,事务失败通过UserTransaction.rollback()方法回滚。

 

如果用其他持久化技术,或跨越多个事务管理源(如两或是多个不同的数据源),需要使用JtaTransactionManager:

JtaTransactionManager不需要知道DataSource和其他特定的资源,因为它引用容器提供的全局事务管理

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">

        <property name="transactionManagerName" value="java:/TransactionManager" />

    </bean>

 

 

5)JmsTransactionManager – 使用各种消息中间件

 

 

 

 

事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)得到事务, TransactionDefinition类定义了一些基本的事务属性。

 

TransactionDefinition:事务的定义

描述事务的隔离级别、超时时间、是否为只读事务和事务传播规则等控制事务具体行为的事务属性,这些事务属性可通过XML配置或注解描述提供,也可通过手工编程的方式设置。

事务属性是事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面

public interface TransactionDefinition {
   // 传播行为

   int PROPAGATION_REQUIRED = 0;
   int PROPAGATION_SUPPORTS = 1;
   int PROPAGATION_MANDATORY = 2;
   int PROPAGATION_REQUIRES_NEW = 3;
   int PROPAGATION_NOT_SUPPORTED = 4;
   int PROPAGATION_NEVER = 5;
   int PROPAGATION_NESTED = 6;

// 事务隔离级别(Spring提供多一个Default
   int ISOLATION_DEFAULT = -1;
   int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
   int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
   int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
   int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

// 超时
   int TIMEOUT_DEFAULT = -1;
   int getPropagationBehavior();    // 返回事务的传播行为
   int getIsolationLevel();   // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
   int getTimeout();           // 返回事务必须在多少秒内完成
   boolean isReadOnly();       // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
   String getName();
}

1)事务传播行为(规则):Spring定义了7种传播属性

传播行为:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播

如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行

规定了事务方法和事务方法发生嵌套调用时事务如何进行传播、

 

1.PROPAGATION_REQUIRED(常见的方式,默认)

当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。没有事务则新建一个事务

如果有事务在运行,当前的方法就在这个事务内运行,否则,新建一个事务,并在自己的事务内运行,。

 

2.PROPAGATION_SUPPORTS

支持当前事务。如果当前没有事务,则以非事务方式执行

如果有事务在运行,当前的方法就在这个事务内运行,否则它不可以运行在事务中

3.PROPAGATION_MANDATORY

该方法必须在事务中运行如果当前事务不存在,则会抛出一个异常

当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常

 

4.PROPAGATION_REQUIRES_NEW

新建事务。如果当前存在事务,则把当前事务挂起。表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

表示该方法必须启动一个新事务, 并在自己的事务内运行. 如果有事务在运行, 就应该先挂起它

当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起

 

5.PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作。如果当前存在事务,则把当前事务挂起。表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

当前的方法不应该运行在事务内部,如果有运行的事务,则将它挂起

6.PROPAGATION_NEVER

以非事务方式执行。如果当前存在事务在运行,则抛出异常

当前的反方不应该运行在事务中,如果有运行的事务,则抛出异常

7.PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行:如果当前没有事务,则执行与
PROPAGATION_REQUIRED 类似的操作。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

 

如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在他自己的事务内运行

 

注:在使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC3.0,并且实现者需要支持保存点事务机制

 

 

2)事务隔离级别

并发若无好的隔离级别,将导致脏读、不可重复读、幻读等问题

Spring定义的隔离级别和java.sql.Connection接口的四个隔离级别同名。

1. ISOLATION_READ_UNCOMMITTED

 

2. ISOLATION_READ_COMMITTED

 

3. ISOLATION_REPEATABLE_READ

 

4. ISOLATION_SERIALIZABLE

 

5. ISOLATION_DEFAULT

表示使用底层数据库的默认隔离级别

 

 

由于事务可以在行和表上获得锁,  因此长事务会占用资源, 并对整体性能产生影响.

如果一个事物只读取数据但不做修改, 数据库引擎可以对这个事务进行优化.

 

3)事务超时

事务在超时前能运行多久,超过时间后,事务被回滚。有些事务管理器不支持事务过期的功能,这时,如果设置TIMEOUT_DEFAULT之外的其他值,则将抛出异常

超时事务属性: 事务在强制回滚之前可以保持多久. 这样可以防止长期运行的事务占用资源.

 

4)只读

只读事务不修改任何数据,资源事务管理者可以针对可读事务应用一些优化措施,提高运行性能。只读事务在某些情况下(如使用Hibernate时)是一种非常有用的优化,试图在只读事务中更改数据将引发异常。

只读事务属性: 表示这个事务只读取数据但不更新数据, 这样可以帮助数据库引擎优化事务

 

5)回滚事务属性

默认情况下只有未检查异常(RuntimeException和Error类型的异常)会导致事务回滚. 而受检查异常不会.

事务的回滚规则可以通过 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性来定义. 这两个属性被声明为 Class[] 类型的, 因此可以为这两个属性指定多个异常类.

 

属性配置与使用:

注解@Transaction:

@Transactional相关属性:

Propagation:定义事务传播属性 org.springframework.transaction.annotation.Propagation

Isolation:设置隔离级别        org.springframework.transaction.annotation.Isolation

readOnly:设置只读属性          @Transactional(readOnly=true)

timeout:设置超时时间。单位为秒 @Transactional(timeout=10)

rollbackFor:设置异常回滚策略    @Transactional(rollbackFor={SQLException.class})) 多个异常之间可用逗号分隔

noRollbackFor:设置异常不回滚策略

@Transactional(propagation=Propagation.REQUIRES_NEW
      isolation=Isolation.READ_COMMITTED, //事务隔离级别。读与提交
     
readOnly=false,  //只读
     
//rollbackFor = ,
      //noRollbackFor = {UserAccountException.class},//
对于这种异常不回滚
     
timeout=3)   //超时就回滚

 

@Transactional在类上面注解:适用于所有public的方法

@Transactional在方法上注解:将覆盖类级别注解

 

使用不同的事务管理器:

Xml中定义不同的事务管理器:

每个事务管理器可以绑定一个独立的数据源。

 

Xml配置文件配置:

在 Spring 2.x 事务通知中,在 <tx:method> 元素中设定传播事务属性、隔离级别、回滚策略(不止一种异常则用逗号隔开)、只读属性和超时时间。

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <
tx:attributes>
       
<!-- 根据方法名指定事务的属性 -->
       
<tx:method name="purchase"

propagation="REQUIRES_NEW"
       
isolation="READ_COMMITTED"
       
rollback-for="java.io.IOException,java.sql.SQLException"
       
no-rollback-for="java.lang.ArithmeticException"
       
timeout="30"
       
read-only="true"/>
        <
tx:method name="get*" read-only="true"/>
        <
tx:method name="find*" read-only="true"/>
        <
tx:method name="*"/>
    </
tx:attributes>
</
tx:advice>

 

 

TransactionStatus:代表一个事务的具体运行状态

事务管理器可通过该接口获取事务运行期的状态信息,也可通过该接口间接回滚事务,它相比于在抛出异常时回滚事务的方式更具可控性。

调用PlatformTransactionManager的getTransaction()的方法得到的是TransactionStatus接口的一个实现

TransactionStatus 扩展了 SavepointManager 接口。

public interface TransactionStatus extends SavepointManager, Flushable {
   boolean isNewTransaction();//当前事务是否是一个新的事务,当前事务是已经存在的事务返回false,或当前操作未运行在事务环境中
   boolean hasSavepoint(); //判断当前事务是否在内部创建了一个保存点,该保存点是为了支持Spring的嵌套事务而创建的
   void setRollbackOnly();//将当前事务设置为rollback-only。通过该标识通知事务管理器只能将事务回滚,事务管理器将通过显式调用回滚命令或抛出异常的方式回滚事务
   boolean isRollbackOnly();//判断当前事务是否己经被标识为rollback-only只回滚
   @Override
  
void flush();
   boolean isCompleted();//判断当前事务是否己经结束(己经提交或回滚)
}

 

该接口继承于SavepointManager接口

SavepointManager接口基于JDBC 3.0保存点的分段事务控制能力提供了嵌套事务的机制。

public interface SavepointManager {
   Object createSavepoint() throws TransactionException; //创建一个保存点对象,以便在后面可以利用
   void rollbackToSavepoint(Object savepoint) throws TransactionException; //使事务回滚到特定的保存点上,被回滚的保存点将自动释放,也可通过releaseSavepoint()释放一个己经不用的保存点
   void releaseSavepoint(Object savepoint) throws TransactionException; //释放一个保存点。如果事务提交,则所有的保存点会被自动释放,无须手工清除
}

这3个方法在底层的资源不支持保存点时,都将抛出NestedTransactionNotSupportedException 异常

 

 

 

事务同步管理器:

Spring将JDBC的Connection、Hibernate的Session等访问数据库的连接或会话对象统称为资源,这些资源在同一时刻是不能多线程共享的。为了让DAO、Service类可能做到 singleton,

Spring事务同步管理器类org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal为不同事务线程提供了独立的资源副本,同时维护事务配置的属性和运行状态信息。

事务同步管理器是Spring事务管理的基石,不管用户用的是编程式事务管理,还是声明式事务管理,都离不开事务同步管理器。

Spring框架为不同的持久化技术提供了一套从TransactionSynchronizationManager中获取对应线程绑定资源的工具类

在调用一个需要事务的组件的时候,管理器首先判断当前调用(即当前线程)有没有一个事务,如果没有事务则启动一个事务,并把事务与当前线程绑定。Spring使用TransactionSynchronizationManager的bindResource方法将当前线程与一个事务绑定,采用的方式就是ThreadLocal

public abstract class TransactionSynchronizationManager {

 ……

 private static final ThreadLocal currentTransactionName = new ThreadLocal();

 private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();

 private static final ThreadLocal actualTransactionActive = new ThreadLocal(); ……

}

持久化技术

线程绑定资源获取工具

Spring JDBC 或 MyBatis

org. springframework .j dbc. datasource. DataSourceU tils

Hibernate X.0

org.springframework.orm.hibemateX.SessionFactoryUtils

JPA

org.springframework.orm.jpa.EntityManagerFactoryUtils

JDO

org.springframework.orm.jdo.PersistenceManagerFactoryUtils

这些工具类都提供了静态的方法,通过这些方法可以获取和当前线程绑定的资源,

DataSourceUtils.getConnection(DataSource dataSource)可从指定的数据源中获取和当前线程绑定的 Connection,

Hibernate 的 SessionFactoryUtils.getSession(SessionFactory sessionFactory,boolean allowCreate)可从指定的SessionFactory中获取和当前线程绑定的Session

当需要脱离模板类,手工操作底层持久化技术的原生API时,就需要通过这些工具类获取线程绑定的资源,而不应该直接从DataSource或SessionFactory中获取。因为后者不能获得与本线程相关的资源,因此无法让数据操作参与到与本线程相关的事务环境中。

这些工具类还有另外一个重要的用途:将特定异常转换为Spring的DAO异常

 

Spring为不同的持久化技术提供了模板类,模板类在内部通过资源获取工具类间接访问TransactionSynchronizationManager中的线程绑定资源。所以,如果DAO使用模板类进行持久化操作,这些DAO就可以配置成singleton。如果不使用模板类,也可以直接通过资源获取工具类访问线程相关的资源。

public abstract class TransactionSynchronizationManager {

//①用于保存每个事务线程对应的Connection或Session等类型的资源
private static final ThreadLocal resources = new ThreadLocal();

//②用于保存每个事务线程对应事务的名称

private static final ThreadLocal currentTransactionName = new ThreadLocal();

//③用于保存每个事务线程对应事务的read-only状态

private static final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
//④用于保存每个事务线程对应事务的隔离级别

private static final ThreadLocal currentTransactionIsolationLevel= new ThreadLocal();

//⑤用于保存每个事务线程对应事务的激活态

private static final ThreadLocal actualTransactionActive = new ThreadLocal();

}

TransactionSynchronizationManager 将 DAO、Service 类中影响线程安全的所有“状态”统一抽取到该类中,并用ThreadLocal进行替换,从此DAO (必须是基于模板类或资源获取工具类创建的DAO)和Service (必须采用Spring事务管理机制)摘掉了非线程安全的帽子,完成了脱胎换骨式的身份转变。

 

 

 

TransactionTemplate

线程安全,可在多个业务类中共享TransactionTemplate实例进行事务管理。

@SuppressWarnings("serial")
public class TransactionTemplate extends DefaultTransactionDefinition
     
implements TransactionOperations, InitializingBean {
   @Getter @Setter private PlatformTransactionManager transactionManager;
   public TransactionTemplate() {   }
   public TransactionTemplate(PlatformTransactionManager transactionManager) {
     
this.transactionManager = transactionManager;
  
}
   public TransactionTemplate(PlatformTransactionManager transactionManager,

TransactionDefinition transactionDefinition) {
     
super(transactionDefinition);
      this
.transactionManager = transactionManager;
  
}
  
@Override
  
public void afterPropertiesSet() {
     
if (this.transactionManager == null) {
        
throw new IllegalArgumentException("Property 'transactionManager' is required");
     
}
   }

// TransactionCallback 回调接口中定义需要以事务方式组织的数据访问逻辑
   @Override
  
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
     
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
   
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
     
} else {
         TransactionStatus status =
this.transactionManager.getTransaction(this);
        
T result;
         try
{
            result = action.doInTransaction(status)
;
        
} catch (RuntimeException ex) {
           
// Transactional code threw application exception -> rollback
           
rollbackOnException(status, ex);
            throw
ex;
        
} catch (Error err) {
           
// Transactional code threw error -> rollback
           
rollbackOnException(status, err);
            throw
err;
        
} catch (Throwable ex) {
           
// Transactional code threw unexpected exception -> rollback
           
rollbackOnException(status, ex);
     throw new
UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
        
}
        
this.transactionManager.commit(status);
         return
result;
     
}
   }

   private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
      try {
        
this.transactionManager.rollback(status);
     
} catch (TransactionSystemException ex2) {
         ex2.initApplicationException(ex);
         throw
ex2;
     
} catch (RuntimeException ex2) {
         throw ex2;
     
catch (Error err) {
         throw err;
     
}
   }
}

 

TransactionCallback

public interface TransactionCallback<T> {
   T doInTransaction(TransactionStatus status); //如果操作不会返回结果,则可用TransactionCallback的子接口 TransactionCallbackWithoutResult
}

 

 

使用TransactionTemplate

TransactionTemplate使用回调方法,把应用程序从处理取得和释放资源中解脱出来。TransactionTemplate是线程安全的。

    TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate

    Object result = tt.execute(

        new TransactionCallback(){ 

            public Object doTransaction(TransactionStatus status){ 

                updateOperation(); 

                return resultOfUpdateOperation(); 

            } 

    }); // 执行execute方法进行事务管理

使用TransactionCallback()可以返回一个值。如果使用TransactionCallbackWithoutResult则没有返回值。

 

 

@Service

public class ForumServicel {

public ForumDao forumDao;

public TransactionTemplate template;

@Autowired        // 通过AOP自动注入

public void setTemplate(TransactionTemplate template) {

this.template = template;

}

public void addForum(final Forum forum) {

template.execute(new TransactionCallbackWithoutResult() {

protected void doInTransactionWithoutResult(TransactionStatus status) {  //需要在事务环境中执行的代码

forrxmDao. addForum(forum);

});

}

}

 

 

TransactionProxyFactoryBean:Spring事务配置与使用的源头

TransactionProxyFactoryBean会读取配置文件中的事务属性并构造出代理对象(proxy)

通过TransactionProxyFactoryBean,spring会返回一个代理对象,当调用配置了事务属性的目标方法时,spring首先会判断该方法是否是事务方法,依据是在配置文件中为目标方法设置的事务属性

如果目标方法是事务方法,那么spring就会进入到事务过程中

 

@SuppressWarnings("serial")
public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean implements BeanFactoryAware {
  
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
   @Setter private
Pointcut pointcut;


   public void setTransactionManager(PlatformTransactionManager transactionManager) {
     
this.transactionInterceptor.setTransactionManager(transactionManager);
  
}
   public void setTransactionAttributes(Properties transactionAttributes) {
     
this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
  
}
   public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
     
this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource);
  
}
   @Override
  
public void setBeanFactory(BeanFactory beanFactory) {
     
this.transactionInterceptor.setBeanFactory(beanFactory);
  
}
   @Override
  
protected Object createMainInterceptor() {
     
this.transactionInterceptor.afterPropertiesSet();
      if
(this.pointcut != null) {
        
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
     
} else { // Rely on default pointcut.
        
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
      
}
   }

   @Override
  
protected void postProcessProxyFactory(ProxyFactory proxyFactory) {
      proxyFactory.addInterface(TransactionalProxy.
class);
  
}
}

 

 

TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
   public TransactionInterceptor() {   }
   public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
      setTransactionManager(ptm)
;
     
setTransactionAttributes(attributes);  // 加入配置文件,进行解析

   }
   public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
      setTransactionManager(ptm)
;
     
setTransactionAttributeSource(tas);
  
}

// 目标方法调用前调用
   @Override
  
public Object invoke(final MethodInvocation invocation) throws Throwable {
     
// Work out the target class: may be {@code null}. The TransactionAttributeSource should be passed the target class as well as the method, which may be from an interface.
     
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);  // 获取目标类
      // Adapt to TransactionAspectSupport's invokeWithinTransaction...
     
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
        
@Override
        
public Object proceedWithInvocation() throws Throwable {
           
return invocation.proceed();
        
}
      })
;
  
}
   // Serialization support
  
private void writeObject(ObjectOutputStream oos) throws IOException {
     
// Rely on default serialization, although this class itself doesn't carry state anyway...
     
oos.defaultWriteObject();
     
// Deserialize superclass fields.
     
oos.writeObject(getTransactionManagerBeanName());
     
oos.writeObject(getTransactionManager());
     
oos.writeObject(getTransactionAttributeSource());
     
oos.writeObject(getBeanFactory());
  
}
  
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
     
// Rely on default serialization, although this class itself doesn't carry state anyway...
     
ois.defaultReadObject();
     
// Serialize all relevant superclass fields.
      // Superclass can't implement Serializable because it also serves as base class
      // for AspectJ aspects (which are not allowed to implement Serializable)!
     
setTransactionManagerBeanName((String) ois.readObject());
     
setTransactionManager((PlatformTransactionManager) ois.readObject());
     
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
     
setBeanFactory((BeanFactory) ois.readObject());
  
}
}

TransactionAspectSupport

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {

private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<Object, PlatformTransactionManager>(4);

private PlatformTransactionManager transactionManager;

@Getter @Setter private TransactionAttributeSource transactionAttributeSource;  // 一个方法对应事务的信息的封装,就是封装了TransactionAttribute

public void setTransactionAttributes(Properties transactionAttributes) {

   NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();//适配的TransactionAttribute

   tas.setProperties(transactionAttributes);

   this.transactionAttributeSource = tas;  // 保存
}
public void setTransactionAttributeSources(TransactionAttributeSource[] transactionAttributeSources) {

   this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources);

}

protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
  
// Do not attempt to lookup tx manager if no tx attributes are set
  
if (txAttr == null || this.beanFactory == null) {
     
return getTransactionManager();
  
}
   String qualifier = txAttr.getQualifier()
;
   if
(StringUtils.hasText(qualifier)) {
     
return determineQualifiedTransactionManager(qualifier);
  
} else if (StringUtils.hasText(this.transactionManagerBeanName)) {
     
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
  
} else {
      PlatformTransactionManager defaultTransactionManager = getTransactionManager()
;
      if
(defaultTransactionManager == null) {
         defaultTransactionManager =
this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
         if
(defaultTransactionManager == null) {
            defaultTransactionManager =
this.beanFactory.getBean(PlatformTransactionManager.class);
            this
.transactionManagerCache.putIfAbsent(
                 
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
        
}
      }
     
return defaultTransactionManager;
  
}
}

private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) {

   PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier);

   if (txManager == null) {

      txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, PlatformTransactionManager.class, qualifier);

      this.transactionManagerCache.putIfAbsent(qualifier, txManager);

   }

   return txManager;

}

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
  
//If the transaction attribute is null,the method is non-transactional.如果事务属性为空,则方法是非事务性的
   final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); // 一个方法配置事务后,会对应一个TransactionAttribute对象,这个对象封装的是方法的名字和方法的属性

获取与目标方法所对应事务的属性

   final PlatformTransactionManager tm = determineTransactionManager(txAttr)

   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
   if
(txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
     
// Standard transaction demarcation with getTransaction and commit/rollback calls.
     
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
     
Object retVal = null;
      try
{
        
// This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
        
retVal = invocation.proceedWithInvocation();
     
catch (Throwable ex) {
         completeTransactionAfterThrowing(txInfo, ex); // target invocation exception
         throw ex;
     
finally {
         cleanupTransactionInfo(txInfo)
;
     
}
      commitTransactionAfterReturning(txInfo)
;
      return
retVal;
  
}
  
else {
     
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
     
try {
         Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr
,
               new
TransactionCallback<Object>() {
                 
@Override
                 
public Object doInTransaction(TransactionStatus status) {
            TransactionInfo txInfo = prepareTransactionInfo(
tm, txAttr, joinpointIdentification, status);
                     try
{
                       
return invocation.proceedWithInvocation();
                    
catch (Throwable ex) {
                       
if (txAttr.rollbackOn(ex)) {   // A RuntimeException: will lead to a rollback.
                          
if (ex instanceof RuntimeException) {
                             
throw (RuntimeException) ex;
                          
} else {
                             
throw new ThrowableHolderException(ex);
                           
}
                        }
else {   // A normal return value: will lead to a commit.
                          
return new ThrowableHolder(ex);
                       
}
                     }
finally {
                        cleanupTransactionInfo(txInfo)
;
                    
}
                  }
               })
;
        
// Check result: It might indicate a Throwable to rethrow.
        
if (result instanceof ThrowableHolder) {
           
throw ((ThrowableHolder) result).getThrowable();
        
} else {
           
return result;
        
}
      }
catch (ThrowableHolderException ex) {
        
throw ex.getCause();
     
}
   }
}

protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm,
TransactionAttribute txAttr, final String joinpointIdentification) {

  // If no name specified, apply method identification as transaction name.

   if (txAttr != null && txAttr.getName() == null) {    // 没有取名字,就帮忙起名字
     txAttr = new DelegatingTransactionAttribute(txAttr) {

         @Override

         public String getName() {

            return joinpointIdentification;

         }

      };

   }

   TransactionStatus status = null;  //事务状态
   if (txAttr != null) {

      if (tm != null) {

         status = tm.getTransaction(txAttr);

      }

   }

   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

}
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {

   TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);

   if (txAttr != null) {

      // We need a transaction for this method... 

      // The transaction manager will flag an error if an incompatible tx already exists.

      txInfo.newTransactionStatus(status);

   } else {

// The TransactionInfo.hasTransaction() method will return false. We created it only to preserve the integrity of the ThreadLocal stack maintained in this class.  We always bind the TransactionInfo to the thread, even if we didn't create a new transaction here. This guarantees that the TransactionInfo stack will be managed correctly even if no transaction was created by this aspect.

   txInfo.bindToThread();

   return txInfo;

}

NameMatchTransactionAttributeSource

public class NameMatchTransactionAttributeSource implements TransactionAttributeSource, Serializable {
private Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>();
public void setProperties(Properties transactionAttributes) {

   TransactionAttributeEditor tae = new TransactionAttributeEditor();

   Enumeration<?> propNames = transactionAttributes.propertyNames(); // 获取配置文件的所有配置元素

   while (propNames.hasMoreElements()) {

      String methodName = (String) propNames.nextElement();

      String value = transactionAttributes.getProperty(methodName);

      tae.setAsText(value);

      TransactionAttribute attr = (TransactionAttribute) tae.getValue();  // 这里将set进去的get出来
      addTransactionalMethod(methodName, attr);

   }

}
public void addTransactionalMethod(String methodName, TransactionAttribute attr) {

   this.nameMap.put(methodName, attr);

}

TransactionAttributeEditor

public class TransactionAttributeEditor extends PropertyEditorSupport {

   /**

    * Format is PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2.

    * Null or the empty string means that the method is non transactional.

    * @see java.beans.PropertyEditor#setAsText(java.lang.String)

    */

   @Override

   public void setAsText(String text) throws IllegalArgumentException {  // 这里就是对配置文件配置的事务进行解析并保存封装到PropertyEditorSupport

      if (StringUtils.hasLength(text)) {

         // tokenize it with ","

         String[] tokens = StringUtils.commaDelimitedListToStringArray(text);

         RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute();

         for (int i = 0; i < tokens.length; i++) {

            // Trim leading and trailing whitespace.

            String token = StringUtils.trimWhitespace(tokens[i].trim());

            // Check whether token contains illegal whitespace within text.

            if (StringUtils.containsWhitespace(token)) {

               throw new IllegalArgumentException("Transaction attribute token contains illegal whitespace: [" + token + "]");

            }

            // Check token type.

            if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_PROPAGATION)) {

               attr.setPropagationBehaviorName(token);

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ISOLATION)) {

               attr.setIsolationLevelName(token);

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_TIMEOUT)) {

               String value = token.substring(DefaultTransactionAttribute.PREFIX_TIMEOUT.length());

               attr.setTimeout(Integer.parseInt(value));

            else if (token.equals(RuleBasedTransactionAttribute.READ_ONLY_MARKER)) {

               attr.setReadOnly(true);

            else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_COMMIT_RULE)) {

               attr.getRollbackRules().add(new NoRollbackRuleAttribute(token.substring(1)));

            } else if (token.startsWith(RuleBasedTransactionAttribute.PREFIX_ROLLBACK_RULE)) {

               attr.getRollbackRules().add(new RollbackRuleAttribute(token.substring(1)));

            } else {

               throw new IllegalArgumentException("Invalid transaction attribute token: [" + token + "]");

            }

         }

         setValue(attr);//后续会被get出来
      } else {

         setValue(null);  // PropertyEditorSupport类中进行实现

      }

   }

}

 

猜你喜欢

转载自blog.csdn.net/qq_34190023/article/details/82833966