「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
如果多个事务对缓存页里的同一条数据同时进行增删改查的时候,可能会导致下面的四种问题:脏写、脏读、不可重复度、幻读 事务特性:ACID
- A(Atomicity原子性):全部成功或全部失败
- I(Isolation隔离性):并行事务之间互不干扰
- D(Durability持久性):事务提交后,永久生效
- C(Consistency一致性):通过AID保证
脏写
有两个事务同时更新一条数据,原先值为C,事务A将值跟新为A值,事务B将值更新为B值,想必大家都知道在更新数据之前会先记录undo log日志,这个时候会记录下最先值为C
A,B两个事务同时更新,A事务先将值更新为A,但是事务并没有提交,这时候B事务将值更新为B,事务提交成功,这时候B事务成功,就认为值为B值,但是这时候,A事务需要回滚数据,就将值回滚为回来的值:C,这时候B事务查询数据的时候还是查询到C值,对于B事务来说,明明刚刚更新成功了值,却过一回结果值却没了,这就是脏写,本质就是事务B去修改了事务A未提交的修改值,但是事务A随时会回滚, 导致事务B修改的值被事务A回滚,这就是脏写的定义。
脏读
同样是事务A,B,数据原先值为:C,事务A将值更新为A,但是事务并没有提交,这个时候事务B来查询数据,会查询到未提交的事务A更新的值A,这个时候事务B会用查询到值做后续的逻辑,然而事务A将数据回滚为事务C,就导致事务B读取到的数据为:A,但是A这个值并没有提交成功,当后面事务B又来查询的数据的时候发现数据又为C值,这样前后两次的数据不一致性,导致事务B读取到的数据为脏数据。
事务B查询了事务A未提交的修改值,然而事务A随时会回滚导致事务B再次查询就读不到刚才事务A修改过的数据,这就是脏读。 无论是脏写还是脏读,都是因为一个事务去更新或者查询另外一个还没提交的事务更新过的数据。 因为另外一个事务还没提交,随时可能会回滚数据,那么必然导致更新的数据被另一个事务回滚,或者之前查询到数据就被回滚。
不可重复度
有三个事务,事务A开启,会对一条数据进行多次查询,另外事务B都是对事务A读取的那一条数据进行更新。当事务A第一次读取的时候,读取到的数据为A,如下图所示:
此时事务B更新了那行数据为B,同时B事务提交成功,此时A事务又来查询数据,此时就会查询到B事务提交的数据:B
事务A在读取数据的时候,读取到的都是其他事务提交成功后的值,理论上是可行的,如果希望在事务执行期间,如果多次查询数据,都是同样一个值:C,希望这个值在事务期间重复读取的时候都是可重复读。 这个时候,希望读取的数据是可重复读,但是数据库表现的事不可重复度,那么久会认为数据库有问题,不能够支持事务开启期间多次读取的值为同一个,这就是"不可重复度"的问题。
幻读
事务A,在开启事务执行查询语句,比如执行:select * from user where age <=18;这条语句的时候,第一次查询出来的条数有3条,如下图所示:
在这个时候事务B往表里插入了age<18的两条数据,并且事务B成功提交事务,此时就有5条数据数据,当事务A又查询的时候,就会查询到数据有5条,如下图所示:
事务A在同一个事务中,同一条SQL,两次查到的结果条数不一致,就给人一种幻觉感觉。幻读指的是一个事务用一用的SQL多次查询,结果每次查询都会查询之前没有看到过的数据。
上面的四个问题都是数据库多事务并发问题,为了解决这些多事务问题,MySQL才设计了事务隔离机制,MVCC多版本隔离机制,锁机制等一套机制来解决多事务并发问题。