常见的三个事务问题(脏读/幻读/不可重复读)
脏读
脏读(Dirty Read)是指在一个事务中,读取了另一个未提交事务的数据。
具体来说,脏读的过程如下:
1. 事务A开始,对某一行数据进行了修改,但尚未提交。
2. 事务B在事务A未提交之前,读取了事务A修改的数据。
3. 事务A回滚或提交后,事务B读取的数据可能是不一致的或无效的。
脏读问题的出现是因为事务B读取了尚未完成的事务A的数据,而这些数据可能会在事务A回滚或提交之后发生变化。这种情况下,事务B读取到的数据可能是不正确或无效的,导致脏读问题。
为了避免脏读问题,可以使用较高的事务隔离级别,如READ_COMMITTED、REPEATABLE_READ或SERIALIZABLE。这些隔离级别会确保一个事务只能读取另一个已经提交的事务的数据,避免了脏读问题的发生。但是,较高的隔离级别可能会带来并发性能的下降,需要根据实际情况进行权衡和选择。
不可重复读
不可重复读(Non-repeatable Read)是指在一个事务内,多次读取同一行数据,但在事务执行期间,其他事务对该行数据进行了修改,导致多次读取的结果不一致。
具体来说,不可重复读的过程如下:
1. 事务A开始,读取某一行数据的值。
2. 事务B在事务A未提交之前,对同一行数据进行了修改并提交。
3. 事务A再次读取同一行数据,发现其值已经发生了改变,与第一次读取时的结果不一致。
不可重复读问题的出现是因为读取操作没有锁定数据,而其他事务在事务A执行期间修改了该数据。这种情况下,事务A在多次读取同一数据时,得到的结果可能是不一致的。
为了解决不可重复读问题,可以使用较高的事务隔离级别,如REPEATABLE_READ或SERIALIZABLE。这些隔离级别会对读取的数据进行锁定,防止其他事务对其进行修改,从而保证多次读取的结果一致性。但是,高隔离级别可能会带来并发性能的下降,需要根据实际情况进行权衡和选择。
幻读
幻读(Phantom Read)是指在一个事务中,多次执行同一个查询,但在事务执行期间,其他事务插入或删除了符合该查询条件的数据,导致多次查询的结果不一致。
具体来说,幻读的过程如下:
1. 事务A开始,执行一个查询语句,返回一组数据。
2. 事务B在事务A未提交之前,插入或删除了符合事务A查询条件的数据。
3. 事务A再次执行相同的查询语句,发现返回的数据集发生了变化,出现了新的数据或者缺失了原有的数据。
幻读问题的出现是因为事务A在多次执行相同的查询时,发现结果集的数据量或内容发生了变化,产生了幻觉一样的感觉。这种情况下,事务A无法保证多次查询的结果一致性。
为了解决幻读问题,可以使用较高的事务隔离级别,如REPEATABLE_READ或SERIALIZABLE。这些隔离级别会对查询的数据集进行锁定,防止其他事务对其进行插入或删除,从而保证多次查询的结果一致性。但是,较高的隔离级别可能会带来并发性能的下降,需要根据实际情况进行权衡和选择。此外,使用行级锁或乐观锁等技术也可以一定程度上解决幻读问题。
骚戴理解:简单说就是同样的条件, 第1次和第2次读出来的记录数不一样,例如假设下面的事务A第一次读10条数据,然后其中没有骚戴这条数据,但是事务B在事务执行的时候插入了一条“骚戴”的数据,事务A同样的查询条件再去读的时候发现读出11条数据,其中有“骚戴”这条数据,这就是幻读,这种情况的出现必须要多个事务并发执行才会发生
例子2
时间点 | 事务A | 事务B |
1 | 开启事务 | |
2 | 开启事务 | |
3 | 查询数据“骚戴”,不存在 | |
4 | 插入数据“骚戴”,插入成功 | |
5 | 提交事务 | |
6 | 插入数据“骚戴”,插入失败 | |
7 | 查询数据“骚戴”,查询成功 | |
8 | 提交事务 |
骚戴理解:幻读就是事务A查询某条数据的时候不存在,然后在准备添加这条数据的之前又有一个事务B插入了这条数据并提交了事务,所以当事务A添加这条数据添加不成功,因为数据库中已经有了,这就导致事务A查询也查询不到这条数据,添加也添加不了这条数据,最后事务A又查询了一次这条数据,惊奇的发现这条数据最后又的确出现在数据库里,从事务A的角度来看就像出现了幻觉,莫名其妙多了一条数据
不可重复读和幻读的区别
不可重复读和幻读都是数据库事务并发执行时可能出现的问题,但它们的表现和原因略有不同。
- 不可重复读(Non-repeatable Read)是指在一个事务内,多次读取同一行数据,但在事务执行期间,其他事务对该行数据进行了修改,导致多次读取的结果不一致。不可重复读的问题是由于数据的更新导致的,其他事务对数据进行了修改,导致事务内多次读取的结果不一致。
- 幻读(Phantom Read)是指在一个事务内,多次执行同一个查询,但在事务执行期间,其他事务插入或删除了符合该查询条件的数据,导致多次查询的结果不一致。幻读的问题是由于数据的插入或删除导致的,其他事务在事务内插入或删除了符合查询条件的数据,导致事务内多次查询的结果不一致。
总结区别如下:
- 不可重复读是由于数据的更新导致的,其他事务对数据进行了修改,导致事务内多次读取的结果不一致。
- 幻读是由于数据的插入或删除导致的,其他事务在事务内插入或删除了符合查询条件的数据,导致事务内多次查询的结果不一致。
为了解决不可重复读问题,可以使用较高的事务隔离级别,如REPEATABLE_READ或SERIALIZABLE。
为了解决幻读问题,可以使用较高的事务隔离级别或者使用行级锁或乐观锁等技术来避免其他事务对数据的插入或删除。需要根据具体的业务需求和并发性能要求来选择合适的解决方案。