MySQL在事务中使用SELECT ... FOR UPDATE

在数据库的操作中,经常发生数据并发更新的情况,这时可以使用SELECT … FOR UPDATE语句对数据加锁保证数据更新的正常执行。

下图所示为一张学生成绩表,现在开启两个终端会话模拟数据的并发操作。(开启终端会话可以使用MySQL Shell,安装和使用方法详见另一篇博文如何使用MySQL Shell连接数据库

学生成绩表

先开启第一个会话,依次执行以下语句将id为3的记录中数学成绩加10:

start transaction;

select * from test where id = 3 for update;

update test set math = math + 10 where id = 3;

select * from test where id = 3;

更新数学成绩

此时,成绩由59变成69,但由于未执行commit,成绩修改未生效。打开第2个会话,执行

select * from test;

查到成绩依然为59。

成绩未修改

在会话2中继续执行以下语句:

start transaction;

select * from test where id = 3 for update;

会话2由于会话1锁定了id为3的行导致阻塞。

阻塞

此时在会话1中执行commit,会话2语句将不再阻塞并查到修改后的成绩69。

会话2结果

但有趣的是,如果在会话2中执行不带FOR UPDATE的语句,查询的结果仍然是59。而使用带FOR UPDATE的语句查询的结果为69。

select * from test where id = 3;

select * from test where id = 3 for update;

不同的查询结果

另外,当SELECT … FOR UPDATE语句中的WHERE条件使用了主键时将只锁定查询到的行。重新打开会话1,依次执行以下语句:

start transaction;

select * from test where id = 4 for update;

select * from test where id = 3 for update;

行锁定

可以看到,尽管会话2锁定了id为3的行,但会话1仍然可以锁定其他行。

当SELECT … FOR UPDATE语句中的WHERE条件同时使用了主键和其他字段时也将只锁定查询到的行,在会话1中执行以下语句锁定id为3的行。

start transaction;

select * from test where id = 3 and student_id <> 2 for update;

会话2再次锁定id为3的记录时阻塞。

会话2阻塞

当SELECT … FOR UPDATE语句中的WHERE条件同时使用了主键和其他字段但查询到的记录为空时也将锁定主键对应的行,在会话1中执行以下语句将锁定id为3的行。

start transaction;

select * from test where id = 3 and student_id <> 3 for update;

尽管会话1查询的记录为空,但依然锁定了id为3的记录,会话2再次锁定时阻塞。

会话2阻塞

当SELECT … FOR UPDATE语句中的WHERE条件不使用主键时将锁定整个表。将会话1与会话2全部commit后,在会话1中执行:

start transaction;

select * from test where student_id = 1 for update;

锁表

会话2中再执行行锁定阻塞。

start transaction;

select * from test where student_id = 2 for update;

无法锁定

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值