共享锁与排他锁
共享锁与排他锁
从锁的策略上来看,
- 共享锁(S
) :共享锁允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁; - 排他锁(X):排他锁则允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
SELECT ... LOCK IN SHARE MODE; -- 共享锁
SELECT ... FOR UPDATE; -- 排他锁
另外,为了允许行锁和表锁共存,实现多粒度锁机制,
- 意向共享锁(IS
) :事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS 锁。 - 意向排他锁(IX
) :事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX 锁。
mysql> set autocommit = 0;
/* 共享锁 */
-- 当前 session 对 actor_id=178 的记录加 share mode 的共享锁:
mysql> select actor_id,first_name,last_name from actor where actor_id = 178 lock in share mode;
-- 当前session对锁定的记录进行更新操作,等待锁:
mysql> update actor set last_name = 'MONROE T' where actor_id = 178;
-- 其他session仍然可以查询记录,并也可以对该记录加share mode的共享锁:
mysql> select actor_id,first_name,last_name from actor where actor_id = 178lock in share mode;
-- 其他session也对该记录进行更新操作,则会导致死锁退出:
mysql> update actor set last_name = 'MONROE T' where actor_id = 178;
-- ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
-- 获得锁后,可以成功更新:
-- Query OK, 1 row affected (17.67 sec)
/* 排他锁 */
-- 当前session对actor_id=178的记录加for update的排它锁:
mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;
-- 其他session可以查询该记录,但是不能对该记录加共享锁,会等待获得锁:
mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;
-- 当前session可以对锁定的记录进行更新操作,更新后释放锁:
mysql> update actor set last_name = 'MONROE T' where actor_id = 178;
mysql> commit;
-- 其他session获得锁,得到其他session提交的记录:
mysql> select actor_id,first_name,last_name from actor where actor_id = 178 for update;
值得一提的是,普通的查询操作都是非锁定读,会基于
而加锁之后就变成了锁定读,所有的锁定读都是当前读,也就是读取当前记录的最新版本,不会利用