MySQL InnoDB存储引擎锁机制实验(二)

2014-11-24 15:49:36 · 作者: · 浏览: 2
w affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
只使用索引更新数据记录
在客户端2执行:
mysql> update test_innodb_lock set b ='xxx' where b=’g’;
只使用非索引字段更新数据记录,客户端2的update语句被阻塞,这是因为客户端2的update语句由于没有使用索引,需要在数据表上加意向排他锁,但在a=4这条记录上,已经存在排他锁了,索引客户端2的update语句只能被阻塞。
以上实验说明:
1、 InnoDB的行级锁在有些情况下是会自动上升为页级锁和表级锁的,此时 数据库的写性能会急剧下降,并可能出现大量的死锁(关于死锁的情况,很容易模仿出来,这里不在举例);
2、 真正的行级锁,只发生在所有的事务都是通过索引来进行检索数据的。
下面我们继续实验与间隙锁相关的情况:
实验六:
在客户端1执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
回滚实验五的操作;
在客户端2执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
回滚实验五的操作;
在客户端1执行:
mysql> update test_innodb_lock set b ='xxx' where a=8;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
通过索引更新数据记录,索引值为8;
在客户端2执行:
mysql> insert into test_innodb_lock(a,b)values(8,'xxx');
向数据表中插入一条数据,插入数据的索引列的值与客户端1的SQL语句的索引值相同,都为8,此时,insert语句被阻塞。
在客户端1执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b ='xxx' where a=8;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
通过索引更新数据记录,索引值为8;
在客户端2执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test_innodb_lock(a,b)values(5,'xxx');
向数据表中插入一条数据,插入数据的索引列的值小于客户端1的SQL语句的索引值,但大于或等于已有数据记录中最大小于检索索引(a=8)的索引值5,此时,insert语句被阻塞。
在客户端1执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b ='xxx' where a=8;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
通过索引更新数据记录,索引值为8;
在客户端2执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test_innodb_lock(a,b)values(9,'xxx');
向数据表中插入一条数据,插入数据的索引列的值大于客户端1的SQL语句的索引值,但小于已有数据记录中最小大于检索索引(a=8)的索引值10,此时,insert语句被阻塞。
在客户端1执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> update test_innodb_lock set b ='xxx' where a=8;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
通过索引更新数据记录,索引值为8;
在客户端2执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test_innodb_lock(a,b)values(10,'xxx');
向数据表中插入一条数据,插入数据的索引列的值大于客户端1的SQL语句的索引值,且大于或等于已有数据记录中最小大于检索索引(a=8)的索引值10,此时,insert语句顺利执行。
以上系列的动作说明,当一个事务在通过索引更新数据时,它会将该索引的前后紧紧相邻的索引记录锁住,包括那些根本就不存在的索引值,锁定的区间为左闭右开区间,即[x,y),其中x为小于事务中SQL语句索引值的最大值,y为大于事务中SQL语句索引值的最小值,在本例中,事务中SQL语句索引值为8,索引其锁定的区间为[5,10),所以另外一个事务在做insert操作时,索引值大于或等于5且小于10的索引记录都将被阻塞。需要注意的是,当更新事务的索引值为已有记录中最大值时,这时所有大于该索引值的记录,其他事务的insert操作都将被阻塞。这就是InnoDB间隙锁的具体表现。所以说,InnoDB的间隙锁避免了部分幻读,但不是全部,因为它锁定的是一个区间,而不是整张表。
实验七:
在客户端1执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
回滚实验六的操作
在客户端2执行:
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
回滚实验六的操作
在客户端1执行:
mysql> update test_innodb_lock set b ='xxx' where b=’a’;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
通过非索引字段更新一条记录;
在客户端2执行:
mysql> insert into test_innodb_lock(a,b)values(10,'xxx');
插入一条完全不相关的数据,该insert语句被阻塞;
说明,当事务1通过非索引字段更新一条数据是,整张表就会被锁住,即使是insert操作,也将被阻塞。
以上实验说明:
1、 InnoDB的间隙锁是可以避免数据出现幻读,但只是避免部分出现幻读,当一个事务是通过索引来更新数据是,另外一个事