一、 表锁
特点:
偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁中突的概率最高,并发最低
语法:
-- 加表锁
lock table 表名 read(write),表名 read(write)....
-- 查看表上加过的锁
show open tables;
-- 释放表锁
unlock tables;
结论:
Myisam在执行查询语句(select)之前,会自动给涉及的所有表加读锁,再增删改操作之前,会给涉及的所有表加写锁。
mysql的表级锁有两种:表共享读锁、表独占写锁。
锁类型 | 可否兼容 | 读锁 | 写锁 |
---|---|---|---|
读锁 | 是 | 是 | 否 |
写锁 | 是 | 否 | 否 |
对myisam表加读锁,不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有读锁释放才会执行其他进程的写操作。
对myisam表加写锁,会阻塞其他进程对同一表的读和写操作,只有当写锁释放才会执行其他进程操作。
如何分析表锁定:
执行命令:
SHOW STATUS LIKE 'table%';
这里有两个变量记录mysql内部表级锁的锁定情况:
Table_locks_immediate: 产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;
Table_locks_waited: 出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1,此值高则说明存在着较严重的表级锁争用情况;
myisam的读写锁调度是写优先,这也是myisam不适合做写为主的引擎。因为写锁后,其他的线程不能做任何事情,大量的更新会使查询很难得到锁,从而造成永远阻塞。
二、 行锁
特点:
偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
加锁方式:
自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;
无索引导致行锁变表锁:
索引失效会导致行锁变表锁,执行更新操作时要注意!
间隙锁:
当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做"间隙(GAP)"。InnoDB也会对这个"间隙"加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
间隙所危害:若执行的条件是范围过大,则InnoDB会将整个范围内所有的索引键值全部锁定,很容易对性能造成影响。
排他锁:
排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
手动锁定一行:
begin;
select * from table where a=0 for update;
-- 解除锁定
commit;
共享锁:
共享锁,也称读锁,多用于判断数据是否存在,多个读操作可以同时进行而不会互相影响。当如果事务对读锁进行修改操作,很可能会造成死锁
行锁优化
- 尽可能让所有数据检索都通过索引来完成,避免无索引行或索引失效导致行锁升级为表锁。
- 尽可能避免间隙锁带来的性能下降,减少或使用合理的检索范围。
- 尽可能减少事务的粒度,比如控制事务大小,而从减少锁定资源量和时间长度,从而减少锁的竞争等,提供性能。
- 尽可能低级别事务隔离,隔离级别越高,并发的处理能力越低。