MySQL自增字段并发插入导致死锁
MySQL帶自增字段的表在并發(fā)插入時發(fā)生死鎖
問題
'int' object has no attribute 'encode'", <class 'mysql.connector.errors.InternalError'>, (1213, '1213 (40001): Deadlock found when trying to get lock; try restarting transaction', u'40001'))- 1
tbl_a有一個自增字段id(PRI,auto_increment),在python腳本中通過線程池并發(fā)執(zhí)行insert into語句
insert into tbl_a (name) select name from tbl_b where name = '%s';- 1
發(fā)生死鎖錯誤:
(1213, ‘1213 (40001): Deadlock found when trying to get lock; try restarting transaction’, u’40001’))
原理
AUTO-INC
MySQL對于自增字段有一種鎖機制:AUTO-INC Locking,從MySQL用戶手冊可以看到:
InnoDB uses a special lock called the table-level AUTO-INC lock for inserts into tables with AUTO_INCREMENT columns. This lock is normally held to the end of the statement (not to the end of the transaction), to ensure that auto-increment numbers are assigned in a predictable and repeatable order for a given sequence of INSERT statements- 1
對于自增字段的插入會觸發(fā)表級的AUTO-INC鎖,這個鎖作用于語句的而不是事務(即語句執(zhí)行完了鎖就會被釋放)。使用這種鎖是為了確保自增列的值的可預見性和可重復性。可預見性是說當一條insert語句作用于多行時,這些行的自增列基于第一行來說是可預見的;可重復執(zhí)行是指基于語句的復制在slave重放時自增列的值與master的一致。
帶自增字段的表插入在并發(fā)數大于208以上可能出現很多死鎖
innodb_autoinc_lock_mode
在5.1.22版本之后,MySQL InnoDB存儲引擎提供了一種輕量級互斥量的自增長實現機制,這種機制大大提高了自增長值插入的性能。參數innodb_autoinc_lock_mode,用于控制向有auto_increment 列的表插入數據時相關鎖的行為,實現性能與安全(主從的數據一致性)的平衡。
-
先對自增長字段的插入進行分類,如下:
- insert-like:指所有的插入語句,如insert,replace,insert—select,replace—select,load data等。
- simple insert:指能在插入之前就確定插入行數的語句。這些語句包含insert、replace等,需要注意的是:simple inserts不包含insert—on duplicater key update這類SQL語句,例如insert into t(name) values(‘test’)。
- bulk inserts:指在插入之前不能確定得到插入行數的語句,如insert—select,replace–select,load data。
- mixed-mode inserts:指插入中有一部分的值是自增長的,有一部分是確定的。例如insert into t(id,name) values(1,‘a’),(null,‘b’),(5,‘c’);
-
innodb_autoinc_lock_mode的取值范圍是0, 1, 2,默認值是1:
- 0(traditonal模式):兼容MySQL5.1.22版本之前的自增長實現方式,即通過表鎖的AUTO-INC Locking方式。
- 1(consecutive連續(xù)模式):對于simple inserts,該值會用互斥量去對內存中的計數器進行累加的操作,對于bulk inserts,還是使用傳統(tǒng)表鎖的AUTO-INC Locking方式。在這種配置下,如果不考慮回滾操作,對于自增長列的增長還是連續(xù)的,并且在這種方式下,statement-based方式的replication還是能很好地工作。需要注意的是,如果已經使用AUTO-INC Locking方式去產生自增長的值,而這時需要進行simple inserts的操作時,還是需要等待AUTO-INC Locking的釋放。
- 2(interleaved交錯模式):在這個模式下,對于所有的insert-like自增長的產生都是通過互斥量,而不是通過AUTO-INC Locking的方式,顯然這時性能最高的方式。然而會帶來一定的問題。因為并發(fā)插入的存在,在每次插入時,自增長的值可能不是連續(xù)的。最重要的是,基于Statment-base replication會出現問題。因此,使用這個模式,任何時候都應該使用row-base replication,這樣才能保證最大的并發(fā)性能及replication主從數據的一致。
- innodb_autoinc_lock_mode = 2 不安全,但是在 binlog_format=ROW,transaction-isolation=READ-COMMITTED , innodb_autoinc_lock_mode = 2 是非常安全的。
回顧
查了一下測試環(huán)境MySQL參數,innodb_autoinc_lock_mode果然是1。
mysql> show variables like 'innodb_autoinc_lock_mode'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | innodb_autoinc_lock_mode | 1 | +--------------------------+-------+ 1 row in set (0.00 sec)- 1
- 2
- 3
- 4
- 5
- 6
- 7
不過因為是腳本工具,僅執(zhí)行一次,將并發(fā)量改成10之后問題消失了。根本的解決方法還是將innodb_autoinc_lock_mode設置為2。
參考
http://www.xuchanggang.cn/archives/1087.html
https://blog.csdn.net/poxiaonie/article/details/72899975
https://www.cnblogs.com/JiangLe/p/6362770.html
總結
以上是生活随笔為你收集整理的MySQL自增字段并发插入导致死锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql自增列,并发插入时导致死锁的问
- 下一篇: 东北大米为什么好?