|
摘自官网的这段,大概可以明白next-key-locking算法的思想。
innodb_locks_unsafe_for_binlog
这个选项在InnoDB搜索和索引扫描中关闭下一键锁定。这个选项的默认值是假(false)。
正常地,InnoDB使用一个被称为next-key locking的算法。当搜索或扫描一个表索引之时,InnoDB以这样一种方式实行行级锁定,它对任何遇到的索引记录设置共享的或独占的锁定。因此,行级锁定实际是索引记录锁定。InnoDB对索引记录设置的锁定也影响被锁定索引记录之前的“gap”。如果一个用户对某一索引内的记录R又共享的或独占的锁定,另一个用户不能立即在R之前以索引的顺序插入一个新的索引记录。这个选项导致InnoDB不在搜索或索引扫描中使用下一键锁定。下一键锁定仍然被用来确保外键强制及重复键核查。注意,使用这个选项可能会导致一些诡异的问题:假设你想要用值大于100的标识符从子表里读取并锁定所有的子记录,同时向随后在选定的行更新一些列:
SELECT * FROM child WHERE id > 100 FOR UPDATE;
假设在id列有一个索引。查询从id大于100的第一个记录开始扫描索引。如果在索引记录上的锁定不把在间隙处生成的插入排除锁定,同时一个新行被插进表中。如果你在同一个事务之内执行同样的SELECT,你会在查询返回的结果包里看到一个新行。这也意味着,如果新条目被加进数据库,InnoDB不保证连续性;尽管如此,对应连续性仍被保证。因此,如果这个选项被使用,InnoDB在大多数孤立级别保证READ COMMITTED。 (对这句话我不是很理解)
这个选项甚至更不安全。InnoDB在一个UPDATE或DELETE中只锁定它更新或删除的行。这大大减少了死锁的可能性,但是可以发生死锁。注意,即使在当类似的操作影响不同行时的情况下,这个选项仍然不允许诸如UPDATE这样的操作压倒相似选项(比如另一个UPDATE)。考虑下列例子:
CREATE TABLE A(A INT NOT NULL, B INT);
INSERT INTO A VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
如果一个连接执行一个查询:
SET AUTOCOMMIT = 0;
UPDATE A SET B = 5 WHERE B = 3;
并且其它连接跟着第一个连接执行其它查询:
SET AUTOCOMMIT = 0;
UPDATE A SET B = 4 WHERE B = 2;
下面的解释应该可以比较清晰的明白这个算法的思想,但是(我经过测试,并没有hung住)
接着查询2要等查询1的提交或回滚,因为查询1对行(2,3)有一个独占的锁定,并且查询2在扫描行的同时也试着对它不能锁定的同一个行(2,3)采取一个独占的锁定。这是因为当innodb_locks_unsafe_for_binlog选项被使用之时,查询2首先对一个行采取一个独占的锁定,然后确定是否这个行属于结果包,并且如果不属于,就释放不必要的锁定。
因此,查询1按如下执行:
x-lock(1,2)
unlock(1,2)
x-lock(2,3)
update(2,3) to (2,5)
x-lock(3,2)
unlock(3,2)
x-lock(4,3)
update(4,3) to (4,5)
x-lock(5,2)
unlock(5,2)
并且查询2按如下执行:
x-lock(1,2)
update(1,2) to (1,4)
x-lock(2,3) - 等待查询1提交或回滚
[ 本帖最后由 fan_zhen_hua 于 2010-8-29 00:45 编辑 ] |
|