最近来尝试总结一下关于事务这块的知识,深化一下自己的理解(若有不当或者缺乏,万望告知)
Spring事务:
1.Spring管理事务的方式有几种?
编程式事务:在代码中硬编码(在分布式系统中推荐使用) : 通过 TransactionTemplate
或者 TransactionManager
手动管理事务,事务范围过大会出现事务未提交导致超时,因此事务要比锁的粒度更小。
声明式事务:在 XML 配置文件中配置或者直接基于注解(单体应用或者简单业务系统推荐使用) : 实际是通过 AOP 实现(基于@Transactional
的全注解方式使用最多)
2.Spring事务中有哪几种传播事务的方式?
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务传播行为可能的值如下:(常用的几种)
1.TransactionDefinition.PROPAGATION_REQUIRED
使用的最多的一个事务传播行为,我们平时经常使用的@Transactional
注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
2.TransactionDefinition.PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW
修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
3.TransactionDefinition.PROPAGATION_NESTED
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
。
3.Spring事务中的隔离级别有哪些?
和事务传播行为这块一样,为了方便使用,Spring 也相应地定义了一个枚举类:Isolation
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 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别
4.@Transactional(rollbackFor=Exception.class)注解了解吗?
Exception
分为运行时异常 RuntimeException
和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
当 @Transactional
注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
@Transactional
注解默认回滚策略是只有在遇到RuntimeException
(运行时异常) 或者 Error
时才会回滚事务,而不会回滚 Checked Exception
(受检查异常)。这是因为 Spring 认为RuntimeException
和 Error 是不可预期的错误,而受检异常是可预期的错误,可以通过业务逻辑来处理。
5.Spring中的事务是如何实现的?
1.Spring事务的基层是基于数据库事务和AOP机制的
2.首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean
3.当调用了代理对象的方法时,会先判断该方法上是否加了@Transactional注解
4.如果加了,那么则利用事务管理器创建一个数据库连接
5.并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步。
6.然后执行当前方法,方法会执行sql
7.执行完方法后,如果没有出现异常处理就直接提交事务
8.如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然是提交事务。
9.Spring事务的隔离级别对应的就是数据库的隔离级别
10.Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的
11.Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开一个事务,那么实际上就是先建立一个数据库连接,在此数据库连接上执行sql
除了可能遇到的问题之外,还有事务的实际操作:
Spring事务之实际情况版:
什么是事务?
事务是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败
事务操作:
1.开启事务(一组操作开始之前,开启事务),start transaction / begin;
2.提交事务(这组操作全部成功之后,提交事务):commit
3.回滚事务(中间任何一个操作出现异常,就回滚事务):rollback
以解散部门为例子,删除部门的同时还要删除部门下的员工,因此,需要进行两次的持久层操作,如果其中出现了不可预料的错误,那么就会导致删除了部门却没有删除员工,这样就会出现问题
开启Spring事务管理:
注解: @Transactional
位置: 业务(service)层的方法上,类上,接口上
作用: 将当前去方法交给Spring进行事务管理,方法执行之前,开启事务;执行完成之后提交事务,出现异常就回滚事务。
注:可以在配置文件中开启事务管理日志。
#开启事务管理日志
logging:
level:
org.springframework.jdbc.support.ldbcTransactionManager:debug
事务进阶;
rollbackFor(异常回滚属性):
默认情况下,只有出现RuntimeException才会回滚异常,rollbackFor属性用于控制出现任意异常类型,回滚事务。(这种情况主要是发生在,比如在两个操作数据库中间,throw了一个异常,因为不是RuntimeException,因此会导致事务回滚失败,导致错误)
添加属性即可:
@Transactional(rollbackFor = Exception.class)
propagation(事务传播行为)
事务传播行为:指的是当一个事务方法被另一个事务方法调用的时候,这个事务方法应该如何进行事务控制。
@Transactional(propagation = Propagation.REQUIRED)