「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
事务
参考资料:
事务的描述
数据库的ACID特性,用来描述事务的性质:
- A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
- C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
- I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
- D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
在实际的使用中,可以明显感知ACID的4个特性,实质上都是服务于一致性而存在的。
acid中的核心是c,其他基本都是为了保证一致性,而i的各种隔离事务就是在并发性和一致性之间的权衡,越高的隔离性就是越低的并发性,牺牲部分一致性可能是考虑在可接受范围内降低一致性要求
由于数据库的配置以及其他的问题,数据库又有3个数据不一致情况,4个隔离级别:
-
数据不一致情况
- 脏读(Dirty Read)
- 不可重复读(Non Repeatable Read)
- 幻读(Phantom Read)
-
隔离级别:
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Reapeatable Read)
- 串行化(Serializable)
隔离级别和数据不一致情景的对应情况如下:
Isolation Level 脏读(Dirty Read) 不可重复读(Non Repeatable Read) 幻读(Phantom Read) Read Uncommitted Yes Yes Yes Read Committed - Yes Yes Repeatable Read - - Yes Serializable - - -
不常用但与事务相关的概念
事务的传播级别(propagation)
传播级别实际上是在Spring中定义的一些东西,MySQL并没有相关的定义。
数据不一致情况
脏读
A事务执行过程中,B事务读取了A事务的修改。但是由于某些原因,A事务可能没有完成提交,发生RollBack了操作,则B事务所读取的数据就会是不正确的。这个未提交数据就是脏读(Dirty Read)。
-
文字版本的流程:
-
-
A事务修改了数据a改为b,此时B事务读取了该数据的变更后的记录,读取出来结果为b或对应的相关结果。
-
A事务因为某些原因,数据修改后提交失败。
-
B事务并不清楚A事务是否失败了(或不关心),因此最终的呈现结果为:
场景 时间线 认为是结果的数据 A事务 开启事务->修改完成->事务失败->回滚 a->b->a B事务 开启事务->读取数据->.... b DB最终数据 A开启->A修改完毕->B读取数据->A事务失败->A回滚 a->b->a
图示为
-
-
(from yubaolee)
不可重复读
B事务读取了两次数据,在这两次的读取过程中A事务修改了数据,B事务的这两次读取出来的数据不一样。B事务这种读取的结果,即为不可重复读(Nonrepeatable Read)。
(from yubaolee)
幻读
B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样。
这个流程看起来和不可重复读差不多,但幻读强调集合的增减,而不是单独一条数据的修改。
幻读和不可重复读,区别就是:
- 幻读指的是某块数据中的前后读取的结果条数有不一致
- 不可重复读指的是某条数据中的前后读取的记录不一致
(from yubaolee)
其他的东西
事实上,数据库在多任务并发的时候,还有两种不经常被描述的问题:
-
第一类丢失更新
-
第一类更新丢失是指,由于某个事务的回滚操作,参与回滚的旧数据将其他事务的数据更新覆盖了。
-
-
第二类丢失更新
-
第二类数据丢失的问题是关于多个事务同时更新一行数据导致的问题。
-
第一类丢失更新的问题,通过SQL标准(SQL92)以及各个实现的推进已经被消除了。
事实上第二类更新就是不可重复读的一种特殊情况。
(from yubaolee)