数据库锁
全局锁
1 | flush table with read lock |
全局锁:对整个数据库实例加锁,MySQL提供一个加全局锁的方法:Flush tables with read lock(FTWRL),这条语句可以让数据库处于只读状态,所有的写操作将被堵塞;全局锁的典型应用场景就是做全库的逻辑备份,即是把整个库 数据查询出来,保存为文本;
表级锁
- 表锁 locktables table_name read/write
- 元数据锁 meta data link, MDL
表级锁:一种是表锁,另一种是元数据锁(meta data lock,MDL锁);表锁,在修改表、或者显示加锁会出现,元数据锁,在事务开始时候加上,是为了保证在并发的情况下,结构变更的一致性,也就是说,事务开始时候,要去做改表操作,必须等待这个事务完成,会堵塞DDL操作。
行锁 record lock
对包含索引列做操作时会产生,在并发的系统下,行锁是不可缺少的,但是行锁在提高并发性的同时,又会带来一些性能问题
行锁: 开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
如何避免?减少锁争用,程序中尽可能使用自动提交,短事务
- Innodb_row_lock_current_waits:当前等待锁的数量
- Innodb_row_lock_time:系统启动到现在、锁定的总时间长度
- Innodb_row_lock_time_avg:每次平均锁定的时间 I
- nnodb_row_lock_time_max:最长一次锁定时间
- Innodb_row_lock_waits:系统启动到现在、总共锁定次数
减少锁争用
- 尽可能让所有的数据检索都通过索引来完成,避免Innodb因为无法通过索引键加锁而升级为表级锁定
- 合理设计索引,让Innodb在索引键上面加锁尽可能准确,缩小锁定范围,避免造成不必要的锁定而影响其他Query的执行
- 尽可能减少基于范围的数据检索过滤条件,避免间隙锁带来的负面影响而锁定了不该锁定的记录
- 尽量控制事务的大小,减少锁定的资源量和锁定时间长度
- 在业务环境允许的情况下,尽量使用较低级别的事务隔离,以减少MySQL因为实现事务隔离级别所带来的附加成本
死锁避免
- 同类的业务模块中,尽可能按照相同的访问顺序来访问,防止产生死锁
- 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率
对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率
GAP锁 间隙锁
特点:锁定一个范围,但不包括记录本身
作用:为了防止同一事务的两次当前读,出现幻读的情况
在可重复读隔离级别下,为了防止幻读,会对某行数据的前后添加间隙锁,不包含某行数据本身
行锁和间隙锁合成为next-key lock