一 锁概念
- 通常的锁范围
- 全局锁(global lock)
- 表锁(table lock)
- 行锁(row lock)
- innodb行锁范围
- record lock
- gap lock
- next-key lock
二 加锁对数据库的影响
1.锁等待
锁L1锁定某个对象R1,锁L2等待锁释放,如果不释放,会一直等待,或者达到系统预设的超时阈值后报错.回滚整个事务或只回滚当前的SQL.
2.死锁
锁资源请求产生了回路.
三 myisam 锁
读锁:LOCK TABLE user READ,自身只读,不能写;其他线程可读,不能写。多个线程都可提交read lock
create table t3_myisam ( id int PRIMARY key, name varchar(10) ) ENGINE=myisam; session1: root@localhost:mysql.sock 20:14:56 [school]>lock table t3_myisam read; Query OK, 0 rows affected (0.00 sec) root@localhost:mysql.sock 20:15:23 [school]>insert into t3_myisam(id,name) values(1,'s01'); ERROR 1099 (HY000): Table 't3_myisam' was locked with a READ lock and can't be updated session2: root@localhost:mysql.sock 20:22:19 [school]>lock table t3_myisam read; Query OK, 0 rows affected (0.00 sec)
写锁:LOCK TABLE user WRITE ,自身可读写;其他线程完全不可读写.
写锁优先级高于读锁
SELECT自动加读锁(共享锁)
释放锁,UNLOCK TABLES
session1: root@localhost:mysql.sock 20:26:51 [school]>lock table t3_myisam write; Query OK, 0 rows affected (7.91 sec) root@localhost:mysql.sock 20:27:20 [school]>insert into t3_myisam(id,name) values(1,'s01'); Query OK, 1 row affected (0.08 sec)
session2:
查询就会等待
特例:单线程往MyISAM表最后空闲位置串行写入新数据不被锁(而写入中间的空洞位置还是会加锁的)
四 innodb锁
默认是行锁(row lock)
Innodb通过在索引记录上加锁,实现行锁.因此,没有索引时就无法实现行锁,而升级成全表记录锁,等同于表锁
1.锁类型
a、共享锁
b、排他锁
c、意向锁,InnoDB特有,加载在表级别上的锁 (防止读写过程中,有DDL发生)
2.其他锁
2.1 全局锁
global read lock:全局读锁 FLUSH TABLES WITH READ LOCK,释放锁 unlock tables
query cache lock:全局query cache锁,最好关闭
对QC中的数据有更新时,都会引发query cache lock
状态:Waiting for query cache lock
query_cache_size = 0 & query_cache_type = 0
2.2 mdl表锁(meta data lock)
2.3 自增互斥量(multex) 用来管理自增值Auto-increment
root@localhost:mysql.sock 21:19:08 [school]>show variables like 'innodb_autoinc_lock_mode'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | innodb_autoinc_lock_mode | 1 | +--------------------------+-------+ 1 row in set (0.01 sec)
1 :默认设置,可预判行数时使用新方式,不可预判时仍旧使用表锁,会造成autoinc列自增空洞,不过影响很小
2.4 innodb自旋锁,spinlock
在高并发的环境中,线程为了获取CPU资源,而不停的自旋等待
InnoDB spin lock 自旋锁 ,参数innodb_spin_wait_delay,控制轮训间隔,默认6秒
root@localhost:mysql.sock 21:19:17 [school]>show variables like 'innodb_spin_wait_delay'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | innodb_spin_wait_delay | 6 | +------------------------+-------+ 1 row in set (0.00 sec)
获得mutex的过程:
** rounds 19812448 ,线程进入spin wait循环的次数,也就是检查 mutex 锁的次数
** OS waits 375285,线程放弃spip wait尝试,直接进入sleep状态的次数
对于普通的select语句(不在事务的select)是一致性非锁定读,Innodb可以通过以下语句显示的给记录集加共享锁或排他锁
注意:如果在事务中begin select 没有显示的给select加lock in share mode 或者 for update,也是普通的select .
共享锁:
Select * from tablename where … lock in share mode;
排它锁:
Select * from tablename where … for update;
innodb事务锁等待,参数 innodb_lock_wait_timeout 默认值:50秒
IX,事务T想要获得表中某几行的排他锁
| X | IX | S | IS | |
| X | 冲突 | 冲突 | 冲突 | 冲突 |
| IX | 冲突 | 兼容 | 冲突 | 兼容 |
| S | 冲突 | 冲突 | 兼容 | 兼容 |
| IS | 冲突 | 兼容 | 兼容 | 兼容 |
浙公网安备 33010602011771号