数据库锁

数据库锁

全局锁

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