点击蓝字
关注不迷途

背景
探究MySQL表锁与行锁的不同。
分析
在多个进程或事务访问数据时,为保证数据的一致性,我们这时候就需要锁了。
那么MySQL数据库的锁又有哪些呢?有行锁、表锁、页锁等。
锁是由存储引擎实现的,所以今天就MyISAM、InnoDB存储引擎探究两种存储引擎在锁上实现的比较。
这两种存储引擎的不同大都因为它们实现了不同的锁行为导致的,MyISAM实现的是表锁,InnoDB实现的是行锁。
两种存储引擎的比较:
MyISAM:表级锁,不支持事务,不支持外键,支持全文索引,使用变量存储表行数,可以很快读出行数。
InnoDB:行级锁,支持事务,支持外键,使用聚集索引,不使用变量保存行数,需要通过全文扫描才能获取行数。
同时因为锁的不同,两者适合使用的场景的差别很大。
表锁:顾名思义,锁粒度是表,粒度大,并发度相对的就小了,同时锁冲突大,但是开销小,加锁快,无死锁。
表锁分为读锁和写锁。
#加锁lock table tableName;#解锁unlock tables;#查看锁情况show open tables;
加读锁情况下,当前session可进行读操作,不能进行写操作也不能读写其它表。

其它session,可进行读操作,但是写操作会堵塞直到释放锁,可读写其它表。


写锁,当前session,可以读写当前表,不能读写其它表。

其它session,不能读写该表,会阻塞直到该表的锁释放,可以读写其它表。


#分析锁情况show status like '%table%';#产生表级锁定记录table_locks_immediate;#等待锁次数(高表示表级争用严重)table_locks_waited:
行锁:锁粒度小,并发度高,发生锁冲突概率小,但是开销大,加锁慢,有死锁。
行锁的行为与事务隔离级别有关,InnoDB默认可重复读级别。解决脏读、不可重复读问题,但会出现幻读。
#关闭自动提交set autocommit=0;#查看锁情况show status like '%innodb_row_lock%'# 返回#当前等待锁数量innodb_row_lock_current_watis#总等待次数innodb_row_lock_watis#等待锁总时间innodb_row_lock_time#等待最长一次所花时间innodb_row_lock_max_time#等待平均时间innodb_row_lock_avg_time
需要注意的情况。
行锁变表锁:where 不走索引会导致行锁变表锁。
间隙锁:使用范围条件而不是相等条件检索数据,并请求共享或排它锁时,InnoDB会给符合条件的已有记录索引加锁,对于在条件范围内但并不存在的记录,叫做间隙。
InnoDB也会给这个间隙加锁。比如数据库内没有id为2的记录,更新语句更新id的范围为1-10,这时新增记录id=2的数据会被阻塞。
如何锁一行:select*from where id=2 for update;
优化建议
尽可能让所有数据检索通过索引,避免无索引行锁升级为表锁(varchar类型加引号)。
合理设计索引,尽量缩小锁范围。
尽可能较少检索条件,避免间隙锁。
尽量控制事务大小,减少锁定资源和时间长度。
尽可能低级别事务隔离。
思考
不同的情景下,应对的方法往往是不一样的。
在不需要事务,读多写少的情况下,可以选择MyISAM,因为读锁共享,而且表锁花销少,加锁快。
需要事务的,读写频繁的,需要外键约束等选择InnoDB。
MySQL5.5后默认InnoDB存储引擎,所以不知道选择什么存储引擎的时候可以使用默认存储引擎。

喜欢本篇内容顺便点个在看吧





