您的位置:首页 > 数据库 > MySQL

细聊MySQL的Innodb存储引擎(二)

2014-12-19 16:08 357 查看
细聊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、优化索引,这样在查询时能扫描更少的索引记录,对更少的索引加锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息