Mysql初次select查询生成快照导致重复插入案例

当前有一个场景:

首先查询订单表是否有订单,如果有订单的情况下则查询记录表是否已经插入记录,如果没有则进行插入操作

1、开启事务A,开启事务B

事务A:

begin

事务B:

begin

2、事务A查询order表是否有id为1的订单,事务B也同时查询order表是否为id为1的订单(因为模拟的是并发,所以这里同时进行)

事务A:

select id from order where id = 1

事务B:

select id from order where id = 1

3、事务A和事务B查询到有订单后,同时进行for update查询,此时A事务先执行,B事务被阻塞

事务A:

select id from order where id = 1 for update

事务B:

select id from order where id = 1 for update

4、A事务获取到锁之后查询记录表view,查询无数据,事务B还在阻塞

事务A:

select * from view

5、A事务查询有数据之后插入记录到记录表中,B事务还在阻塞

事务A:

insert into view(val) values(100)

6、A事务执行完毕,提交事务。B事务获得锁,B事务执行完上面第3条的查询sql之后,也进行查询记录表view,但是发现也没有数据

事务B:

select * from view

7、B事务查询view没有数据之后也插入了一条记录到记录表

事务B:

insert into view(val) values(100)

8、最后B事务提交事务,整个过程结束

我们看到这有一个疑问,为什么事务A明明插入了一条记录,为什么事务B查询并没有这条记录,就导致了B事务也插入了一条一模一样的记录?并且B事务是在A事务提交后才进行查询,也没有这条记录,这是为什么呢?

解释:因为事务A和事务B在执行一开始都进行了一次查询(select id from order where id = 1),也就是这时生成了快照,导致后面虽然调了一次含有forupdate刷新了快照,但是刷新的是order表的快照,并没有刷新view表的快照,所以导致为什么事务A已经插入了一条记录并提交了事务,但是事务B却没有查询到记录并重复插入了记录


已发布

分类

,

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注