首页 > 代码库 > 细聊MySQL的Innodb存储引擎(二)
细聊MySQL的Innodb存储引擎(二)
细聊MySQL的Innodb存储引擎(一)
上一篇主要和大家探讨了下Innodb的锁机制与隔离机制。本篇来和大家一起研究下在使用Innodb是会出现的问题以及如何解决它们。
Innodb是如何解决幻读问题的
什么是幻读?听起来似乎很高端,但实际上它只是反映了事务中的一种数据不一致的情况。下面看我来描述这样一个场景,通过这个场景,大家就能很清楚的知道幻读到底是什么意思。
打开两个客户端,设为A和B
A客户端
mysql> start transaction; (步骤一)
Query OK, 0 rows affected (0.00 sec)
mysql> select * from b; (步骤二)
+----+------+
| id | name |
+----+------+
| 10 | abd |
| 99 | NULL |
| 1 | wang |
| 7 | eeee |
| 2 | wei |
| 3 | ak47 |
| 9 | ffff |
+----+------+
7 rows in set (0.00 sec)
mysql> mysql> select * from b;(步骤六)
+----+------+
| id | name |
+----+------+
| 10 | abd |
| 99 | NULL |
| 1 | wang |
| 7 | eeee |
| 2 | wei |
| 3 | ak47 |
| 9 | ffff |
+----+------+
7 rows in set (0.00 sec)
mysql> insert into b (id,name) values (100,‘abc’); (步骤七)
ERROR 1062 (23000): Duplicate entry ‘100‘ for key ‘PRIMARY‘
B客户端
mysql> start transaction; (步骤三)
Query OK, 0 rows affected (0.00 sec)
mysql> insert into b (id,name) values (100,‘abc’); (步骤四)
Query OK, 1 row affected (0.00 sec)
mysql> commit; (步骤五)
Query OK, 0 rows affected (0.01 sec)
=。= what? 明明步骤六查询结果没有值为100的id,为啥插入时提示重复key呢?这个值为100的id在事务A中“凭空”的产生了,这种现象就称之为幻读。
由于REPEATABLE-READ隔离级别是参照第一次查询的时间点快照来保持一致性读的,所以当事务B提交插入数据后,事务A仍然显示旧版本的结果集来保持数据的一致性。而这样恰好就成为了引起幻读的原因。
那么,如何解决幻读问题呢?要解决幻读问题,需要在查询事务中显示添加锁,如使用select * from b for update声明来获取最新的数据。但这样就与一致性读的性质相矛盾了。所以具体问题使用什么办法解决要具体分析。
死锁的侦测与回滚
Innodb能自动侦测事务死锁,当侦测到死锁时,Innodb能自动回滚小事务。事务的大小由插入、更新或删除的行数决定。
如果没有设置Innodb_table_locks参数或者将事务设置成自动,那么Innodb将不能侦测死锁。如果MySQL使用LOCK TABLES声明或使用其它的存储引擎加锁,MySQL也不能侦测死锁。
当Innodb执行一个事务回滚后,所有被该事务设置的锁都将被释放。如果一个SQL声明执行后返回错误。那么被该声明设置的锁将不被释放。
如何避免死锁
1、如果频繁的出现死锁警告,可以开启innodb_print_all_deadlocks选项,查看在error log里的关于死锁的详细信息。
2、尽量使用小事务,这样可以减少冲突的概率。
3、如果你使用SELECT...FOR UPDATE类似声明,尽量使用更低的隔离级别,比如READ-COMMITTED。
4、掌握好事务内的操作顺序,这样可以有效防止死锁。
5、优化索引,这样在查询时能扫描更少的索引记录,对更少的索引加锁。
本文出自 “架构师之路” 博客,请务必保留此出处http://wangweiak47.blog.51cto.com/2337362/1591765
细聊MySQL的Innodb存储引擎(二)