并发事务带来的问题

mysql数据库一般会并发执行多个事务,多个事务就可能并发的对相同的数据进行增加、删除、修改和删除的操作,这就可能导致出现并发事务的问题,会发生以下几个问题:

  • 更新丢失(脏写)
  • 脏读
  • 不可重复读
  • 幻读

更新丢失

对于同一行数据来说,一个事务对该行数据的更新操作覆盖了其他事务对该行数据的更新操作。

本质上是写操作的冲突,解决办法就是让每个事务按照串行的方式执行,按照一定的顺序依次进行写操作。

例如:我们转账的时候,张三的账户余额有100元,当前有两个事务(事务A和事务B),事务A向张三的账户转账100元,事务B向张三的账户转账200元,此时事务A和事务B同时读取到张三的账户余额为100元,事务A和事务B分别更新张三的账户余额。假设事务A先与事务B提交,而事务A和事务B都提交后的结果是账户余额是300元,也就是说后提交的事务B覆盖了事务A的更新操作。

更新丢失本质上就是写操作的冲突,解决办法就是让每个事务都按照串行的方式执行,按照一定的顺序依次进行写操作

脏读

一个事务读取了另一个事务未提交的数据。

例如:当前有两个事务(事务A和事务B),事务A向张三账户转行100元,事务B查询张三的账户余额,事务A执行转账操作,此时事务A还没有提交,事务B查询到张三的账户多了100元,事务A由于某些原因(服务超时、系统异常或者其它因素)进行了回滚操作,此时事务B查询到的数据就是脏数据。

本质上是读写操作的冲突,解决脏读的方法就是先写后读,也就是写完之后再读

不可重复读

同一个事务,使用相同的查询语句,在不同的时刻读取的结果数据不一致。

例如:当前有两个事务(事务A和事务B),事务A向张三的账户转账100元,事务B查询张三的账户余额,第一次查询的时候事务A还没有转账成功,第二次查询的时候事务A已经转账成功,这就会导致事务B两次查询的结果不一致。

本质上是读写操作的冲突,解决办法就是先读后写,也就是读完之后再写。

幻读

一个事务两次读取一个范围的数据记录,两次读取的范围结果不同。

例如:当前有两个事务(事务A和事务B),事务A两次查询张三的转账记录,事务B向张三的账户转账100元,事务A在第一次查询的时候事务B还没有转账,事务A第二次查询的时候事务B已经转账成功,这就会导致事务A两次查询的转账记录不一致。

本质上是读写操作的冲突,解决方法就是先读后写,也就是读完之后再写。

不可重复读和幻读的区别

  • 不可重复读的重点在于更新和删除操作,而幻读的重点在于插入操作。
  • 使用锁机制实现事务隔离级别时,不可重复读与幻读不同。
  • 幻读无法通过行级锁来避免。
  • 不可重复读和幻读最大的区别,就在于如何通过锁机制来解决它们产生的问题

实现事务隔离级别的时候,在可重复读隔离级别中,SQL语句在第一次读取到数据之后,就会将响应的数据加锁,其他事务无法修改这些数据,此时就能实现重复读,而这种方法无法对新插入的数据加锁,比如说一个事务A读取了数据或者修改了数据,另一个事务B还是可以对表进行insert操作,这就会导致事务A莫名其妙多了一条数据,所以幻读的重点在于插入。

幻读无法通过行级锁来避免,需要使用串行化的事务隔离级别,但是这种事务级别会极大的降低数据库的并发能力,所以数据库一般不会使用串行化的事务隔离级别。

posted @ 2022-06-06 18:31  李小菜丶  阅读(612)  评论(0编辑  收藏  举报