跳到主要内容

前言

事务原本是数据库中的一个概念,使用事务主要是想要数据库从某一个一致性状态到达另一个一致性状态,Spring中也对于事务提供了很好的支持

Spring事务的两种方式

在Spring中主要有两种事务,分别是编程式事务声明式事务

  • 编程式事务

对于编程式事务主要是通过硬编码来实现的从而达到事务管理,这样做可以清晰的定义好事务的边界,比如从哪开始,到哪结束

  • 声明式事务

对于声明式事务,最大的优点就是简单,不用像编程式事务那样,我们同样能达到事务的效果,但是我们不能清晰的定义事务的边界

而具体选择哪一种事务,取决于我们我们对于易用性和粒度来进行权衡

编程式事务对于业务控制的粒度更高,我们能精确的定位到事务的边界,事务的开始和结束完全取决于我们的需求,但这种方式对于代码的耦合度过高,不便于维护

声明式事务虽然对于业务控制的粒度更低,但是这种方式对于代码的侵入更小,耦合度更低,便于我们维护

事务的传播行为

事务的传播行为指的是,当应用程序中的服务间互相调用,如果调用方已经创建事务或尚未创建事务,那么被调用的服务将如何处理事务的一种行为方式

Spring提供了七种事务传播特性

  • MANDATORY

表示方法必须运行再一个事务中,如果当前事务不存在,就抛出异常

  • NESTED

表示如果当前事务存在,则方法应该运行再一个嵌套事务当中

  • NEVER

表示方法不能运行在一个事务中,否则抛出异常

  • NOT_SUPPORTED

表示方法不能运行在一个事务中,如果当前存在一个事务,则该方法将被挂起

  • REQUIRED

表示当前方法必须运行在一个事务中,如果当前存在一个事务,那么该方法运行在这个事务中,否则创建一个新的事务

  • REQUIRES_NEW

表示当前方法必须运行在自己的事务中,如果当前存在一个事务,那么这个事务将在该方法运行期间被挂起

  • SUPPORTS

表示当前方法不支持运行在一个事务中,但如果有一个事务存在,那么会将该事务挂起

Spring事务隔离级别

Spring事务的隔离级别和数据库的事务隔离级别相同,Spring提供了五种隔离级别

  • DEFAULT

默认:使用和后端数据库相同的事务隔离级别

  • READ_UNCOMMITTED

读未提交

  • READ_COMMITTED

读已提交

  • REPEATABLE_READ

不可重复读

  • SERIALIZABLE

可串行化

Spring事务失效场景及解决方案

我们在使用Spring事务的时候经常会遇到事务失效,这里我总结一下事务失效的几种场景

  • 事务方法修饰符不是public导致事务失效

我们可以将修饰符改变或者开启代理模式

  • 方法抛出的异常不能被Transactional注解支持的异常,导致失效

使用rollbackfor手动指定异常类型

  • 数据库表本身并不支持事务(例如MyISAM引擎),导致失效

更换支持事务的数据库引擎

  • @Transactional注解方法的类没有被Spring管理导致失效

将该类交给Spring来管理

  • 使用try-catch捕获异常之后没有手动抛出异常导致失效

使用throw手动抛出异常

  • 非事务方法调用自身事务方法导致失效

在非事务方法加上注解,或者自己注入自己通过注入的实例来调用该方法