Spring事务总结

236 阅读4分钟

1. 什么是事务?

事务是逻辑上的一组操作,要么都执行,要么都不执行。

2. 事物的特性(ACID)了解嘛?

  • 原子性(Atomicity): 一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
  • 一致性(Consistency): 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
  • 隔离性(Isolation): 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • 持久性(Durability): 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

参考 :zh.wikipedia.org/wiki/ACID

3. 详谈Spring对事务的支持

3.1. Spring 支持2种方式的事务管理

1). 编程式事务管理

通过 TransactionTemplate或者TransactionManager手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。

使用TransactionTemplate 进行编程式事务管理的示例代码如下:

 @Autowired
 private TransactionTemplate transactionTemplate;
 public void testTransaction() {
 ​
         transactionTemplate.execute(new TransactionCallbackWithoutResult() {
             @Override
             protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
 ​
                 try {
 ​
                     // ....  业务代码
                 } catch (Exception e){
                     //回滚
                     transactionStatus.setRollbackOnly();
                 }
 ​
             }
         });
 }

使用 TransactionManager 进行编程式事务管理的示例代码如下:

 @Autowired
 private PlatformTransactionManager transactionManager;
 ​
 public void testTransaction() {
 ​
   TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
           try {
                // ....  业务代码
               transactionManager.commit(status);
           } catch (Exception e) {
               transactionManager.rollback(status);
           }
 }

2).声明式事务管理

推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)。

使用 @Transactional注解进行事务管理的示例代码如下:

 @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
 public void aMethod {
   //do something
   B b = new B();
   C c = new C();
   b.bMethod();
   c.cMethod();
 }

3.2. Spring 事务管理接口介绍

3.2.1. PlatformTransactionManager:事务管理接口

  • 获得事务

  • 提交事务

  • 回滚事务

3.2.2. TransactionDefinition:事务属性

  • 隔离级别
  • 传播行为
  • 回滚规则
  • 是否只读
  • 事务超时

3.2.3. TransactionStatus:事务状态

3.3. 事务属性详解

3.3.1. 事务传播行为

  1. TransactionDefinition.PROPAGATION_REQUIRED

我们使用最对的一个事务,@Transactional 注解默认就是用这个事务传播行为。若当前存在事务,就加入该事务;如果当前没有事务,就创建一个新事务。

  1. TransactionDefinition.PROPAGATION_REQUIRED_NEW

创建一个新的事务,如果担起啊存在事务,则吧当前存在的事务挂起。无论如何,我都会开启一个新的事务。

  1. TransactionDefinition.PROPAGATION_NESTED

如果当前存在事务,那么创建一个事务作为当前事务的嵌套事务来执行,如果没有事务,那么就等价于TransactionDefinition.PROPAGATION_REQUIRED

如果 aMethod() 回滚的话,bMethod()bMethod2()都要回滚,而bMethod()回滚的话,并不会造成 aMethod()bMethod()2回滚。

  1. TransactionDefinition.PROPAGATION_MANDATORY

如果当前存在事务,就加入该事务;如果当前没有事务,那么就抛出异常!

(使用很少)

3.3.2. 事务隔离级别

  • TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

3.3.3. 事务超时属性

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒,默认值为-1。

3.3.4. 事务只读属性

3.3.5. 事务回滚规则

3.4. @Transactional注解使用详解

3.4.1. @Transactional的作用范围

3.4.2. @Transactional的常用配置参数

3.4.3. @Transactional事务注解原理

3.4.4. Spring AOP 自调用问题

3.4.5. @Transactional 使用注意事项总结