赞
踩
事务是逻辑上的一组操作,要么都执行,要么都不执行。
需要注意的是:事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的 innodb引擎。但是,如果把数据库引擎变为 myisam,那么程序也就不再支持事务了!
通过 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);
- }
- }
推荐使用(代码侵入性最小),实际是通过 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();
- }
作用范围
方法:推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效
类:如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效。
接口 :不推荐在接口上使用。
@Transactional注解源码如下,里面包含了基本事务属性的配置:
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Inherited
- @Documented
- public @interface Transactional {
-
- @AliasFor("transactionManager")
- String value() default "";
-
- @AliasFor("value")
- String transactionManager() default "";
-
- Propagation propagation() default Propagation.REQUIRED;
-
- Isolation isolation() default Isolation.DEFAULT;
-
- int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
-
- boolean readOnly() default false;
-
- Class<? extends Throwable>[] rollbackFor() default {};
-
- String[] rollbackForClassName() default {};
-
- Class<? extends Throwable>[] noRollbackFor() default {};
-
- String[] noRollbackForClassName() default {};
-
- }
-

@Transactional 的常用配置参数总结:
- isolation:用于指定事务的隔离级别。默认底层事务的隔离级别。
- noRollbackFor:指定遇到特定异常时强制不回滚事务。
- noRollbackForClassName:指定遇到特定的多个异常时强制不回滚事务。该属性值可以指定多个异常类名。
- propagation:指定事务传播行为
- readOnly:指定事务是否只读。
- rollbackFor:指定遇到特定异常时强制回滚事务。
- rollbackForClassName:指定遇到特定的多个异常强制回滚事务。该属性值可以指定多个异常类名。
- timeout:指定事务的超时时长。单位为秒,当超时时,会引发异常,默认会导致事务回滚。
使用声明式事务需要配置注解驱动,在配置文件中加上如下配置就可以使用@Transactional配置事务了。
- <!-- 根据注解生成事务代理-->
- <tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional 的使用注意事项总结
- @Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
- 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;
- 正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败;
- 被 @Transactional 注解的方法所在的类必须被 Spring 管理,否则不生效;
- 底层使用的数据库必须支持事务机制,否则不生效。
Spring 框架中,事务管理相关最重要的 3 个接口如下:
- PlatformTransactionManager: (平台)事务管理器,Spring 事务策略的核心。
- TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。
- TransactionStatus:事务运行状态
我们可以把 PlatformTransactionManager 接口可以被看作是事务上层的管理者,而 TransactionDefinition 和 TransactionStatus 这两个接口可以看作是事务的描述。
PlatformTransactionManager 会根据 TransactionDefinition 的定义比如事务超时时间、隔离级别、传播行为等来进行事务管理 ,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态比如是否新事务、是否可以回滚等等。
Spring 并不直接管理事务,而是提供了多种事务管理器 。Spring 事务管理器的接口是:PlatformTransactionManager。
通过这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager接口中定义了三个方法:
- package org.springframework.transaction;
-
- import org.springframework.lang.Nullable;
-
- public interface PlatformTransactionManager {
- //获得事务
- TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
- //提交事务
- void commit(TransactionStatus var1) throws TransactionException;
- //回滚事务
- void rollback(TransactionStatus var1) throws TransactionException;
- }
事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。
事务属性包含了5个方面:
TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。
- package org.springframework.transaction;
-
- import org.springframework.lang.Nullable;
-
- 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;
- int ISOLATION_DEFAULT = -1;
- int ISOLATION_READ_UNCOMMITTED = 1;
- int ISOLATION_READ_COMMITTED = 2;
- int ISOLATION_REPEATABLE_READ = 4;
- int ISOLATION_SERIALIZABLE = 8;
- int TIMEOUT_DEFAULT = -1;
- // 返回事务的传播行为,默认值为 REQUIRED。
- int getPropagationBehavior();
- //返回事务的隔离级别,默认值是 DEFAULT
- int getIsolationLevel();
- // 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
- int getTimeout();
- // 返回是否为只读事务,默认值为 false
- boolean isReadOnly();
-
- @Nullable
- String getName();
- }

原子性:一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
下面我依次对每一种事务隔离级别进行介绍:
- 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 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒,默认值为-1。
事务传播行为是为了解决业务层方法之间互相调用的事务问题。
正确的事务传播行为可能的值如下:
TransactionDefinition.PROPAGATION_REQUIRED
使用的最多的一个事务传播行为,我们平时经常使用的@Transactional注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。也就是说:
- 如果外部方法没有开启事务的话,Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
- 如果外部方法开启事务并且被Propagation.REQUIRED的话,所有Propagation.REQUIRED修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务均回滚。
传播行为是指方法之间的调用事务策略的问题,Spring支持的事务传播行为如下:
Spring支持的事务传播行为包括:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER和NESTED。其中,
- REQUIRED表示如果当前存在事务,则加入该事务,否则创建一个新的事务;
- SUPPORTS表示如果当前存在事务,则加入该事务,否则以非事务状态执行;
- MANDATORY表示必须存在一个事务,否则抛出异常;
- REQUIRES_NEW表示创建一个新的事务,并挂起当前的事务;
- NOT_SUPPORTED表示以非事务状态执行,并挂起当前的事务;
- NEVER表示必须不存在事务,否则抛出异常;
- NESTED表示如果当前存在事务,则在嵌套事务内执行,否则创建一个新的事务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。