mysql锁
数据库为了保证数据的一致性,使各种资源在被并发访问时变得有序。
mysql锁最显著的特点是不同的存储引擎支持不同的【锁机制】,innodb支持行锁,myisam支持表锁。
表锁的特点特点开销小,加锁快,不会出现死锁,锁粒度大,发生锁冲突的概率高,并发低。
行锁的特点就是开销大,加锁慢,会出现死锁,锁粒度小,发生锁冲突的概率低,并发度也相对行锁较高。
还有一种页锁,性能介于表锁,行锁之间。
一)innodb锁类型
1,读锁
简称S锁,一个事物获取了一个数据行的读锁,其他事物能够获得该行对应的读锁,不能获得写锁。
2,写锁
写锁简称X锁,一个事物获取了一个数据行的写锁,其他事物就不能再获取该行的其他数据,写锁优先级高。
比较特殊的 select for update会对读取的行记录加一个写锁。
3,MDL锁
5.5引入了 meta data lock,MDL锁,用于保证表中元数据的信息,在会话A中开启了查询事物后,会自动获得一个MDL锁,
会话B就不可以执行任何DDL语句的操作。
session1:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1;
±—±-------+
| id | name |
±—±-------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | llllll |
| 4 | 刘六 |
±—±-------+
4 rows in set (0.00 sec)
session 2:
mysql> alter table t1 change name num varchar(30);
session1:
show processlist;
±—±-----±----------±-----±--------±-----±--------------------------------±---------------------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
±—±-----±----------±-----±--------±-----±--------------------------------±---------------------------------------------+
| 19 | root | localhost | test | Query | 0 | starting | show processlist |
| 20 | root | localhost | test | Query | 8 | Waiting for table metadata lock | alter table t1 change name num varchar(30) |
±—±-----±----------±-----±--------±-----±--------------------------------±---------------------------------------------+
在state列可以看到mds锁的信息。
4,意向锁
在innodb引擎中,意向锁是表级锁,分为意向共享锁,意向排他锁。
意向共享锁(IS):在给一个行数据加共享锁之前必须先取得该表的IS锁。
意向排他锁(IX):在给一个数据行加排他锁前必须先取得该表的IX锁。
二)一致性非锁定读,一致性锁定读
一致性非锁定读:
一致性的非锁定读是指innodb存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据,如果读取的行正在执行delete或update操作,这时读取操作不会因此去等待行锁的释放,相反地innodb存储引擎会去读取行的一个快照,之所以称其为非锁定读,因为不需要等待访问的行上X锁的释放。
快照数据是指该行的之前版本的数据,该实现是通过undo段来完成。
而undo用来在事物中回滚数据,因此快照数据本身是没有额外的开销。此外,读取快照数据是不需要上锁的,因此没有事物需要对历史的数据进行修改操作。
可以看到非锁定读极大地提高了数据库的并发性。在innodb的默认设置下,这时默认的读取方式,即读取不会占用和等待表上的锁,因此在不同的隔离级别下,读取的方式不同,并不是在每个隔离级别下都是采用非锁定一致性读,此外即使都是使用非锁定的一致性读,当时对于快照数据的定义也各部相同。
快照数据其实就是当前数据的历史版本,每行记录可能有多个版本,一个行记录可能不止有一个快照数据,一般称这种技术为多版本技术,由此带来的并发控制称之为多版本并发技术mvcc。
在RC和RR(默认级别)下,innodb存储引擎使用非锁定的一致性读,,然而对快照数据的定义却不相同:
RC:对于快照读,非一致读总是读取被锁定行的最新一份快照数据。
RR:对于快照读,非一致性读总是读取事物开始时的行数据版本。
举例:
select @@tx_isolation;
±---------------+
| @@tx_isolation |
±---------------+
| READ-COMMITTED |
±---------------+
1 row in set, 1 warning (0.00 sec)
session-1 |
---|
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select *from t1;
±—±-----+
| id | num |
±—±-----+
| 1 | NBA |
±—±-----+
1 row in set (0.00 sec)
session-2 |
---|
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set num=‘CBA’ where id=1;
Query OK, 1 row affected (0.10 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec
session-1 |
---|
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select *from t1;
±—±-----+
| id | num |
±—±-----+
| 1 | CBA |
±—±-----+
1 row in set (0.00 sec)
说明RC级别下,非一致性锁定读取被锁定行的最新快照。
接下来模拟RR级别:
select @@tx_isolation;
±----------------+
| @@tx_isolation |
±----------------+
| REPEATABLE-READ |
±----------------+
1 row in set, 1 warning (0.00 sec)
session-1 |
---|
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1;
±—±-----+
| id | num |
±—±-----+
| 1 | CBA |
±—±-----+
1 row in set (0.00 sec)
session-2 |
---|
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set num=“WBA” where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
session-1 |
---|
select * from t1;
±—±-----+
| id | num |
±—±-----+
| 1 | CBA |
±—±-----+
1 row in set (0.00 sec)
可见在RR级别下,非一致快照读数据读取事物开始时的行数据版本。
一致性锁定读:
某些情况下用户需要显示地对数据库读取操作进行加锁以保证数据逻辑的一致性。
这就要求支持加锁语句,即使是对于select的只读操作,innodb存储引擎对于select语句支持两种一致性的锁定读(locking read)操作。
select for update
select lock in share mode
select, for update对读取的行加一个X锁,其他事物不能对已锁定的行加上任何锁,
select, lock in share mode对读取的行记录加上一个S锁,其他事物可以向被锁定的行加S锁,但是如果是X会被阻塞。
以上情况必须在一个事物中,当事物提交了,锁也就释放了,因此在使用上述语句时必须加上BEGIN,START TRANSACTION或者SET AUTOCOMMIT=0.
三)innodb行锁算法:
默认RR隔离级别模式下,
(1) 单个行记录的锁revord lock
(2)间隙锁gap lock,锁定一个范围,不包含记录本身。
(3)记录锁和间隙锁的组合叫做next-key lock,当查询的索引中包含唯一索引时,next-key lock会降级为record lock
注:主键和唯一索引都是行记录的锁模式,在RC隔离级别下,只有record lock记录锁模式。
普通索引默认的就是next-key lock模式。
用户可以通过两种方式来显示关闭gap lock:
(1)将事物的隔离级别设置为RC,
(2)将参数innodb_locks_unsafe_for_binlog设置为1