时间:2021-07-01 10:21:17 帮助过:12人阅读
Innodb存储引擎实现了例如以下2种标准的行级锁:
?
共享锁(S lock),同意事务读取一行数据。
? 排它锁(X lock)。同意事务删除或者更新一行数据。
当一个事务获取了行r的共享锁。那么另外一个事务也能够马上获取行r的共享锁,由于读取并未改变行r的数据。这样的情况就是锁兼容。
可是假设有事务想获得行r的排它锁,则它必须等待事务释放行r上的共享锁—这样的情况就是锁不兼容。二者兼容性例如以下表格所看到的:
排它锁和共享锁的兼容性 | ||
| X 排它锁 | S 共享锁 |
X 排它锁 | 冲突 | 冲突 |
S 共享锁 | 冲突 | 兼容 |
2。锁的扩展
Innodb存储引擎支持多粒度锁定,这样的锁定同意在行级别上的锁和表级别上的锁同一时候存在。为了支持在不同粒度上进行加锁操作。InnoDB存储引擎支持一种额外的锁方式,就是意向锁。
意向锁是表级别的锁。其设计目的主要是为了在一个事务中揭示下一行将被请求的锁的类型。它也分为两种:
? 意向共享锁(IS Lock),事务想要获得一个表中某几行的共享锁。
? 意向排它锁(IX Lock),事务想要获得一个表中某几行的排它锁。
由于InnoDB支持的是行级别锁,所以意向锁事实上不大会堵塞除了全表scan下面的不论什么请求。共享锁、排它锁、意向共享锁、意向排它锁相互之前都是有兼容/相互排斥关系的。能够用一个兼容性矩阵表示(y表示兼容,n表示不兼容)。例如以下所看到的:
| X 排它锁 | S 共享锁 | IX 意向排它锁 | IS 意向共享锁 |
X 排它锁 | 冲突 | 冲突 | 冲突 | 冲突 |
S 共享锁 | 冲突 | 兼容 | 冲突 | 兼容 |
IX 意向排它锁 | 冲突 | 冲突 | 兼容 | 兼容 |
IS 意向共享锁 | 冲突 | 兼容 | 兼容 | 兼容 |
解析:X和S的相互兼容关系step1描写叙述过了,IX和IS的相互关系全部是兼容,这也非常好理解,由于它们都仅仅是“有意”。还处于YY阶段,没有真干,所以是能够兼容的;
剩下的就是X和IX。X和IS, S和IX, S和IS的关系了,我们能够由X和S的关系推导出这四组关系。
简单的说:X和IX的=X和X的关系。为什么呢?由于事务在获取IX锁后。接下来就有权利获取X锁。假设X和IX兼容的话,就会出现两个事务都获取了X锁的情况。这与我们已知的X与X相互排斥是矛盾的,所以X与IX仅仅能是相互排斥关系。其余的三组关系同理。可用同样的方式推导出来。
3。模拟锁场景
在InnoDB Plugin之前。我们仅仅能通过SHOW FULL PROCESSLIS和SHOW ENGINE INNODB STATUS来查看当前的数据库请求,然后再推断事务中锁的情况。新版本号的InnoDB Plugin中,在information_schema库中加入了3张表,INNODB_LOCKS、INNODB_TRX、INNODB_LOCK_WAITS。通过这3个表,能够更简单的监控当前的事务而且分析可能存在的锁问题。
假设数据库正常运行,这3个表都是空的,没有不论什么记录。
3.1,开启事务t1、t2,模拟锁
开启2个session窗体,而且开启2个事务t1和t2。
在第一个窗体开启事务t1运行一个锁定操作,例如以下t1事务窗体界面:
mysql> set autocommit =0;
Query OK, 0 rows affected (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
開始运行锁定操作
mysql> select * from test.t1 where a<5 for update;
+---+----+----+
| a | b | c |
+---+----+----+
| 1 | c2 | c2 |
| 2 | a | |
| 3 | r5 | r3 |
| 4 | r4 | r5 |
+---+----+----+
4 rows in set (0.00 sec)
mysql>
这个时候,事务t1已经锁定了表t1的全部a<5的数据行,然后去第二个窗体开启第二个事务t2,例如以下,会看到update语句一直在等待事务t1释放锁资源,过了几秒后,会有报错信息,例如以下t2事务窗体界面:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update test.t1 set b=‘t2‘ where a=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>
3.2,通过3个系统表来查看锁信息
l 1,INNODB_TRX表
先看下表的重要字段以及记录的信息
a) trx_id:innodb存储引擎内部事务唯一的事务id。
b) trx_state:当前事务的状态。
c) trx_started:事务開始的时间。
d) trx_requested_lock_id:等待事务的锁id。如trx_state的状态为LOCK WAIT。那么该值代表当前事务之前占用锁资源的id,假设trx_state不是LOCK WAIT的话,这个值为null。
e) trx_wait_started:事务等待開始的时间。
f) trx_weight:事务的权重,反映了一个事务改动和锁住的行数。
在innodb的存储引擎中。当发生死锁须要回滚时。innodb存储引擎会选择该值最小的事务进行回滚。
g) trx_mysql_thread_id:正在运行的mysql中的线程id。show full processlist显示的记录中的thread_id。
h) trx_query:事务运行的sql语句,在实际中发现,有时会显示为null值,当为null的时候,就是t2事务中等待锁超时直接报错(ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction)后。trx_query就显示为null值
……
由于前面模拟了事务锁场景。开启了t1和t2事务,如今去查看这个表信息,会有2条记录例如以下:
mysql> select * from INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 3015646
trx_state: LOCK WAIT
trx_started: 2014-10-07 18:29:39
trx_requested_lock_id: 3015646:797:3:2
trx_wait_started: 2014-10-07 18:29:39
trx_weight: 2
trx_mysql_thread_id: 18
trx_query: update test.t1 set b=‘t2‘ where a=1
trx_operation_state: starting index read
trx_tables_in_use: 1
trx_tables_locked: 1
trx_lock_structs: 2
trx_lock_memory_bytes: 376
trx_rows_locked: 1
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: READ COMMITTED
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 10000
trx_is_read_only: 0
trx_autocommit_non_locking: 0
*************************** 2. row ***************************
trx_id: 3015645
trx_state: RUNNING
trx_started: 2014-10-07 18:29:15
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 2
trx_mysql_thread_id: 17
trx_query: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 0
trx_lock_structs: 2
trx_lock_memory_bytes: 376