﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-我的博客-随笔分类-MySQL</title><link>http://www.blogjava.net/qbna350816/category/55123.html</link><description>201103</description><language>zh-cn</language><lastBuildDate>Fri, 23 Sep 2016 16:36:32 GMT</lastBuildDate><pubDate>Fri, 23 Sep 2016 16:36:32 GMT</pubDate><ttl>60</ttl><item><title>MySQL事务隔离级别详解</title><link>http://www.blogjava.net/qbna350816/archive/2016/09/24/431834.html</link><dc:creator>胡小军</dc:creator><author>胡小军</author><pubDate>Fri, 23 Sep 2016 16:06:00 GMT</pubDate><guid>http://www.blogjava.net/qbna350816/archive/2016/09/24/431834.html</guid><wfw:comment>http://www.blogjava.net/qbna350816/comments/431834.html</wfw:comment><comments>http://www.blogjava.net/qbna350816/archive/2016/09/24/431834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/qbna350816/comments/commentRss/431834.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/qbna350816/services/trackbacks/431834.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">SQL标准定义了4类隔离级别，包括了一些具体规则，用来限定事务内外的哪些改变是可见的，哪些是不可见的。低级别的隔离级一般支持更高的并发处理，并拥有更低的系统开销。<br /><strong>Read Uncommitted（读取未提交内容）</strong></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在该隔离级别，所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用，因为它的性能也不比其他级别好多少。读取未提交的数据，也被称之为脏读（Dirty Read）。<br /><strong>Read Committed（读取提交内容）</strong></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是大多数数据库系统的默认隔离级别（但不是MySQL默认的）。它满足了隔离的简单定义：一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读（Nonrepeatable Read），因为同一事务的其他实例在该实例处理其间可能会有新的commit，所以同一select可能返回不同结果。<br /><strong>Repeatable Read（可重读）</strong></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是MySQL的默认事务隔离级别，它确保同一事务的多个实例在并发读取数据时，会看到同样的数据行。不过理论上，这会导致另一个棘手的问题：幻读 （Phantom Read）。简单的说，幻读指当用户读取某一范围的数据行时，另一个事务又在该范围内插入了新行，当用户再读取该范围的数据行时，会发现有新的&#8220;幻影&#8221; 行。InnoDB和Falcon存储引擎通过多版本并发控制（MVCC，Multiversion Concurrency Control）机制解决了该问题。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;"><strong>Serializable（可串行化）</strong>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是最高的隔离级别，它通过强制事务排序，使之不可能相互冲突，从而解决幻读问题。简言之，它是在每个读的数据行上加上共享锁。在这个级别，可能导致大量的超时现象和锁竞争。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">这四种隔离级别采取不同的锁类型来实现，若读取的是同一个数据的话，就容易发生问题。例如：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">&nbsp;&nbsp; 脏读(Drity Read)：某个事务已更新一份数据，另一个事务在此时读取了同一份数据，由于某些原因，前一个RollBack了操作，则后一个事务所读取的数据就会是不正确的。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致，这可能是两次查询过程中间插入了一个事务更新的原有的数据。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致，例如有一个事务查询了几列(Row)数据，而另一个事务却在此时插入了新的几列数据，先前的事务在接下来的查询中，就会发现有几列数据是它先前所没有的。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在MySQL中，实现了这四种隔离级别，分别有可能产生问题如下所示：</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; text-align: center; background-color: #ffffff;"><img alt="" width="700" src="http://dl.iteye.com/upload/picture/pic/72610/af5b9c1e-4517-3df2-ad62-af25d1672d12.jpg" height="223" title="点击查看原始大小图片" style="border: 0px; cursor: url(&quot;/images/magplus.gif&quot;), pointer; vertical-align: middle;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;"><br /></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">下面，将利用MySQL的客户端程序，分别测试几种隔离级别。测试数据库为test，表为tx；表结构：</span></p><table border="0" width="440" style="color: #000000; font-family: Helvetica, Tahoma, Arial, sans-serif; font-size: 14px; line-height: 25.2px; height: 50px; background-color: #ffffff;"><tbody><tr><td style="font-size: 1em;"><span style="font-size: medium;">id</span></td><td style="font-size: 1em;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int</span></td></tr><tr><td style="font-size: 1em;"><p style="margin: 0px; padding: 0px;"><span style="font-size: medium;">num</span></p></td><td style="font-size: 1em;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int</span></td></tr></tbody></table><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">两个命令行客户端分别为A，B；不断改变A的隔离级别，在B端修改数据。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;"><strong>（一）、将A的隔离级别设置为read uncommitted(未提交读)</strong></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;在B未更新数据之前：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong><img alt="" width="645" src="http://dl.iteye.com/upload/picture/pic/72618/1ca8ec0d-3b6c-3ae1-babc-5dd541c4d1a4.jpg" height="379" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">B更新数据：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端B：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="640" src="http://dl.iteye.com/upload/picture/pic/72620/b37214c3-7726-3306-95ee-1b2fae5ccd6c.jpg" height="397" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="640" src="http://dl.iteye.com/upload/picture/pic/72622/200d9c94-197a-3fe5-8925-3411cd88555e.jpg" height="481" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">&nbsp;&nbsp;&nbsp; 经过上面的实验可以得出结论，事务B更新了一条记录，但是没有提交，此时事务A可以查询出未提交记录。造成脏读现象。未提交读是最低的隔离级别。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">（二）、将客户端A的事务隔离级别设置为read committed(已提交读)</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;在B未更新数据之前：</span></p><strong style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">客户端A：</span></strong><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><a href="http://xm-king.iteye.com/upload/picture/pic/72626/ae414e52-c216-3bbb-b005-0d972f593456.jpg" style="color: #006600;"><img alt="" width="644" src="http://dl.iteye.com/upload/picture/pic/72626/ae414e52-c216-3bbb-b005-0d972f593456.jpg" height="351" style="border: 0px;" /></a></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">B更新数据：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端B：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="641" src="http://dl.iteye.com/upload/picture/pic/72628/12051f3d-c01e-34b3-a6b6-8b71e1b1dcc8.jpg" height="313" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="642" src="http://dl.iteye.com/upload/picture/pic/72630/cc80744e-eb9f-3104-bb24-2218e9986d78.jpg" height="351" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 经过上面的实验可以得出结论，已提交读隔离级别解决了脏读的问题，但是出现了不可重复读的问题，即事务A在两次查询的数据不一致，因为在两次查询之间事务B更新了一条数据。已提交读只允许读取已提交的记录，但不要求可重复读。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">(三)、<span style="font-size: medium;"><strong>将A的隔离级别设置为repeatable read(可重复读)</strong></span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;在B未更新数据之前：</span></p><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong></div><div style="font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="643" src="http://dl.iteye.com/upload/picture/pic/72632/0bf52be3-e873-3f3f-8d56-d703a8f678ab.jpg" height="319" style="border: 0px;" /></div><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">B更新数据：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端B：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="645" src="http://dl.iteye.com/upload/picture/pic/72634/e58d1814-bdca-3313-bcf5-339e3678536a.jpg" height="333" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="640" src="http://dl.iteye.com/upload/picture/pic/72636/83bfe583-2d57-345a-917e-4ee163235b62.jpg" height="497" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">B插入数据：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端B：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="641" src="http://dl.iteye.com/upload/picture/pic/72638/192348aa-4fa5-3d5f-a4f9-4660ddd725cd.jpg" height="366" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">客户端A：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="641" src="http://dl.iteye.com/upload/picture/pic/72640/4398c5b1-434c-3380-ba19-060154cf2070.jpg" height="351" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由以上的实验可以得出结论，可重复读隔离级别只允许读取已提交记录，而且在一个事务两次读取一个记录期间，其他事务部的更新该记录。但该事务不要求与其他事务可串行化。例如，当一个事务可以找到由一个已提交事务更新的记录，但是可能产生幻读问题(注意是可能，因为数据库对隔离级别的实现有所差别)。像以上的实验，就没有出现数据幻读的问题。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;">(<strong>四)、<span style="font-size: medium;"><strong>将A的隔离级别设置为&nbsp;</strong></span><span style="font-size: medium;">可串行化&nbsp;(Serializable)</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">A端打开事务，B端插入一条记录</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">事务A端：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="639" src="http://dl.iteye.com/upload/picture/pic/72642/c604c5ce-311d-3923-8dcd-36b0188f4f31.jpg" height="234" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">事务B端：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="640" src="http://dl.iteye.com/upload/picture/pic/72644/c488f9d9-7da2-3e6d-9a82-2b92d1051afd.jpg" height="141" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">因为此时事务A的隔离级别设置为serializable，开始事务后，并没有提交，所以事务B只能等待。</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">事务A提交事务：</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">事务A端</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="639" src="http://dl.iteye.com/upload/picture/pic/72646/322ed59a-b2b9-338c-a2f0-09c9b7707577.jpg" height="73" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><strong><span style="font-size: medium;">事务B端</span></strong></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><img alt="" width="644" src="http://dl.iteye.com/upload/picture/pic/72648/8e60e19b-09af-31a7-b8d3-8e638bbf177c.jpg" height="47" style="border: 0px;" /></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.2px; background-color: #ffffff;"><span style="font-size: medium;">&nbsp; &nbsp; &nbsp;&nbsp;<br /></span><span style="line-height: 25.2px;">&nbsp;</span><span style="line-height: 25.2px; font-size: medium;">serializable完全锁定字段，若一个事务来查询同一份数据就必须等待，直到前一个事务完成并解除锁定为止</span><span style="line-height: 25.2px;">&nbsp;。</span><span style="line-height: 25.2px; font-size: medium;">是完整的隔离级别，会锁定对应的数据表格，因而会有效率的问题。<br /><br /></span></p><div>&nbsp;转自：http://xm-king.iteye.com/blog/770721</div><img src ="http://www.blogjava.net/qbna350816/aggbug/431834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/qbna350816/" target="_blank">胡小军</a> 2016-09-24 00:06 <a href="http://www.blogjava.net/qbna350816/archive/2016/09/24/431834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>