1.锁分类
操作类型:
a.读锁(共享锁):对同一个数据,多个读操作可以同时进行,互不干扰。
b.写锁(互斥锁):如果当前些操作没有完毕,则无法进行其它的读、写操作。
操作范围:
a.表锁:一次性对一张表整体加锁。如M有ISAM存储引擎使用表锁,开销小、加锁快,无死锁;但锁的范围大,容易发生锁冲突、并发能力低。
b.行锁:一次性对一条数据加锁。如InnoDB存储引擎使用行锁,开销大,加锁慢,容易死锁;锁的范围小,不易发生锁冲突,并发度高(很小概率发生并发问题:脏读、幻读、不可重复度、丢失更新)
c.页锁:很少使用
2.表锁:MyISAM
a.读锁(共享锁):对同一个数据,多个读操作可以同时进行,互不干扰。
加锁:lock table 表名 read;
释放锁:unlock tables;
读锁结论:如果某一个会话对A表加了read锁,则该会话只能对A表进行读操作、不能进行写操作,对于其它表不能进行读、写操作。
其它会话:对所有表(包括A表)可以读操作,对A表之外的所有表有写操作。对A表的写等待(需要加锁会话释放锁,才会结束等待执行)。
b.写锁(互斥锁):如果当前些操作没有完毕,则无法进行其它的读、写操作。
加锁:lock table 表名 write;
写锁结论:如果某一个会话对A表加了写锁,该会话可以对A表进行任何操作;但不能对其它表进行任何操作。
其它会话:对A表进行读、写操作要等待加锁会话释放锁。
c.MySQL表级锁的锁模式:
MyISAM在执行查询语句(select)前,会自动给设计的所有表加读锁,在执行写操作前,会自动给涉及的表加写锁。
对MyISAM表的读操作(加读锁),不会阻塞其它进程(会话)对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后, 才会执行其它进程的写操作。
对MyISAM表的写操作(加写锁),会阻塞其它进程(会话)对同一表的读、写操作,只有当前锁释放后,才会执行其它进程的读写操作。
d.分析表锁定:
i.查看那些表加了锁:show open tables; #1代表被加了锁
ii.分析表锁定的严重程度:show status like 'table%';
Table_locks_immediate:立刻能获取到的锁数
Table_locks_waited:需要等待的表锁数
一般建议:Table_locks_immediate/Table_locks_waited >5000,建议采用InnoDB,否则使用MyISAM
3.行锁:InnoDB(MySQL自动提交,行锁需要把自动提交关闭 set autoconmmit =0;)
a.某个会话对某条数据进行DML操作,其它会话需要等该会话结束事务(commit、rollback)后,才能对这条数据进行DML操作
b.行锁是通过事务来解锁的
c.行锁注意事项:
i)、如果没有索引,行锁会转为表锁。(索引失效也会转为表锁)
ii)、行锁的一种特殊情况:间隙锁(行锁):值在范围内,但却不存在。
iii)、如果有where,则实际加锁的范围就是where后面的范围(不是实际的值)
d.行锁:InnoDB默认使用行锁
缺点:比表锁性能损耗大
有点:并发能力强,效率高
因此建议:高并发用InnoDB,否则使用MyISAM。
e.行锁分析
show status like '%innodb_row_lock%';
Innodb_row_lock_current_waits:当前正在等待锁的数量。
Innodb_row_lock_time:等待总时长。从系统启动到目前一共等待的时间。
Innodb_row_lock_time_avg:平均等待时长,从系统启动到目前平均等待时间。
Innodb_row_lock_time_max:最大等待时长,从系统骑电动到现在最大一次等待时间。
Innodb_row_lock_waits:等待次数。从系统启动到现在等待次数。
f.通过for update给select语句加锁。注意不要自动提交(set autocommit = 0;|start transaction;|begin;)