在我们的电商系统中,需求非常多,永远做不完。同时一些也经常面临一些技术方面的问题,比如,这次一条 SQL 语句让整个数据库都挂了。
由于最近业绩爆发,系统中某张表由于设计不太合理,导致产生了大量的冗余数据。于是,经过一番讨论后,我们想把冗余数据迁出一部分。这和我们前面讲的有点不太一样了。前面我们是整库迁移,现在是针对单表迁移。
针对单表只读,我们使用了表锁的语法 lock tables … read/writ…。具体用法如下:
lock tables xttblog read;
-- lock tables xttblog2 write;
使用上面的语句后,在我们操作完成后,可以通过 unlock tables 进行解锁或者,也可以在客户端断开的时候自动释放。
unlock tables;
show open TABLES from test;
使用 lock tables xttblog read,writ xttblog2 语法需要注意的是,则当前会话只能对 xttblog 表 read ,不能 write。其他会话不能写 xttblog 表,读写 xttblog2 表。当前会话对其它表不能 read,write,并且在解锁之前,当前会话也只能读 xttblog,读写 xttblog2。
这么 BT 的限制,导致了一个正在执行的事务被阻塞了。光阻塞也还算好,因为事务会有超时机制。
但是线程池配置的有一个大 Bug,超时之后会进行重试。当前表锁住,限制只读之后,增删改请求都被阻塞了。于是不停的有线程被阻塞,然后还有重试。
本来这张表设计的冗余数据就比较多,操作比较频繁。现在好了,大量的线程被阻塞了。于是整个生产库随之挂了。
所以,有时候有 DBA 是一种莫大的幸福啊。切记在业务高峰时期对生产库进行操作,夜深人静才是进行数据进行迁移的时候。
还有,遇到这类问题,先修改业务代码。从源头控制,别光一直想着进行数据迁移。重试这种机制有好处也有害处,使用要合理。
最后,结合前面的文章总结一下,全局锁 Flush tables with read lock(FTWRL) 与 lock table table_name read/write 锁的区别。
- Flush tables with read lock: 全局读锁,解锁:unlock tables 。
- lock table table_name read/write :指定表锁,解锁:unlock table table_name /unlock tables table_names 每次只能持一个锁。
- lock tables table read :没有会话能 DML read-locked 表。
- lock tables table_name write : 除了持有锁会话,没有会话能访问 write-locked 表。
一个 session 只能为自己获取锁和释放锁,不能为其他 session 获取锁,也不能释放由其他 session 保持的锁。保持该锁的 session 可以读取加锁的表,但不能写,对于没有加锁的表不能读也不能写。多个 session 可同时为同一个表获取 READ 锁。当前 session 只能读取明确获取了 READ 锁的表,不能更新该表,也不能读取和更新其他没有获取 READ 锁的表。其他的 session 可以读取没有在当前 session 中明确获取 READ 锁的表,当然也可以读取获取了 READ 锁的表。但是更新在其他 session 中获取了 READ 锁的表会被阻塞,可以正常更新其他的表。
网上的代码好 Copy,做 demo 演示很溜,拿到生产上就是车祸。主要是理解的太片面,理解不深,容易翻车!
: » 一个SQL让导致整个数据库都整挂了
原创文章,作者:wdmbts,如若转载,请注明出处:https://blog.ytso.com/252420.html