Java提升篇-事务隔离级别和传播机制
问题的提出
为了保证并发操作数据的正确性及一致性,SQL规范于1992年提出了数据库事务隔离级别。
事务隔离级别分类
事务隔离级别由低往高可分为以下几类
READ UNCOMMITTED,读取未提交的数据。
这是最不安全的一种级别,查询语句在无锁的情况下运行,并能读取到别的未提交的数据,造成脏读,如果未提交的那个事务数据全部回滚了,而之前读取了这个事务的数据即是脏数据,这种数据不一致性读造成的危害是可想而知的。
READ COMMITTED,读取已提交的数据。
一个事务只能读取数据库中已经提交过的数据,解决了脏读问题,但不能重复读,即一个事务内的两次查询返回的数据是不一样的。如第一次查询金额是100,第二次去查询可能就是50了,这就是不可重复读取。
REPEATABLE READ,可重复读取数据,这也是Mysql默认的隔离级别。
一个事务内的两次无锁查询返回的数据都是一样的,但别的事务的新增数据也能读取到。比如另一个事务插入了一条数据并提交,这个事务第二次去读取的时候发现多了一条之前查询数据列表里面不存在的数据,这时候就是传说的中幻读了。这个级别避免了不可重复读取,但不能避免幻读的问题。
SERIALIZABLE,可串行化读。
这是效率最低最耗费资源的一个事务级别,和可重复读类似,但在自动提交模式关闭情况下可串行化读会给每个查询加上共享锁和排他锁,意味着所有的读操作之间不阻塞,但读操作会阻塞别的事务的写操作,写操作也阻塞读操作。
上面介绍了4种事务隔离级别及脏读、不可重复读、幻读与它们的联系,对应的关系表如下:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读取未提交 | √ | √ | √ |
读取已提交 | × | √ | √ |
可重复读 | × | × | √ |
可串行化读 | × | × | × |
Mysql官方对于事务级别的定义可参考:
https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html
扩展
上面介绍的是Mysql的事务隔离级别,那跟spring中的事务隔离级别有什么必然的联系呢?
spring就是对数据库事务进行了封装而已,并提了5种事务隔离级别和7种事务传播机制。
5种事务隔离级别
ISOLATION_DEFAULT
spring将使用数据库中默认的事务隔离级别。
下面四种定义和上面一致。
ISOLATION_READ_UNCOMMITTED 4 p" L. I' F; k1 {) a. D( E5 ?: V
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
7种事务传播机制
REQUIRED
如果当前方法有事务则加入事务,没有则创建一个事务。
NOT_SUPPORTED
不支持事务,如果当前有事务则挂起事务运行。
REQUIREDS_NEW
新建一个事务并在这个事务中运行,如果当前存在事务就把当前事务挂起。新建的事务的提交与回滚一挂起事务没有联系,不会影响挂起事务的操作。
MANDATORY
强制当前方法使用事务运行,如果当前没有事务则抛出异常。
NEVER
当前方法不能存在事务,即非事务状态运行,如果存在事务则抛出异常。
SUPPORTS
支持当前事务,如果当前没事务也支持非事务状态运行。
NESTED
如果当前存在事务,则在嵌套事务内执行。嵌套事务的提交与回滚与父事务没有任务关系,反之,当父事务提交嵌套事务也一起提交,父事务回滚会也回滚嵌套事务的。
如果当前没有事务,则新建一个事务运行,这时候则与PROPAGATION_REQUIRED场景一致。