InnoDB存储引擎中使用的锁机制

 

共享锁(s lock):允许事务读一行数据

排他锁(x lock):允许事务删除或者更新一行数据

意向共享锁(is lock):事务想要获得一个表中某几行的共享锁

意向排他锁(ix lock):事务想要获得一个表中某几行的排他锁

意向锁是表级别的锁,是为了在一个事务中揭示下一行将被请求的锁的类型。

自增长锁(autoinc_lock):当表里有一个auto increment字段时,InnoDB会在内存里保存一个计数器来记录auto_increment的值,当插入一个新行数据时,就会用一个表锁来锁住这个计数器,直到插入结束。innodb_autoinc_lock_mode模式有0traditional1consecutive2interleaved

死锁:相互等待对方。

锁升级:将当前锁的粒度降低。

 

事务的隔离级别:READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ,SERIALIZABLE.

 

一致性非锁定读:不需要等待查询行上的X锁释放。与事务隔离级别有关,不同事务隔离级别,读取的方式不同,读取的并不都是一致性读,对于快照的定义也不相同。

是指InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在进行删除,更改操作,这时读取操作不会因此而等待行上的锁释放,相反,InnoDB存储引擎会去读取行的一个快照数据。

 

read committedrepeatable read事务隔离级别下,InnoDB存储引擎使用非锁定的一致性读。

read committed事务隔离级别下,对于快照数据,非一致性读总是读取不被锁定行的最新一份快照数据。

repeatable read事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。

 

REPEATABLE-READ事务隔离级别:(InnoDB默认的事务隔离级别)

Session A

Session B

mysql> start transaction;

mysql> select * from test where id=3;

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

| id | value |

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

|  3 | ccc   |

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

 

 

mysql> start transaction;

mysql> update test set value='333' where id=3; 

mysql> mysql> select * from test where id=3;

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

| id | value |

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

|  3 | ccc   |

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

 

 

mysql> commit;

 

mysql> show variables like "tx_isolation";

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

| Variable_name | Value           |

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

| tx_isolation  | REPEATABLE-READ |

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

 

mysql> select * from test where id=3;

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

| id | value |

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

|  3 | ccc   |

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

 

mysql> commit;

 

结论:对于REPEATABLE-READ事务隔离级别总是读取事务开始时的行数据。

 

READ-COMMITTED事务隔离级别:

Session A

Session B

mysql> set session tx_isolation='READ-COMMITTED';

mysql> show variables like "tx_isolation";

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

| Variable_name | Value          |

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

| tx_isolation  | READ-COMMITTED |

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

mysql> set session tx_isolation='READ-COMMITTED';

mysql> show variables like "tx_isolation";

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

| Variable_name | Value          |

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

| tx_isolation  | READ-COMMITTED |

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

mysql> start transaction;

mysql> select * from test where id = 2;

 

 

mysql> start transaction;

mysql> update test set value='222' where id=2;

mysql> select * from test where id = 2;

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

| id | value |

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

|  2 | bbb   |

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

 

 

 

mysql> commit;

mysql> select * from test where id = 2;

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

| id | value |

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

|  2 | 222   |

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

 

mysql> commit;

 

结论:对于READ-COMMITTED事务隔离级别总是读取行的最新版本,如果行被锁定了,则读取该行版本的最新一个快照。(读取committed后的行数据)不符合事务ACID中的隔离行,一致性(即不可重复读)

 

InnoDB存储引擎中行锁的算法:

1.record lock:单个行记录上的锁(锁定索引记录)

2.gap lock:间隙锁,锁定一个范围,但不包括记录本身

3.next-key lock:以上两种的组合,锁定一个范围并且锁定记录本身

 

Next-key lock算法:

Session A

Session B

mysql> select * from test;

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

| id | value |

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

|  1 | aaa   |

|  2 | 222   |

|  3 | 333   |

|  4 | 444   |

|  8 | 888   |

|  9 | 999   |

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

 

mysql> start transaction;

mysql> select * from test where id <6 lock in share mode;

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

| id | value |

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

|  1 | aaa   |

|  2 | 222   |

|  3 | 333   |

|  4 | 444   |

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

 

 

mysql> start transaction;

mysql> insert into test select 5,555;

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

mysql> insert into test select 8,888;

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

mysql> insert into test select 10,101;

Query OK, 1 row affected

mysql> rollback;

mysql> rollback;

mysql> start transaction;

mysql> select * from test where id = 2 lock in share mode;

 

 

mysql> start transaction;

mysql> update test set value='11111' where id=1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> update test set value='22222' where id=2;    

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

mysql> update test set value='33333' where id=3;     

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> rollback;

mysql> rollback;

结论:在next-key lock算法下,锁定的区间在(-∞,8)。对于单个值的索引查询,使用record lock算法。在REPEATABLE-READ事务隔离级别InnoDB使用next-key lock算法。使用next-key lock算法可以避免不可重复读的现象。

 

 

脏读发生的原因:事务的隔离级别为READ UNCOMMITTED

脏读是指一个事务可以读到另外一个事务中尚未提交的数据。

脏读现象:事务的隔离级别为READ UNCOMMITTED

Session A

Session B

mysql> set session tx_isolation='READ-UNCOMMITTED';

mysql> set session tx_isolation='READ-UNCOMMITTED';

mysql> start transaction;

mysql> select * from test;

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

| id | value |

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

|  1 | aaa   |

|  2 | 222   |

|  3 | 333   |

|  4 | 444   |

|  9 | 999   |

| 10 | 101   |

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

 

 

mysql> insert into test value ('20','202');

mysql> select * from test;

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

| id | value |

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

|  1 | aaa   |

|  2 | 222   |

|  3 | 333   |

|  4 | 444   |

|  9 | 999   |

| 10 | 101   |

| 20 | 202   |

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

 

mysql> rollback;

mysql> rollback;

结论:事务的隔离级别为READ UNCOMMITTED会发生脏读的现象,可以读取到尚未提交的数据。

 

 

查看阻塞语句和等待语句:http://who0168.blog.51cto.com/253401/533990

 

你可能感兴趣的:(InnoDB,事务,锁,sql语句,ACID)