事务,这次还有不清楚的吗,一次实战坑
以前对事务其实也有一定了解,事务最重要的应该就是。1.事务特性,2.事务的传播行为,3.事务的隔离级别。
但是仅仅是皮毛。。。那些定义而已。从别人的博客直接复制一下吧。哈哈哈,一搜都能搜到的。定义放在后面,前面主要说一下遇到的问题与解决。
问题:
以前在使用事务的时候,一般都是直接在方法上加@Transactional注解,更多的是通过业务设置一下传播行为。
今天业务上需要实现的是,第一个方法不需要事务,在第一个方法内部调用第二个方法,第二个方法需要开启事务。因为两个方法都属于同一service,当时在写的时候,
就感觉,这样会不会有问题,果然,第二个方法事务没有生效。。。
于是就查阅了一下相关资料,第一个方法如果没有受事务管理: 则线程内的connection 的 autoCommit为true。
第二个方法得到事务时事务传播特性依然生效,得到的还是第一个方法使用的connection,但是不会改变autoCommit的属性。所以第二个方法当中是按照每条sql进行提交的。
解决方式:
把两个方法放在两个不同service
参考文章:https://www.cnblogs.com/lukelook/p/11246180.html
最后罗列一下事务的一些定义,方便以后自己看
一. 事务的4种特性
1 原子性(Atomicity) 事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么全部不执行。
2 一致性(Consistemcy) 事务前后,数据库的状态都满足所有的完整性约束。
3 隔离性(Isolation) 并发执行的事务是隔离的,一个不影响一个。通过设置数据库的隔离级别,可以达到不同的隔离效果
4 持久性(Durability) 在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
二 事务的7种传播行为
1 PROPAGATION_REQUIRED ,默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中
执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
2 PROPAGATION_SUPPORTS ,从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事
务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。
这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。
3 PROPAGATION_MANDATORY , 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控
制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况
,就可以使用这个传播级别。
4 PROPAGATION_REQUIRES_NEW ,从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并
且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数
据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回
滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接
影响到父事务的提交和回滚。
5 PROPAGATION_NOT_SUPPORTED ,这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则
挂起事务,执行当前逻辑,结束后恢复上下文的事务。
这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程
中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样
的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用
场了。用当前级别的事务模板抱起来就可以了。
6 PROPAGATION_NEVER ,该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要
求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。
7 PROPAGATION_NESTED ,字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,
如果不存在事务,则新建事务。
三 事务的五种隔离级别
1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
2. 不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
补充 : 基于元数据的 Spring 声明性事务 :
Isolation 属性一共支持五种事务设置,具体介绍如下:
DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
REPEATABLE_READ 会出幻读(锁定所读取的所有行)
SERIALIZABLE 保证所有的情况不会发生(锁表)