2023-03-23
原文作者:一直不懂 原文地址:https://blog.csdn.net/shenchaohao12321/article/details/82798275

外键主要用于引用完整性的约束检查。在 InnoDB存储引擎中,对于一个外键列,如果没有显式地对这个列加索引, InnoDB存储引擎自动对其加一个索引,因为这样可以避免表锁——这比 Oracle数据库做得好, Oracle数据库不会自动添加索引,用户必须自已手动添加,这也导致了 Oracle数据库中可能产生死锁。

对于外键值的插入或更新,首先需要查询父表中的记录,即 SELECT父表。但是对于父表的 SELECT操作,不是使用一致性非锁定读的方式,因为这样会发生数据不一致的问题,因此这时使用的是 SELECT… LOCK IN SHARE MODE方式,即主动对父表加一个S锁。如果这时父表上已经这样加X锁,子表上的操作会被阻塞,如下表所示。

时间 会话A 会话B
时间 会话A 会话B
1 BEGIN  
2 DELETEFROMparentWHEREid=3;  
3   BEGIN
4   INSERTINTOchildSELECT2,3;#第二列是外键,执行该句时被阻塞(waiting)

在上述的例子中,两个会话中的事务都没有进行COMMIT或ROLLBAGK操作,而会话B的操作会被阻塞。这是因为id为3的父表在会话A中已经加了一个X锁,而此时在会话B中用户又需要对父表中id为3的行加一个S锁,这时INSERT的操作会被阻塞。设想如果访问父表时,使用的是一致性的非锁定读,这时 Session B会读到父表有id=3的记录,可以进行插入操作。但是如果会话A对事务提交了,则父表中就不存在id为3的记录。数据在父、子表就会存在不一致的情况。若这时用户查询INNODB_LOCKS表,会看到如下结果:

202303232333111921.png

阅读全文