Mysql中的锁

114 阅读3分钟

1、从锁的粒度:页级、表级、行级。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。\

  • 表级锁又细分为表锁和元数据锁,表锁的语法是 lock tables … read/write,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁

image.png session A先启动,这时候会对此表加一个MDL读锁。由于session B需要的也是MDL读锁,因此可以正常执行

之后session C会被blocked,是因为session A的MDL读锁还没有释放,而session C需要MDL写锁,因此只能被阻塞。 避免: 首先要解决长事务,因为事务不提交就会一直占用MDL锁,可以查到当前执行中的事务。如果你要做DDL变更的表刚好有长事务在执行, 要考虑先暂停DDL,或者kill掉这个长事务。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。\

image.png

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般\

2、读锁(共享)、写锁(互斥)----加写锁的时候,不能加写锁和读锁,加读锁的时候可以加读锁不能加写锁 加共享锁的命令:select * from table lock in share mode

当有一个事务加了独占锁之后,此时其它事务再要更新这行数据,都是要加独占锁的,但是只能生成独占锁在后面等待。

当有人在更新数据的时候,其它的事务可以读取这行数据吗?默认情况下需要加锁吗?不用! 因为MVCC机制

2、什么情况下需要加锁

  • 在高并发买票情况下
  • 迁移数据的时候

3、死锁

这时候,事务A在等待事务B释放id=2的行锁,而事务B在等待事务A释放id=1的行锁。 事务A和事务B在互相等待对方的资源释放,就是进入了死锁状态。当出现死锁以后,有两种策略:
1、直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置。
2、发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。

在InnoDB中,innodb_lock_wait_timeout的默认值是50s,意味着如果采用第一个策略,当出现死锁以后,第一个被锁住的线程要过50s才会超时退出,然后其他线程才有可能继续执行。对于在线服务来说,这个等待时间往往是无法接受的。

但是,我们又不可能直接把这个时间设置成一个很小的值,比如1s。这样当出现死锁的时候,确实很快就可以解开,但如果不是死锁,而是简单的锁等待呢?所以,超时时间设置太短的话,会出现很多误伤。

所以,正常情况下我们还是要采用第二种策略,即:主动死锁检测,而且innodb_deadlock_detect的默认值本身就是on。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的,但是它也是有额外负担的。

参考文献:
1、blog.csdn.net/weixin_4265…