|
477 | 477 | <link href="https://geekhoon.github.io/2017/04/12/JDBC%E4%BA%8B%E5%8A%A1/"/>
|
478 | 478 | <id>https://geekhoon.github.io/2017/04/12/JDBC事务/</id>
|
479 | 479 | <published>2017-04-12T15:20:57.000Z</published>
|
480 |
| - <updated>2018-06-08T16:47:52.297Z</updated> |
| 480 | + <updated>2018-06-09T08:16:25.339Z</updated> |
481 | 481 |
|
482 | 482 | <content type="html"><![CDATA[<h2 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h2><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>概念: 逻辑上的一组操作,要么全部成功,要么全部失败.<br>作用: 保证在一个事务中多次操作要么全部成功,要么全部失败<br>缩写为tx<br><a id="more"></a></p>
|
483 | 483 | <h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p>在数据操作前开启事务,如果在多次数据操作间出现了错误,比如A给B转账,A转出了100,但此时B没有收到,此时程序出错,则A可以rollback回滚,恢复到开始事务时的状态.如果多次数据操作间没出现错误,则可以commit提交.<br><strong>注意:</strong>事务是否结束,取决与 是否调用了rollback 或 commit</p>
|
|
487 | 487 | <h2 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>本地线程变量<br>作用: 在当前线程任意位置,共享数据;</p>
|
488 | 488 | <h3 id="使用-1"><a href="#使用-1" class="headerlink" title="使用"></a>使用</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">set(Object obj); 设置数据;</div><div class="line">get(); 获取数据;</div><div class="line">remove(); 移除数据;</div><div class="line"></div><div class="line">ThreadLocal local = <span class="keyword">new</span> ThreadLocal();</div><div class="line">Thread ct = Thread.currentThread();</div><div class="line"></div><div class="line">local相当于map集合,键的位置存放当前线程,值的位置存放Connection对象</div><div class="line">对应关系:</div><div class="line">local.set(con) --- map.put(ct,con)</div><div class="line">local.get -------- map.get(ct)</div><div class="line">local.remove ----- map.remove(ct)</div></pre></td></tr></table></figure>
|
489 | 489 | <h2 id="事务特性"><a href="#事务特性" class="headerlink" title="事务特性"></a>事务特性</h2><p>ACID<br>1.原子性: 事务结束后,这组操作,要么同时成功,要么同时失败;<br>2.一致性: 事务前后数据必须保持一致,操作完成后,所有数据必须符合业务逻辑,否则事务必须中止;<br>3.隔离性(多事务的并发): 多事务并发,事务以相互隔离的方式执行;<br>4.持久性: 事务提交后,数据必须以一种持久性方式存取起来,事务不可逆;</p>
|
490 |
| -<h2 id="事务中的问题与隔离级别"><a href="#事务中的问题与隔离级别" class="headerlink" title="事务中的问题与隔离级别"></a>事务中的问题与隔离级别</h2><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">脏读:</div><div class="line"> 一个事务读取到另一个事务未提交的数据;</div><div class="line"></div><div class="line">不可重复读:</div><div class="line"> 一个事务中两次查询的数据不一致 --> 一个事务读到了另一个事务 已经提交数据(update)</div><div class="line"></div><div class="line">虚读(幻读):</div><div class="line"> 一个事务中两次查询的数据不一致 --> 一个事务读到了另一个事务 已经提交数据(insert)</div></pre></td></tr></table></figure> |
491 |
| -<h3 id="隔离"><a href="#隔离" class="headerlink" title="隔离"></a>隔离</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">隔离级别(安全从高到低,性能从低到高):</div><div class="line"> (串行化)serializable; --> 解决脏读,不可重复读,虚读(幻读)问题;</div><div class="line"> (可重复读)repeatalbe read; --> 解决脏读,不可重复读问题;(mysql默认隔离级别)</div><div class="line"> (读已提交)read committed; --> 解决脏读问题;</div><div class="line"> (读未提交)read uncommitted; --> 未解决任何问题;</div><div class="line"></div><div class="line">查看隔离级别:</div><div class="line"> select @@tx_isolation;</div><div class="line"></div><div class="line">修改隔离级别:</div><div class="line"> set session transaction isolation level 隔离级别;</div></pre></td></tr></table></figure> |
492 |
| -]]></content> |
| 490 | +<h2 id="事务中的问题与隔离级别"><a href="#事务中的问题与隔离级别" class="headerlink" title="事务中的问题与隔离级别"></a>事务中的问题与隔离级别</h2><p>如果不考虑事务的隔离性,就会引发如下安全性问题:</p> |
| 491 | +<h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">脏读:</div><div class="line"> 一个事务读取到另一个事务未提交的数据;</div><div class="line"></div><div class="line">不可重复读:</div><div class="line"> 一个事务中两次查询的数据不一致 --> 一个事务读到了另一个事务 已经提交数据(update),导致在当前事务中多次查询结果不一致</div><div class="line"></div><div class="line">虚读(幻读):</div><div class="line"> 一个事务中两次查询的数据不一致 --> 一个事务读到了另一个事务 已经提交数据(insert),导致在当前事务中多次查询结果不一致</div><div class="line"> 虚读的产生有一定概率性</div></pre></td></tr></table></figure> |
| 492 | +<h3 id="隔离"><a href="#隔离" class="headerlink" title="隔离"></a>隔离</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">隔离级别(安全从高到低,性能从低到高):</div><div class="line"> (串行化)serializable; --> 解决脏读,不可重复读,虚读(幻读)问题;</div><div class="line"> (可重复读)repeatalbe read; --> 解决脏读,不可重复读问题;(mysql默认隔离级别)</div><div class="line"> (读已提交)read committed; --> 解决脏读问题;(oracle默认隔离级别)</div><div class="line"> (读未提交)read uncommitted; --> 未解决任何问题;</div><div class="line"></div><div class="line">查看隔离级别:</div><div class="line"> select @@tx_isolation;</div><div class="line"></div><div class="line">修改隔离级别:</div><div class="line"> set session transaction isolation level 隔离级别;</div></pre></td></tr></table></figure> |
| 493 | +<h3 id="演示"><a href="#演示" class="headerlink" title="演示"></a>演示</h3><h4 id="演示脏读的发生"><a href="#演示脏读的发生" class="headerlink" title="演示脏读的发生"></a>演示脏读的发生</h4><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">分别开启两个窗口:A,B</div><div class="line">分别查看两个窗口的隔离级别:select @@tx_isolation;</div><div class="line">设置A窗口的隔离级别为:read uncommitted:</div><div class="line">* set session transaction isolation level read uncommitted;</div><div class="line">分别在两个窗口中开启事务:</div><div class="line">* start transaction;</div><div class="line">在B窗口完成转账的操作:</div><div class="line">* update account set money = money - 1000 where name = '张三';</div><div class="line">* update account set money = money + 1000 where name = '李四';</div><div class="line">在A窗口查询数据:(钱已经到账---脏读)</div><div class="line">* select * from account; -- A事务读到了B事务还没有提交的数据.</div></pre></td></tr></table></figure> |
| 494 | +<h4 id="演示避免脏读,不可重复读发生"><a href="#演示避免脏读,不可重复读发生" class="headerlink" title="演示避免脏读,不可重复读发生"></a>演示避免脏读,不可重复读发生</h4><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">分别开启两个窗口:A,B</div><div class="line">分别查看两个窗口的隔离级别:select @@tx_isolation;</div><div class="line">设置A窗口的隔离级别为:read committed:</div><div class="line">* set session transaction isolation level read committed;</div><div class="line">分别在两个窗口中开启事务:</div><div class="line">* start transaction;</div><div class="line">在B窗口完成转账的操作:</div><div class="line">* update account set money = money - 1000 where name = '张三';</div><div class="line">* update account set money = money + 1000 where name = '李四';</div><div class="line">在A窗口中进行查询:</div><div class="line">* select * from account; -- 避免脏读.</div><div class="line">在B窗口提交事务:</div><div class="line">* commit;</div><div class="line">在A窗口中再次查询:</div><div class="line">* select * from account; -- 转账成功.(不可重复读:一个事务读到另一个事务中已经提交的update的数据,导致多次查询结果不一致.)</div></pre></td></tr></table></figure> |
| 495 | +<h4 id="演示避免不可重复读"><a href="#演示避免不可重复读" class="headerlink" title="演示避免不可重复读"></a>演示避免不可重复读</h4><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">分别开启两个窗口:A,B</div><div class="line">分别查看两个窗口的隔离级别:select @@tx_isolation;</div><div class="line">设置A窗口的隔离级别为:repeatable read:</div><div class="line">* set session transaction isolation level repeatable read;</div><div class="line">分别在两个窗口中开启事务:</div><div class="line">* start transaction;</div><div class="line">在B窗口完成转账的操作:</div><div class="line">* update account set money = money - 1000 where name = '张三';</div><div class="line">* update account set money = money + 1000 where name = '李四';</div><div class="line">在A窗口查询:</div><div class="line">* select * from account; -- 转账没有成功:避免脏读.</div><div class="line">在B窗口提交事务:</div><div class="line">* commit;</div><div class="line">在A窗口中再次查询:</div><div class="line">* select * from account; -- 转账没有成功:避免不可重复读.</div></pre></td></tr></table></figure> |
| 496 | +<h4 id="演示避免虚读的发生"><a href="#演示避免虚读的发生" class="headerlink" title="演示避免虚读的发生"></a>演示避免虚读的发生</h4><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">分别开启两个窗口:A,B</div><div class="line">分别查看两个窗口的隔离级别:select @@tx_isolation;</div><div class="line">设置A窗口的隔离级别为:serializable:</div><div class="line">* set session transaction isolation level serializable;</div><div class="line">在A,B两个窗口中分别开启事务:</div><div class="line">* start transaction;</div><div class="line">在B窗口中完成一个insert操作:</div><div class="line">* insert into account values (null,'王老师',10000);</div><div class="line">在A创建中进行查询的操作:</div><div class="line">* select * from account; -- 没有查询到任何结果.</div><div class="line">在B窗口提交事务:</div><div class="line">* commit; -- A窗口马上就会显示数据.</div></pre></td></tr></table></figure>]]></content> |
493 | 497 |
|
494 | 498 | <summary type="html">
|
495 | 499 |
|
|
0 commit comments