MySQL数据库锁介绍
1. 锁的基本概念
2. 锁的基本类型
2.1 共享锁(Shared Lock,也叫S锁)
2.2 排他锁(Exclusive Lock,也叫X锁)
产生排他锁的sql: select * from ad_plan for update;
S X
时间\事务 |
Tx1: |
Tx2: |
T1 |
set autocommit=0; |
set autocommit=0; |
T2 |
select * from ad_plan lock in share mode; |
|
T3 |
|
update ad_plan set name='' ; blocking |
执行sql: select * from information_schema.innodb_locks; 可以查看锁。
3. 锁的粒度
就是通常我们所说的锁级别。MySQL有三种锁的级别:页级、表级、行级。MySQL这3种锁的特性可大致归纳如下:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
3.1 行锁(Row Lock)
通常用在DML语句中,如INSERT, UPDATE, DELETE等。
InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
INSERT INTO test_index values(1,'张一',15);
INSERT INTO test_index values(3,'张三',16);
INSERT INTO test_index values(4,'张四',17);
INSERT INTO test_index values(5,'张五',19);
INSERT INTO test_index values(7,'刘琦',19);
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test_index | ALL | NULL | NULL | NULL | NULL | 5 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
ADD UNIQUE uk_id(id),
mysql> explain select * from test_index where id = 1;
+----+-------------+------------+-------+---------------+-------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+-------+---------+-------+------+-------+
| 1 | SIMPLE | test_index | const | uk_id | uk_id | 5 | const | 1 | NULL |
+----+-------------+------------+-------+---------------+-------+---------+-------+------+-------+
mysql> select * from test_index where age=17 lock in share mode;
+------+------+------+
| id | name | age |
+------+------+------+
| 4 | 张四 | 17 |
+------+------+------+
1 row in set (0.00 sec)
mysql> insert test_index values(8,'test',18);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+--------------+-------------+-----------+-----------+---------------------+------------+------------+-----------+----------+--------------------+
| 45288:57:5:5 | 45288 | X,GAP | RECORD | `test`.`test_index` | idx_age | 57 | 5 | 5 | 19, 0x000000000208 |
| 45289:57:5:5 | 45289 | S,GAP | RECORD | `test`.`test_index` | idx_age | 57 | 5 | 5 | 19, 0x000000000208 |
+--------------+-------------+-----------+-----------+---------------------+------------+------------+-----------+----------+--------------------+
G | I | R | N | |||
G | + | + | + | + | ||
I | – | + | + | – | ||
R | + | + | – | – | ||
N | + | + | – | – |
间隙锁只会出现在辅助索引(index)上,唯一索引(unique)和主键索引是没有间隙锁。
3.2 页面锁
3.3 表锁(Table Lock)
在MySQL 数据库中,使用表级锁定的主要是MyISAM,Memory等一些非事务性存储引擎。
A. trx1 BEGIN
B. trx1 给 T1 加X锁,修改表结构。
C. trx2 BEGIN
D. trx2 给 T1 的一行记录加S或X锁(事务被阻塞,等待加锁成功)
trx1要操作整个表,锁住了整个表。那么trx2就不能再对T1的单条记录加X或S锁,去读取或修这条记录。
3.3.1 表锁—意向锁
IS | IX | S | X | |
IS | + | + | + | – |
IX | + | + | – | – |
S | + | – | + | – |
X | – | – | – | – |