如果客户端会话当前持有读锁(允许并发读取,同时已经阻止写入),然后在同一表(S)上获得写锁,MySQL是否保证锁是连续的?
手册指出:
如果会话在已经持有锁的同时发出锁表语句以获取锁,则在授予新锁之前隐式地释放其现有锁。
据我所见,它没有明确规定从读到写“升级”锁。如图所示
mysql> LOCK TABLE `awesome` READ;
mysql> SELECT ... FROM `awesome` ...
mysql> LOCK TABLE `awesome` WRITE; # lock continuous, or dropped+reacquired?
mysql> INSERT INTO `awesome` ...
mysql> UNLOCK TABLES;如果我偏执于文档中的语句,那么我必须假设,在我的会话暂时没有锁的两个锁状态之间会有一个短暂的时刻,在这段时间内,并发会话可能会修改表,从而使它处于与我在SELECT阶段看到的情况不一致的状态。
我不能依赖由重复的密钥冲突引发的异常,因为没有有用的唯一键(如果MySQL甚至支持它,它可能会使表的大小翻两番)。出于同样的原因,事务并不能真正帮助我,但无论如何我都不能使用它们,因为问题中的表格是出于性能原因使用MyISAM引擎的。锁定似乎是我最好的选择,只是文档在转换细节上显得有点显眼。
以及如果表集相同,MySQL如何在内部处理从读锁到写锁的转换?
大木锤的方法当然是在前面发出一个单一的写锁。但很明显,这会迫使所有人都选择等待。OTOH,据我所知,无限数量的会话可以同时读取-锁定同一个表(隐式或显式),而对select性能没有任何影响。读锁所做的唯一一件事就是防止更新击中表,这正是我在第一阶段所需要的。
发布于 2014-05-19 10:20:54
实际上,你所引用的手册中的部分就是这样说的:
-- Connection #1
LOCK TABLE mytable READ; -- lock is acquired
-- Connection #2
LOCK TABLE mytable WRITE; -- execution is suspended, lock is NOT acquired
-- Connection #1
LOCK TABLE mytable WRITE; -- execution is suspended
-- READ lock was released, allowing Connection #2 to acquire the WRITE lock
-- Connection #2 resumes解决方案:切换到InnoDB并使用事务。InnoDB引擎在最近的版本中做了很多改进的性能。
-- Connection #1
BEGIN;
SELECT * FROM mytable LOCK IN SHARE MODE; -- lock is acquired
-- Connection #2
BEGIN;
SELECT * FROM mytable FOR UPDATE; -- execution is suspended, lock is NOT acquired
-- Connection #1
SELECT * FROM mytable FOR UPDATE;
-- deadlock is detected, Connection #2 is rolled backhttps://dba.stackexchange.com/questions/63739
复制相似问题