一文学习MySQL 意向共享锁、意向排他锁、死锁
基本概念
在MySQL中,锁分为共享锁和排他锁。通过给表或行加锁,可以控制并发访问,保证数据的一致性。但在实际中,使用锁的时候需要考虑多个事务的锁的申请与释放顺序,否则会导致死锁。
MySQL还引入了意向锁的概念。在行级别加锁之前,通过意向锁标记表上接下来需要加的锁类型,以便它能和其他请求的锁协调。在MySQL中,意向锁分为意向共享锁和意向排他锁,它们可以表示事务将要加的锁类型。
意向共享锁和意向排他锁
意向锁标记的是接下来需要加的锁的类型,它并不是真正的锁,而是一种通知。当一段事务想要上锁时,会首先在对象上面请求相应类型的意向锁。
意向锁是一个或多个事务加的锁的通知,以表明它对下一个需要加相应类型的锁有兴趣。因此,在任何时刻只能有唯一一个排他锁,或者同时存在多个共享锁,这些锁都能请求相同的意向锁。
死锁
当发生死锁时,两个或多个事务在等待尚未释放的锁。这些事务不能继续,因此形成了一个循环依赖的状态。这种情况下存在两个或多个事务,每个事务都在等待对方释放锁,而这些事务都不能继续向前推进。
为了避免死锁,应该尽量避免长时间持有锁,尽快释放锁。另外,可以通过规避循环依赖,避免形成死锁。
示例说明
下面通过两个示例来说明意向锁的使用和死锁的产生。
示例一
假设有两个事务T1和T2,T1先进行SELECT操作,请求共享锁并获取,T2接着进行SELECT操作,也请求共享锁,可以发现遵循了意向锁机制。但T1接着进行UPDATE操作,需要改为排他锁,此时会请求意向排他锁,因为此时有意向共享锁存在,所以只能加意向排他锁。T2如果此时也想进行UPDATE操作,会先请求意向排他锁,在检查到意向排他锁存在的情况下,会等待T1事务的排他锁释放。
-- T1
START TRANSACTION;
SELECT * FROM t WHERE id = 1 LOCK IN SHARE MODE;
UPDATE t SET name = 'test' WHERE id = 1;
COMMIT;
-- T2
START TRANSACTION;
SELECT * FROM t WHERE id = 1 LOCK IN SHARE MODE;
-- 排队等待锁
-- T1释放锁后,T2继续执行
UPDATE t SET name = 'test' WHERE id = 1;
COMMIT;
示例二
假设有两个事务T1和T2,在不同的表上进行SELECT和UPDATE操作。在T1事务进行SELECT加共享锁后,T2检查另一个表中没有意向共享锁,于是继续向下执行。但T1事务接着进行UPDATE操作时,需要上排他锁,此时产生了死锁,因为T2事务已经拥有表上行的共享锁,在T1释放行上锁之前,两个事务就会一直等待下去。
-- T1
START TRANSACTION;
SELECT * FROM t1 WHERE id = 1 LOCK IN SHARE MODE;
UPDATE t2 SET name = 'test' WHERE id = 1;
COMMIT;
-- T2
START TRANSACTION;
SELECT * FROM t2 WHERE id = 1 LOCK IN SHARE MODE;
-- 检查到没有意向共享锁
-- 接着向下执行,查询t1
SELECT * FROM t1 WHERE id = 1;
-- 接着上共享锁
SELECT * FROM t1 WHERE id = 2 LOCK IN SHARE MODE;
-- 死锁
在遇到死锁时,MySQL会根据一定的机制自动选择一个事务进行回滚,回到请求的地方重新执行。但一般来说,调整事务的执行顺序还是降低死锁产生的一个可行方法。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文学习MySQL 意向共享锁、意向排他锁、死锁 - Python技术站