为什么你的insert就死锁了
一、前言
本以为只需要系统学习一个较完全的逻辑,但是实际牵扯很多innodb锁相关知识及加锁方式。我好像并没有那么大的能耐,把各种场景的加锁过程一一列举并加之分析;亦没有太多的精力验证网上的言论的准确性。
只好根据现在了解的内容,参考官方文档,说说自己当前的理解。本文仅供参考,如有误导,概不负责。
二、现场状态
不同的mysql版本,不同的参数设置,都可能对加锁过程有影响。分析加锁机制还是应当尽可能多地列举一下关键参数,例如:当前mysql版本、事务隔离级别等。如下,仅仅只列出个别比较重要的参数。
1.数据库版本
``mysql> select version();
+-----------+
| version() |
+-----------+
| 5.6.27 |
+-----------+
复制代码
2. 数据库引擎
``mysql> show variables like '%engine%';
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| default_storage_engine | InnoDB |
| default_tmp_storage_engine | InnoDB |
| storage_engine | InnoDB |
+----------------------------+--------+
复制代码
注:InnoDB支持事务,Myisam不支持事务;InnoDB支持行锁和表锁;Myisam不支持行锁。
3. 事务隔离级别
``mysql> select @@global.tx_isolation, @@session.tx_isolation, @@tx_isolation;
+-----------------------+------------------------+-----------------+
| @@global.tx_isolation | @@session.tx_isolation | @@tx_isolation |
+-----------------------+------------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+------------------------+-----------------+
复制代码
注:几种事务隔离级别:READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE
4. 查看gap锁开启状态
``mysql> show variables like 'innodb_locks_unsafe_for_binlog';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_locks_unsafe_for_binlog | OFF |
+--------------------------------+-------+
复制代码
innodb_locks_unsafe_for_binlog:默认值为0,即启用gap lock。最主要的作用就是控制innodb是否对gap加锁。但是,这一设置变更并不影响外键和唯一索引(含主键)对gap进行加锁的需要。开启innodb_locks_unsafe_for_binlog的REPEATABLE-READ事务隔离级别,很大程度上已经蜕变成了READ-COMMITTED。
参见官方文档1:By default, the value of innodb_locks_unsafe_for_binlog is 0 (disabled), which means that gap locking is enabled: InnoDB uses next-key locks for searches and index scans. To enable the variable, set it to 1. This causes gap locking to be disabled: InnoDB uses only index-record locks for searches and index scans.
Enabling innodb_locks_unsafe_for_binlog does not disable the use of gap locking for foreign-key constraint checking or duplicate-key checking.
The effect of enabling innodb_locks_unsafe_for_binlog is similar to but not identical to setting the transaction isolation level to READ COMMITTED.
5. 查看自增锁模式
``mysql> show variables like 'innodb_autoinc_lock_mode';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 1 |
+--------------------------+-------+
复制代码
innodb_autoinc_lock_mode有3种配置模式:0、1、2,分别对应”传统模式”, “连续模式”, “交错模式”。
传统模式:涉及auto-increment列的插入语句加的表级AUTO-INC锁,只有插入执行结束后才会释放锁。这是一种兼容MySQL 5.1之前版本的策略。
连续模式:可以事先确定插入行数的语句(包括单行和多行插入),分配连续的确定的auto-increment值;对于插入行数不确定的插入语句,仍加表锁。这种模式下,事务回滚,auto-increment值不会回滚,换句话说,自增列内容会不连续。
交错模式:同一时刻多条SQL语句产生交错的auto-increment值。
由于insert语句常常涉及自增列的加锁过程,会涉及到AUTO-INC Locks加锁过程。为了分步了解insert加锁过程,本文暂不讨论任何涉及自增列的加锁逻辑。这一参数设置相关内容可能会出现在我的下一篇文章里。
三、InnoDB锁类型2
1. 基本锁
基本锁:共享锁(Shared Locks:S锁)与排他锁(Exclusive Locks:X锁)
mysql允许拿到S锁的事务读一行,允许拿到X锁的事务更新或删除一行。
加了S锁的记录,允许其他事务再加S锁,不允许其他事务再加X锁;
加了X锁的记录,不允许其他事务再加S锁或者X锁。
mysql对外提供加这两种锁的语法如下:
加S锁:selec