1、select … from
除了serializable隔离级别,这种SQL都是一致性非锁定读,不加锁;在serializable级别,这种SQL加next-key锁。
2、select … from … lock in share mode
这种SQL加S类型的next-key锁。例如,在会话1上开启事务1,执行如下操作(num列上建有普通二级索引):
mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from lock_test;
+----+-----+------+
| id | num | name |
+----+-----+------+
| 1 | 1 | jdd |
| 2 | 43 | hjh |
| 3 | 6 | ew |
| 4 | 4 | dd |
| 5 | 12 | t |
| 6 | 32 | hu |
| 32 | 45 | gj |
+----+-----+------+
mysql> select * from lock_test where num=12 lock in share mode;
+----+-----+------+
| id | num | name |
+----+-----+------+
| 5 | 12 | t |
+----+-----+------+
会话2上开启事务2,执行如下操作:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into lock_test values(null,8,'hgj');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> insert into lock_test values(null,31,'hgj');
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
插入num=8和31,都发生阻塞,说明事务1执行的语句产生了间隙锁。若再在事务2中执行语句“select * from lock_test where num=12 lock in share mode;”,不会发生阻塞,说明num=12上加的是S锁,所以锁兼容。
3、select … from … for update
这种SQL加X类型的next-key锁。
4、update … where …
RR及其以上隔离级别下,该语句会加next-key锁;在RC级别,只加record锁。
5、delete from … where …
RR及其以上隔离级别下,该语句会加next-key锁;在RC级别,只加record锁。
6、insert … values …
这里指简单的insert(simple insert),即不加ON DUPLICATE KEY UPDATE和select子句的insert语句。这种SQL语句只会在它插入的行上加X锁,而不会加next-key锁。
但是对于唯一列(unique列和主键列),如果多个事务向同一行插入数据,那么第一个事务持有该行的X锁,之后的事务将向这个重复的索引记录行上请求加S锁,并且此时发生锁等待现象。这个时候,还有可能会有死锁发生:
例如假设有个如下结构的innodb表:
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
假设有三个会话依次执行如下操作:
Session 1:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 2:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 3:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 1:
ROLLBACK;
会话1获得i=1数据行上的X锁,之后会话2和会话3的操作因为可能会导致重复键错误,所以它们均请求i=1上的S锁而发生锁等待;当会话1回滚后,i=1数据行上的X锁被释放(或者说没有了i=1的行),此时锁请求队列里的会话2和会话3都可以获得S锁,但此时将产生死锁:由于它们都持有该数据行上的S锁,因此两个会话都获取不到数据行上的X锁。
上面的例子,如果i是unique key,情况也同样适用。
7、insert … on duplicate key update
该SQL与simple insert的不同之处在于,当发生重复键错误时,在要更新的行上设置X类型的next-key锁
8、insert into T select … from S where…
这种SQL在T表被插入的行上加X record lock;在S表上,若事务隔离级别不是SERIALIZABLE,innodb在S表上是一致性非锁定读方式(即不加锁)。如果是在SERIALIZABLE级别,innodb将在S表上加S类型的next-key锁。
9、create table … select …
加锁方式和insert … select方式相同。
10、lock tables
包括lock tables tb_name read/write语句,这种语句加的是表锁(table locks),设置表锁的是innodb层之上的MySQL server层