MySQL数据库-事务处理与事务隔离(锁机制)
2016-08-08 20:23
405 查看
MySQL 事务处理
简单介绍事务处理:
MySQL 事务主要用于处理操作量大,复杂度高的数据。 比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
一个事务是一个连续的一组数据库操作,就好像它是一个单一的工作单元进行。换言之,永远不会是完整的事务,除非该组内的每个单独的操作是成功的。如果在事务的任何操作失败,则整个事务将失败。
事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行
事务用来管理多条insert,update,delete语句
一般来说,事务是必须满足4个条件(ACID):
Atomicity(原子性)、Consistency(稳定性)、Isolation(隔离性)、Durability(可靠性)
1、事务的原子性:一组事务,要么成功;要么撤回。
2、稳定性 : 有非法数据(外键约束之类),事务撤回。
3、隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
4、可靠性:软、硬件崩溃后,InnoDB数据表驱动会利用日志文件重构修改。可靠性和高速度不可兼得, innodb_flush_log_at_trx_commit选项 决定什么时候把事务保存到日志里。
开始一个事务
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
在MySQL中,事务开始使用COMMIT或ROLLBACK语句开始工作和结束。开始和结束语句的SQL命令之间形成了大量的事务。
COMMIT & ROLLBACK:
这两个关键字提交和回滚(撤销事务)主要用于MySQL的事务。
当一个成功的事务完成后,发出COMMIT命令应使所有参与表的更改才会生效。
如果发生故障时,应发出一个ROLLBACK命令返回的事务中引用的每一个表到以前的状态。
可以控制的事务行为称为AUTOCOMMIT设置会话变量。如果AUTOCOMMIT设置为1(默认值),然后每一个SQL语句(在事务与否)被认为是一个完整的事务,并承诺在默认情况下,当它完成。 AUTOCOMMIT设置为0时,发出SET AUTOCOMMIT =0命令,在随后的一系列语句的作用就像一个事务,直到一个明确的COMMIT语句时,没有活动的提交。
Java中setAutoCommit(false)对应mysql中的“START TRANSACTION;”的功能
SQL代码演示说明:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>;</span> <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">delete</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> aa <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">where</span> id=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'7'</span>;</span> <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">update</span> aa <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> sname=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'aaaa'</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">where</span> id=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'5'</span>;</span> <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">rollback</span>;</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*事务回滚-执行失败*/</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*commit;提交事务-执行成功*/</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
说明:从”start transaction”开始 到 “bollback; 或 commit; ”,这中间的那么语句是一个整体,如果执行 “bollback”,那么这些动作都会回滚(撤消)。如果执行“commit”,就全部执行成功。
Java代码演示:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Test</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">transactionDemo</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> ClassNotFoundException, SQLException{ <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//1、加载连接器(驱动) Driver </span> Class.forName(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.mysql.jdbc.Driver"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//2、建立连接</span> String url = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"jdbc:mysql://127.0.0.1:3306/hncu?useUnicode=true&characterEncoding=utf-8"</span>; Connection con = DriverManager.getConnection(url, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"root"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"1234"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//3、获取语句对象</span> Statement st = con.createStatement(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//4、下面为Java实现事务处理</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { con.setAutoCommit(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//从设置false开始,以下都是一个事务</span> String sql = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"insert into aa values(1,'张三');"</span>; st.execute(sql);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//增</span> sql = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"delete from aa where id = 5"</span>; st.execute(sql);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//删</span> sql = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"update aa set sname='rose111' where id=6"</span>; st.execute(sql); con.commit();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//提交</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { con.rollback();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果出现异常,我们就让事务回滚</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>{ con.setAutoCommit(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//再设置回去</span> con.close(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li></ul>
事务隔离级别(加锁):
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。查询事务隔离级别:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">select</span> @@tx_isolation;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,被称之为脏读(Dirty Read)。<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">测试流程: 1、A设置read-uncommitted, <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> 设置事务隔离级别(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span>-uncommitted): <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">session</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">isolation</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">level</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span> uncommitted;</span> 2、B执行<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,再修改一条记录, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>、A查询记录,得到了以为正确的记录 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>、B回滚。 问题:A读到了B没有提交的记录,也就是脏读。 </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
不可重复读(nonrepeatable read):
一个从开始直到提交之前所做的任何修改对其它事务都是不可见的。两次同样的查询可能会得到不一样的结果。
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">测试流程: 1、A设置read-committed, <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> 设置事务隔离级别(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span>-committed): <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">session</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">isolation</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">level</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span> committed;</span> 2、B执行<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,修改一条记录,查询记录,记录已经修改成功 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>、A查询记录,结果还是老的记录 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>、B提交事务 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>、A再次查询记录,结果是新的记录。 问题:两次查询结果不一致,也就是不可重复读问题。</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
Repeatable Read(可重读)-MySQL的默认事务隔离级别
它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。保证了在同一事务中多次读取结果是一致的。但会引起另外一个幻读问题,当某个事务在读取某个范围记录时,另外一个事务在该范围插入和新记录,当之前事务再次读取该范围记录时会产生幻行。
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">测试流程: 1、A设置repeatable-read, <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,查询记录,结果是老的记录 设置事务隔离级别(repeatable-<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span>,MySQL默认): <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">session</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">isolation</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">level</span> repeatable <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span>;</span> 2、B执行<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,修改一条记录,查询记录,记录已经修改成功 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>、A查询记录,结果还是老的记录 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>、B提交事务 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>、A再次查询记录,结果还是老的记录。 问题:可以重复读,A在事务过程中,即使B修改了数据,并且<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">commit</span>,A读取的还是老的数据。即可重复读。 注意:这里可能会存在一个新的问题,A在事务过程中,B增加一条记录,并提交,导致A的两次读取不一致,会多一条记录,也就是幻影读。 InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">测试流程: 1、A设置serializable, <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,查询记录,结果是老的记录 设置事务隔离级别(serializable,最高级别): <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">session</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">isolation</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">level</span> serializable;</span> 2、B执行<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span>,修改一条记录,B卡在这里,要等待A完成才行。 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>、A查询记录,结果还是老的记录,A提交。 <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>、B的修改操作才进行下去。 注意:B在等待过程中,会出现<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">lock</span>超时。</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
小知识点:
<code class="hljs autohotkey has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">共享锁:如果事务T对数据<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">A</span>加上共享锁后,则其他事务只能对<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">A</span>再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。 排他锁:如果事务T对数据<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">A</span>加上排他锁后,则其他事务不能再对<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">A</span>加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
查看当前隔离级别:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">select</span> @@tx_isolation;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
设置隔离级别语法:
<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">session</span> | <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">global</span>] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">transaction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">isolation</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">level</span> {<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span> uncommitted | <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span> committed | repeatable <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">read</span> | serializable}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:
脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack(回滚)了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
相关文章推荐
- 关于事务的隔离级别和处理机制的理解
- mysql事务处理和不同隔离机制
- MySQL---数据库从入门走向大神系列(六)-事务处理与事务隔离(锁机制)
- MYSQL数据库事务处理和锁机制
- Mysql数据库事务、隔离、锁机制介绍
- Hibernate逍遥游记-第15章处理并发问题-001事务并发问题及隔离机制介绍
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理
- 分析Hibernate的事务处理机制
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理
- open session and Hibernate事务处理机制
- open session and Hibernate事务处理机制
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处理
- 理解事务处理、事务处理的隔离级别,和使用JDBC进行事务处
- 分析Hibernate的事务处理机制
- Hibernate事务处理机制
- 初识jdbc对oracle数据库事务处理(隔离级别)
- open session and Hibernate事务处理机制 - Hibernate - Java - JavaEye论坛
- open session and Hibernate事务处理机制
- PHP对MYSQL数据库进行事务处理及表锁定