文章目录
(资料图片仅供参考)
前言语句层面死锁如何安全地给小表加字段总结
前言
之前的文章,我们对锁的种类,和锁的一些用途,进行了简单的讲解。今天我们将接着上张的内容,对锁的优化进行介绍。
语句层面
首先,我们从语句层面介绍下怎么进行锁优化。之前的文章我们介绍过,锁实在sql执行的时候才会加锁。但是锁的释放,却是在事务提交之后,才会释放。这样就会带来一个问题。如下图 假如,这是一个电影院的一个购票业务。电影院叫b,客户为a,a想在b买一张电影票,上图则是一个完整的买票流程。然后这个时候,c也想从电影院买张票,那么c和a冲突的地方就是第二条语句。如果我们把第二条语句放在最后,那么a和c冲突的时间是不是就会缩短。因为锁是在最后事务提交的时候才会释放,那么放在最后执行冲突语句,锁持续的时间就是最短的。这样就可以减少锁的时间,减少并发冲突的时间。
死锁
说起死锁,相必大家都不会陌生,因为这个在java中也是十分的常见的。产生死锁的原因就是双方互相占有对方所需要的的互斥资源,且短时间内,不会释放。那么从这个描述上呢,我们基本可以有四种解决方法。但是在mysql中呢,大致有两种解决方法。因为mysql中的锁不会像java中的锁,那么便于操作。如下图 事务a和事务b相互需要对方的行锁,导致死锁的产生。这个时候大致有两种策略。 1.直接进入等待,直到超时,这个超时的参数可以自己设置。 2.死锁检测,检测到这个死锁,然后对其中一个事务进行回滚,释放出另一个事务需要的锁,以便两个语句都能进行下去。 但是开启死锁检测是十分的消耗性能的,比如一千个事务同时更新同一行数据,那么死锁基本要检测1000x1000行数据,消耗太大。 那遇到这种热点表怎么办呢,最好的办法就是控制并发,可以用一个队列(不管是在数据库中实现,还是依靠消息中间件实现,都可以),让进来的事务进行排队,同一时间至多有10个,或者20个可以对这行数据进行修改,这样就可以很好的实现并发修改了。
如何安全地给小表加字段
首先我们要解决长事务,事务不提交,就会一直占着 MDL 锁。在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。但考虑一下这个场景。如果你要变更的表是一个热点表,虽然数据量不大,但是上面的请求很频繁,而你不得不加个字段,你该怎么做呢?这时候 kill 可能未必管用,因为新的请求马上就来了。比较理想的机制是,在 alter table 语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程。
总结
今天我们继续上篇文章,对锁的优化进行了讲解,但是只是在语句层面进行大致的讲解。同时也介绍的死锁的出现原因,和怎么避免死锁的方法。