Spring(Spring MVC/Spring Boot ...)spring

SpringMVC-@Transaction声明事务的使用

2017-06-22  本文已影响0人  zhanglbjames

1- 事务ACID

事务由一系列操作组成的,保证所有操作整体原子执行,完整的事务满足ACID特性

2- 事务管理器

Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。

2.1- PlatformTransactionManager

org.springframework.transaction.PlatformTransactionManager是Spring事务管理器的接口,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

PlatformTransactionManager接口


提供了获取TransactionDefinition的方法以及根据TransactionStatus相应的状态进行提交或者回滚

TransactionStatus事务状态接口

上面讲到的调用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现,这个接口的内容如下:


TransactionDefinition事务定义的接口

而TransactionDefinition接口内容如下:
属性:



方法:


3- TransactionDefinition接口定义的事务的五个属性

3.1- 传播行为

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,没有默认值。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行

我们可以看 org.springframework.transaction.annotation.Propagation 枚举类中定义了6个表示传播行为的枚举值:

3.2- 隔离级别

隔离级别是指若干个并发的事务之间的隔离程度,与我们开发时候主要相关的场景包括:脏读取、重复读、幻读。

并发事务引起的问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务。并发虽然是必须的,但可能会导致一下的问题。

不可重复读与幻读的区别

我们可以看 org.springframework.transaction.annotation.Isolation 枚举类中定义了五个表示隔离级别的值:

3.3- 只读

事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。

3.4- 事务超时

为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

3.5- 回滚规则

事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常Unchecked时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

4- Spring Boot 基于声明式注解事务使用示例

在Spring Boot中,当我们使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依赖的时候,框 架会自动默认分别注入DataSourceTransactionManager或JpaTransactionManager。所以我们不需要任何额外 配置就可以用@Transactional注解进行事务的使用。关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会默认注入 JpaTransactionManager 实例。

4.1- 事务管理两种方式

spring支持编程式事务管理和声明式事务管理两种方式。

  1. 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

  2. 声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

4.2- 单事务管理开启与配置

在启动类中配置事务管理器

  1. 默认事务管理器,只需开启事务管理器即可,不需显示的配置
  1. 显示的指明事务管理器

如果你项目做的比较大,添加的持久化依赖比较多,我们还是会选择人为的指定使用哪个事务管理器



在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。

4.3- 多事务管理器的配置

对于同一个工程中存在多个事务管理器进行配置



启动类实现TransactionManagementConfigurer接口,通过@Bean注解注入两个事务管理器,实现annotationDrivenTransactionManager接口方法,指定value缺省值情况下提供的默认事务管理器,如下:



注:
如果Spring容器中存在多个 PlatformTransactionManager 实例,并且没有实现接口 TransactionManagementConfigurer 指定默认值,在我们在方法上使用注解 @Transactional 的时候,就必须要用value指定,如果不指定,则会抛出异常。
4.4- @Transaction 注解使用的注意事项

@Transactional属性


noRollback示例



@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

最佳实践:

事务异常排查列表:

  1. 数据库本身是否支持事务,如mysql的myisam引擎就不支持事务
  2. 多数据源,是否指定了正确的事务管理器
  3. 数据源配置是否正确(MyBatis的SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源是否一致)
  4. 私有方法不会生效事务(AOP默认不代理私有方法,也不会抛出异常)
  5. 被调用方法不会生效事务(this指针调用方法,并没有使用AOP代理来执行方法)
  6. 不指明回滚的异常,方法内用户抛出的checked异常不会生效回滚(默认只有unchecked异常发生回滚)

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

@Transaction示例

方法上注解属性会覆盖类注解上的相同属性



事务管理器保证事务方法内的SQL在同一个SqlSession中,相当于:


参考链接
Spring声明式事务为何不回滚

上一篇 下一篇

猜你喜欢

热点阅读