你容易忽視的mysql外鍵鎖和自增鎖

一、外鍵鎖 

一般在插入大量數據的時候要先禁用外鍵(SET foreign_key_checks = 0)。那是爲什麼呢?下面我們對此進行研究:

表結構:

CREATE TABLE `foreign_no1` (
 `id` int(11) NOT NULL DEFAULT '0',
 `no` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`))
CREATE TABLE `foreign_no2` (
 `id` int(11) NOT NULL DEFAULT '0',
 `no` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 CONSTRAINT `foreign_no2_ibfk_2` FOREIGN KEY (`id`) REFERENCES`foreign_no1` (`id`) ON DELETE CASCADE)


數據:

mysql> select * from foreign_no1;
+----+------+
| id | no  |
+----+------+
|  1|    2 |
|  2|    3 |
+----+------+
mysql> select * from foreign_no2;
+----+------+
| id | no  |
+----+------+
|  1|    5 |
+----+------+

Delete 操作

            子表            父表


mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)


 

mysql> delete from foreign_no2 whereid=1;

Query OK, 1 row affected (0.00 sec)




mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from foreign_no1 whereid=1 lock in share mode;  ##父表可以查詢

+----+------+

| id | no  |

+----+------+

|  1|    2 |

+----+------+

1 row in set (0.00 sec)

 

 

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

 

mysql> delete from foreign_no1 whereid=1;    ##父表不允許做更改操作

^CCtrl-C -- sending "KILL QUERY78" to server ...

Ctrl-C -- query aborted.

ERROR 1317 (70100): Query execution wasinterrupted

mysql> rollback

可以看到子表做delete操作,父表可以做select 但不能運行dml語句,因爲子表對父表相關的一行記錄做了讀鎖操作,只允許讀,不能修改,以此來保障父表和子表的數據完整性


                           父表

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

 

mysql> delete from foreign_no1 whereid=2;

Query OK, 1 row affected (0.00 sec)

可以看到父表鎖對應的一行做了讀鎖操作,其餘記錄行依然能更新。


Insert操作

          子表              父表

mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

 

mysql> insert into foreign_no2 values (3,5);

Query OK, 1 row affected (0.00 sec)






mysql> start transaction;

Query OK, 0 rows affected (0.00 sec)

 

mysql> delete from foreign_no1 where id=3;

^CCtrl-C -- sending "KILL QUERY78" to server ...

Ctrl-C -- query aborted.

ERROR 1317 (70100): Query execution wasinterrupted

mysql> update  foreign_no1 set id=8 where id=3;

^CCtrl-C -- sending "KILL QUERY78" to server ...

Ctrl-C -- query aborted.

ERROR 1317 (70100): Query execution wasinterrupted


 可以發現insert 也和delete情況一樣,父表鎖對應的一行做了讀鎖操作。


Update操作


           子表          父表

mysql> start transaction;

mysql> update foreign_no2 set id =3where id=2;

Query OK, 1 row affected (0.02 sec)

Rows matched: 1  Changed: 1 Warnings: 0




mysql> delete from foreign_no1 whereid=3;

^CCtrl-C -- sending "KILL QUERY78" to server ...

Ctrl-C -- query aborted.

ERROR 1317 (70100): Query execution wasinterrupted

mysql> delete from foreign_no1 whereid=2;

ERROR 1205 (HY000): Lock wait timeoutexceeded; try restarting transaction



可以看到被update相關的父表兩條記錄都加了鎖


在對子表進行操作時,外鍵鎖將會在父表中鎖住相應的記錄來保證數據完整性。所以爲了防止在子表更新時對父表數據鎖的現象發生,一般在大量插入數據時會禁用外鍵約束。


二、自增鎖 

insert一般分爲兩種,

第一種:簡單的insert。插入之前知道插入的行數。如:insert ,replace

第二種:塊的insert。插入之前不知道多少插入的行數。如:insert select ,load data

 

簡單insert不會生成auto-inc locking(自增鎖)。那塊的insert 會不會呢?


mysql> show create tableFreedom.key_id_inre;
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                                       |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| key_id_inre | CREATE TABLE `key_id_inre`(
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `no` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1638392DEFAULT CHARSET=utf8 |
+-------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+


        事務一          事務二


 

mysql> insert into Freedom.key_id (id)select id from sanguo_te.players;

 

 


 







mysql> insert into key_id_inre (no)values (100); 

^CCtrl-C -- sending "KILL QUERY78" to server ...

Ctrl-C -- query aborted.

ERROR 1317 (70100): Query execution wasinterrupted

mysql> delete from foreign_no1 whereid=2;

ERROR 1205 (HY000): Lock wait timeoutexceeded; try restarting transaction


                      


auto-inc locking不會等到事務提交後才釋放,而是插入好以後立即釋放。當事務一,開始insert 時,事務二被鎖住,當事務一insert 結束時,事務二insert被解鎖並插入成功。這樣的目的是Mysql通過auto-inc locking來保障塊插入是連續的所以在此期間不能有新記錄插入。如果列中沒有自增量,auto-inc locking鎖自然也不會存在。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章