spring 声明式事务,底层使用Aop来实现,是一个应用aop逻辑处理比较好的实现。
在方法层次增加@Transactional注解,里面有属性 propagation(传播)有七种传播类型
propagation_required 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
propagation_supports 支持当前事务,如果当前没有事务,就以非事务方式执行。
propagation_mandatory 使用当前的事务,如果当前没有事务,就抛出异常。
propagation_requires_new 新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation_never 以非事务方式执行,如果当前存在事务,则抛出异常。
propagation_nested 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。
1.serviceA调用了serviceB中的方法。两个都是用的是默认的事务处理required,如果在A中捕获了B中的异常,那么会出现异常,因为B中出现异常需要回滚,A中捕获的异常,需要提交,因为处于同一个事务中,所以会出错。如果不出错的话B中事务需要设置requires_new属性,重新创建一个单独的事务。实际业务中要保证事务的完整性
required 如果当前没有事务,就会创建一个新的事务,如果已经存在,就加入事务中;
supports 支持当前事务,如果当前没有事务,就以没有事务的方式处理;
mandatory 使用当前事务,如果当前没有事务,就抛出异常;
requires_new 新建事务,如果当前存在事务,将将当前事务挂起,从新创建一个事务,是独立的事务,原来挂起的事务照常执行,不会再去影响子事务;
not_supported 已非事务的方式操作,如果存在当前事务,就将当前事务挂起,当前操作不包含事务,被挂起的事务正常执行;
-->B抛出异常,B正常提交,A未捕获异常,将会回滚;
never 已非事务的方式处理,如果存在事务将抛出异常;
-->B中声明了事务never,A中声明事务,B中抛出异常;
nested 如果当前存在事务,则在嵌套事务中执行,如果当前没有事务,则会创建事务;
-->B中声明 nested,A中没有声明事务,B中将是事务控制,A中无事务;
测试代码地址 https://gitee.com/daileideyu/spring-transactional.git
二、readOnly读写事务控制
readOnly=true表明所注解的方法或类只是读取数据。readOnly=false表明所注解的方法或类是增加,删除,修改数据;
三、isolation事务隔离级别
来源:为什么要有事务隔离级别?
我们在使用事务过程中,通常会发生以下三种情况:
1.脏读(dirty read):在一个事务在读取到另一个事务,未提交的修改的数据,产生脏读;
2.不可重复读(non-repeatable read):同一查询在同一个事务中多次进行,由于其他事务所做的删除或者修改,导致每次查询返回的数据结果集不一致;
3.幻像读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻像读;
针对上述三种情况,Spring提供了5种事务隔离级别予以解决;
1.DEFAULT默认级别 DEFAULT为数据源(数据库)的默认隔离级别,以目前常用的MySQL为例,默认的隔离级别通常为REPEATABLE_READ;
2.read_uncommitted未授权读取级别 这是最低的隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;
3.READ_COMMITTED授权读取级别
以操作同一行数据为前提,读事务允许其他读事务和写事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读,但不能防止不可重复读、幻读。此隔离级别可以通过“瞬间共享读锁”和“排他写锁”实现;
4.repeatable_read 可重复读取级别
保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响。以操作同一行数据为前提,读事务禁止其他写事务,但允许其他读事务,未提交的写事务禁止其他读事务和写事务。此隔离级别可以防止更新丢失、脏读、不可重复读,但不能防止幻读。
5.serializable 序列化级别
所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。提供严格的事务隔离,此隔离级别可以防止更新丢失、脏读、不可重复读、幻读。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到;
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免更新丢失、脏读,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制;
参考:https://www.jianshu.com/p/71d1409ee180 |