关于 select for update
作用
for update不仅可以锁行,也可以锁表。
仅适用于InnoDB。通常使用该语句对数据进行手工加锁,避免其他线程对该数据进行修改,造成数据不一致性。
锁的范围
行锁:明确指定Id,且数据存在
select * from customer where id = 1124 for UPDATE
表锁:未指定Id或Id不明确
-- 未指定Id列 SELECT * from customer where name = 1112 for update -- Id不明确 SELECT * from customer where id <> 11 for update
以上可通过变量innodb_row_lock进行观察
模拟表锁
线程A,未指定Id列,会造成表锁
线程B,对id=1的数据加锁,此时因为线程A表锁了,需要等待线程A释放才可以加锁
锁的场景
for update 悲观锁,当前线程在处理时,希望别的线程对当前数据无法进行操作。
线程A
BEGIN; -- 将ID=1的数据锁住 SELECT * FROM work_order WHERE id = 1 FOR UPDATE;
-- 模拟事物未提交 -- COMMIT;
执行结果,对id=1 的数据进行加锁,但是未提交事物,此时别的线程只可读却无法更改
线程B
BEGIN; -- 查询出id=1的数据 SELECT * FROM work_order WHERE id = 1 ; -- 修改id=1的状态为V UPDATE work_order set `status` = 'V' WHERE id = 1 ; COMMIT;
执行结果,可以查询出id=1的数据,修改时会等待线程A释放锁,否则会进行等待
innodb_row_lock
Innodb_row_lock_current_waits : 当前等待的锁的数量
Innodb_row_lock_time:锁的总时长
Innodb_row_lock_time_avg:每次等待锁花时间的平均数
Innodb_row_lock_time_max:最大的一次等待锁花的时间
Innodb_row_lock_waits:一共等待锁的次数