功能第四篇——事务之Spring事务()

综述

事务的实现方式有三种,JTA,Spring事务,Web Container方式。本篇讲述Spring事务。

Spring事务分为两个部分核心对象,Spring事务的实现方式。

Spring事务实现的方式有三种。声明式,注解式,代码的方式。声明方式在实际项目中运用比较广泛,注解方式需要在每个方法上添加@Transactional注解,代码冗余度比较高。代码方式只是为了更好的理解Spring事务的机制,在实际项目中并不适用。

核心对象

PlatformTransactionManager

事务管理接口。

  1. Transaction getTransaction(transactionDefinition) :通过事务定义对象获取事务
  2. commit(transactionStatus):提交事务
  3. rollback(transactionStatus):回滚事务。

TransactionDefinition

事务的属性或定义对象。包含的属性如下:

Isolation:事务的隔离级别。

    1. TRANSACTION_NONE:表示不支持事务。值为0,
    2. TRANSACTION_READ_UNCOMMITED:表示一个事务可以读取另外事务未提交的数据。存在脏读。值为1
    3. TRANSACTION_READ_COMMITED:表示只读取已提交的数据。防止脏读。存在重复读,幻读。值为2
    4. TRANSACTION_REPEATABLE_READ:表示在读取过程中不允许修改操作。防止一个事务多次查询得到不同的值。防止脏读,重复读,存在虚读。值为4
    5. 当为TRANSACTION_SERIALIZABLE:TODO,值为8.

Propagation:事务的传播机制。

    1. Never:表示没有事务。
    2. NOT SUPPORT:表示不支持事务。
    3. REQUIRED:为每个方法的事务创建一个域(Scope),内部方法共享外部方法的域,内部方法可以在自己的域内回滚事务,此时外部方法的事务不受内部方法事务的影响,外部事物依然可以提交。但是外部事物会捕获到UnexeceptedRollBackException。类似于语言中的函数,或方法,内部方法有自己独立的域,外部方法也有自己独立的域,内部方法可以访问外部方法的变量等等。
    4. REQUIRED NEW:为每个方法创建一个事务,彼此无关联。
    5. NESTED:为外部方法创建一个事务,多个存档点。内部方法与外部方法在同一事务内。

Timeout:超时时间。

read-only:是否是只读的事务。

TransactionStatus

表示一个新创建的事务或者已存在的事务。

  1. isNewTransaction:是否是新事务。
  2. hasSavepoint:事务是否有存放点
  3. setRollbackOnly:回滚事务
  4. isRollbackOnly:TODO
  5. flush:TODO
  6. isCompleted:事务是否执行完成。

代码示例如下:

 1 //第一步:创建事务属性对象TransactionDefinition,创建事务管理对象TransactionManager。
 2 // 创建事务属性对象
 3 DefaultTransactionDefinition def = new DefaultTransactionDefinition();
 4 def.setName("trans1");
 5 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
 6 // 创建事务管理对象
 7 DataSourceTransactionManager transcationManager = new DataSourceTransactionManager();
 8
 9 //第二步:获取事务对象,
10 TransactionStatus status = transcationManager.getTransaction(def);
11 //第三步:实现业务逻辑代码
12 try
13 {
14     // 代码逻辑
15 }
16 catch(Exception e)
17 {
18     transcationManager.rollback(status);
19     throw e;
20 }
21 transcationManager.commit(status);

实现方式

spring事务实现的方式有三种。配置切面方式,注解方式,代码方式。配置切面方式在实际项目中运用比较广泛,注解方式需要在每个方法上添加@Transactional注解,代码冗余度比较高。代码方式只是为了更好的理解Spring事务的机制,在实际项目中并不适用。

配置切面方式

第一步:配置事务管理。

<!-- 配置事务管理 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property>
</bean>

第二步:通过”tx:advice”标签配置事务的场景。指定在哪些方法上配置事务,以及这些事务的定义。tx:advice包含一个或多个tx:attribtue,tx:attribute包含一个或多个tx:method。tx:method标签配置具体的事务。

tx:method的属性有

  1. name:表示方法的名称,可以使用通配符。例如get*表示以get开头的方法,如果配置多个,使用逗号隔开。
  2. isolation:配置事务的隔离级别。参考TransactionDefinition
  3. propagation:配置事务的传播机制。传播机制的种类如下:
  4. rollbackFor:指定运行时让事务回滚的异常。这些异常必须是运行时异常,而且需要指定异常类的全路径名。默认情况下,只要运行时出现异常,就回滚事务。
  5. noRollbackFor:指定运行时不会让事务回滚的异常。
  6. timeout:表示超时时间,事务执行超过当前时间,事务自动回滚。默认值为-1,表示永不超时。

示例如下:

<tx:advice id="txAdvice">
    <tx:attributes>
        <!--方法名称以get开头的事务为只读事务,隔离级别为SERIALIZABLE-->
        <tx:method name="get*" read-only="true" isolation="SERIALIZABLE"  />
        <!--方法名称以insert开头的事务,隔离级别为SERIALIZABLE,传播机制为REQUIRED,当发生TestException时回滚事务,ArithmeticException不会回滚事务。-->
        <tx:method name="insert*" isolation="SERIALIZABLE" timeout="20" propagation="REQUIRED"
             rollback-for="com.rain.exception.TestException"
no-rollbackfor="java.lang.ArithmeticException" />
        <tx:method name="*" isolation="READ_COMMITTED" />
    </tx:attributes>
</tx:advice>

第三步:通过aop:config配置事务切面。aop:config包含一个或多个(aop:pointcut,aop:advisor)。aop:pointcut指定为哪些类配置切面,aop:advisor将tx:advice与aop:pointcut关联起来。其中aop:config标签中expression的格式为:execution(* packageName.className.*(..))。它是SPEL表达式。

示例如下:

<aop:config>
    <aop:pointcut expression="execution(* com.rain.service.*.*(..))"  id="studentServiceMethod" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="studentServiceMethod" />
</aop:config> 

如果配置多个事务,重复上述步骤。也可以在aop:config中配置多组(aop:pointcut,aop:advisor)。

第四步:验证。使用Log4J日志,将级别设置为DEBUG。启动时,会加载事务的配置。

2017-05-30 12:22:00 DEBUG NameMatchTransactionAttributeSource:96 - Adding transactional method [get*] with attribute [PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,readOnly]

2017-05-30 12:22:00 DEBUG NameMatchTransactionAttributeSource:96 - Adding transactional method [insert*] with attribute [PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE,timeout_20,-com.rain.exception.TestException,+java.lang.ArithmeticException]

2017-05-30 12:22:00 DEBUG NameMatchTransactionAttributeSource:96 - Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED]

运行insertXX方法时,显示事务处理的详细过程。

2017-05-30 11:49:57 DEBUG DataSourceTransactionManager:367 - Creating new transaction with name [com.rain.service.impl.StudentServiceImpl.insertStudent]: PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE,timeout_20,-com.rain.exception.TestException,+java.lang.ArithmeticException。

2017-05-30 11:49:58 TRACE TransactionInterceptor:517 - Completing transaction for [com.rain.service.impl.StudentServiceImpl.insertStudent] after exception: java.lang.ArithmeticException: / by zero

2017-05-30 11:49:58 TRACE RuleBasedTransactionAttribute:131 - Applying rules to determine whether transaction should rollback on java.lang.ArithmeticException: / by zero

2017-05-30 11:49:58 TRACE RuleBasedTransactionAttribute:148 - Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.ArithmeticException]

2017-05-30 11:49:58 DEBUG DataSourceTransactionManager:759 - Initiating transaction commit
2017-05-30 11:49:58 DEBUG DataSourceTransactionManager:310 - Committing JDBC transaction on Connection [[email protected]]
2017-05-30 11:49:58 TRACE TransactionSynchronizationManager:331 - Clearing transaction synchronization

当insertXX方法有java.lang.ArithmeticException异常时。不会回滚事务。

2017-05-30 12:09:17 TRACE RuleBasedTransactionAttribute:131 -Applying rules to determine whether transaction should rollback on java.lang.ArithmeticException: / by zero
2017-05-30 12:09:17 TRACE RuleBasedTransactionAttribute:148 - Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.ArithmeticException]

当insertXX方法中有TestException异常时。回滚事务。

Applying rules to determine whether transaction should rollback on com.rain.exception.TestException: 这是测试用的异常
2017-05-30 12:22:01 TRACE RuleBasedTransactionAttribute:148 - Winning rollback rule is: RollbackRuleAttribute with pattern [com.rain.exception.TestException]
2017-05-30 12:22:01 DEBUG DataSourceTransactionManager:851 - Initiating transaction rollback
2017-05-30 12:22:01 DEBUG DataSourceTransactionManager:325 - Rolling back JDBC transaction on Connection [[email protected]]

注解方式

第一步:配置事务管理。与声明式事务完全相同。参考配置切面方式第一步

第二步:通过tx:annotation-driven配置事务支持注解方式。tx:annotation-driven的属性有

  1. transaction-manager:指定事务管理的名称,默认值为transactionManager。所以当名称为transactionManager时,可以忽略。
  2. mode:注解的模式,模式有两种,proxy与aspectj,默认方式为proxy。
  3. proxy-target-class:识别注解的方式。@Transactional可以在接口的方法上,也可以在具体类的方法上。当设置为false时,既可以识别具体类上的@Transactional注解,也可以识别接口上的@Transactional。当为true时,接口上的@Transactional将被忽略。默认值为false。
  4. order:TODO。

示例如下:

<!-- 配置注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager" mode="proxy" proxy-target-class="true"/>

第三步:在方法上加@Transactional注解,该注解属性的含义如下:

  1. value:表示事务管理器的名称,如果配置中存在多个事务管理器,trans1,trans2。value值用来指定当前事务所属的事务管理器。
  2. isolation:事务的隔离级别。参考事务隔离级别,默认值为READ_COMMITED。
  3. propagation:事务的传播机制,参考事务传播机制
  4. readOnly:是否是只读事务。true表示是,false表示否,默认值为false。
  5. rollbackFor:指定发生哪些异常时,事务回滚,默认值为Exception.class。异常类型为运行时异常
  6. rollbackForClassName:含义与rollbackFor相同,值为异常类的名称字符串。
  7. noRollbackFor:指定发生哪些异常时,事务不会回滚,无默认值
  8. noRollbackForClassName:含义为noRollbackFor相同,值为异常类的名称字符串。
    @Transactional(propagation=Propagation.REQUIRED,isolation = Isolation.SERIALIZABLE,timeout=20,rollbackFor = {com.rain.exception.TestException.class},
            noRollbackFor = {java.lang.ArithmeticException.class})

第四步:验证。在运行该方法时。会加载事务属性,并创建事务。

2017-05-30 14:06:57 DEBUG AnnotationTransactionAttributeSource:116 - Adding transactional method ‘com.rain.service.impl.StudentServiceImpl.insertStudent‘ with attribute: PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE; ‘‘,-com.rain.exception.TestException,-java.lang.NullPointerException,+java.lang.ArithmeticException

2017-05-30 14:06:57 DEBUG DataSourceTransactionManager:367 - Creating new transaction with name [com.rain.service.impl.StudentServiceImpl.insertStudent]: PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE; ‘‘,-com.rain.exception.TestException,-java.lang.NullPointerException,+java.lang.ArithmeticException

当发生TestException时,事务回滚。

2017-05-30 14:06:57 TRACE RuleBasedTransactionAttribute:131 - Applying rules to determine whether transaction should rollback on com.rain.exception.TestException: 这是测试用的异常
2017-05-30 14:06:57 TRACE RuleBasedTransactionAttribute:148 - Winning rollback rule is: RollbackRuleAttribute with pattern [com.rain.exception.TestException]

当发生ArithmeticException时,事务不会回滚。

2017-05-30 12:09:17 TRACE RuleBasedTransactionAttribute:131 - Applying rules to determine whether transaction should rollback on java.lang.ArithmeticException: / by zero
2017-05-30 12:09:17 TRACE RuleBasedTransactionAttribute:148 - Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.ArithmeticException]

代码方式

代码实现事务的方式有两种,一种是TransactionTemplate,该对象可以设置事务的属性。另外一种是TransactionManager方式。TransactionManager方参考核心对象下面的代码示例。

TransactionTemplate方式

第一步:初始化TransactionTemplate,

 1 // 创建事务template类
 2 private final TransactionTemplate tranTemp;
 3
 4 // 创建学生的service类
 5 @Autowired
 6 private IStudentService studentService;
 7
 8 // 在构造器中初始化TransactionTemplate
 9 public TransactionServiceImpl(PlatformTransactionManager tranManager) {
10     Assert.notNull(tranManager, "The ‘tranManager‘ argument must not be null ");
11     this.tranTemp = new TransactionTemplate(tranManager);
12 }

第二步:调用transactionTemplate的execute方法,参数为TransactionCallback,或者是TransactionCallbackWithoutResult,前者返回类型为void,后者有返回类型。

无返回类型TransactionCallbackWithoutResult

 1 // 通过代码的方式实现事务
 2 @Override
 3 public void insertStudent(Student stu) {
 4     tranTemp.execute(new TransactionCallbackWithoutResult() {
 5         @Override
 6         protected void doInTransactionWithoutResult(TransactionStatus status) {
 7             try {
 8                  // 代码逻辑
 9             } catch (Exception e) {
10                 e.printStackTrace();
11                 status.setRollbackOnly();
12             }
13         }
14     });
15 }      

有返回类型TransactionCallback<T>

 1 public void insertStudentWithReturn(Student stu)
 2 {
 3     tranTemp.execute(new TransactionCallback<Student>() {
 4         @Override
 5         public Student doInTransaction(TransactionStatus status) {
 6             try
 7             {
 8                 // 代码逻辑
 9             }catch(Exception e)
10             {
11                 e.printStackTrace();
12                 // 回滚事务
13                 status.setRollbackOnly();
14             }
15             return stu;
16         }});
17 }

至此本篇内容结束

时间: 2024-10-23 13:06:34

功能第四篇——事务之Spring事务()的相关文章

hibernate的事务和spring事务的区别 (转)

spring事务: 对于传统的基于特定事务资源的事务处理而言(如基于JDBC的数据库访问),Spring并不会对其产生什么影响,我们照样可以成功编写并运行这样的代码.同时,Spring还提供了一些辅助类可供我们选择使用,这些辅助类简化了传统的数据库操作流程,在一定程度上节省了工作量,提高了编码效率 对于依赖容器的参数化事务管理而言,Spring则表现出了极大的价值.Spring本身也是一个容器,只是相对EJB容器而言,Spring显得更为轻便小巧.我们无需付出其他方面的代价,即可通过Spring

深入Spring事务(一)Spring事务概述

Spring事务概述 一.事务概述 事务首先是一系列操作组成的工作单元,该工作单元内的操作是不可分割的,即要么所有操作都做,要么所有操作都不做,这就是事务. 事务必需满足ACID(原子性.一致性.隔离性和持久性)特性,缺一不可: 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做: 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整 性约束没有被破坏:如银行转帐,A转帐给

spring学习笔记:spring事务管理 (转)

关于事物隔离级别, 脏读, 不可重复读, 幻读的理解, 另有一篇文章比较生动的介绍:http://blog.csdn.net/sunxing007/article/details/6427290 spring事务管理相关的接口: TransactionDefinition:代表一个事物,描述了事务的隔离级别, 超时时间,事务是否只读, 传播规则等等; TransactionStatus:描述事物的状态; PlatformTransactionManager:事务管理器接口, 只定义了3个方法:g

深入理解 Spring 事务原理

一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(); 使

Spring事务管理之几种方式实现事务(转)

一:事务认识 大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销.Spring事务管理基于底层数据库本身的事务处理机制.数据库事务的基础,是掌握Spring事务管理的基础.这篇总结下Spring事务. 事务具备ACID四种特性,ACID是Atomic(原子性).Consistency(一致性).Isolation(隔离性)和Durability(持久性)的英文缩写. (1)原子性(Atomicity) 事务最基本的操作单元,要么全部成功,要么全部失败,

Spring事务管理之几种方式实现事务

也可以参考https://blog.csdn.net/liuhaiabc/article/details/52450167 https://blog.csdn.net/baidu_37107022/article/details/77481670 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted.Read committed.Repeatable read.Serializable,这四个级别可以逐个解决脏读.不可重复读.幻读这几类问题. √: 可能出现    ×: 不

一文带你深入浅出Spring 事务原理

Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的.对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取连接 Connection con = DriverManager.getConnection() 开启事务con.setAutoCommit(true/false); 执行CRUD 提交事务/回滚事务 con.commit() / con.rollback(); 关闭连接 conn.close(

spring 事务管理详解 学习心得

今天,我终于登上了你的诺曼底,spring事务. 在此之前,一谈起spring我就没底,虽然用的很顺手,但是其中的AOP和事务一直未理解和掌握,数次尝试突破都未成功,之前看过很多网上的相关文章和书籍,要么基于的版本不同,有的基于spring2有的基于spring3:要么切入点不同,有的讲的太低级,我都懂,有的讲的太庞杂,我晕了...... 从这周一开始,我决定在试一下.计划每天的上午专门学习,横扫各大网站,收集文章,然后对其分类,整理记笔记,到周二坚持一个一个的看,规整,理解,熟记,本子下写下了

Spring事务传播行为中可能的坑点

一.简介 Spring事务配置及相关说明详见:https://www.cnblogs.com/eric-fang/p/11052304.html.这里说明spring事务的几点注意: 1.默认只会检查回滚RuntimeException的异常. 2.@Transactional注解只能作用于public的方法上,默认传播行为 Propagation.REQUIRED 3.service内部方法之间的调用,不会被spring拦截到,也即不会产生事务 二.坑点 主要的坑点就是在嵌套事务上,当serv