﻿<?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-yuyee-随笔分类-orm</title><link>http://www.blogjava.net/yuyee/category/46759.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 03 Nov 2010 10:26:20 GMT</lastBuildDate><pubDate>Wed, 03 Nov 2010 10:26:20 GMT</pubDate><ttl>60</ttl><item><title>嵌套事务</title><link>http://www.blogjava.net/yuyee/archive/2010/11/03/336885.html</link><dc:creator>羔羊</dc:creator><author>羔羊</author><pubDate>Tue, 02 Nov 2010 16:11:00 GMT</pubDate><guid>http://www.blogjava.net/yuyee/archive/2010/11/03/336885.html</guid><description><![CDATA[<span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">在所有使用 spring 的应用中, 声明式事务管理可能是使用率最高的功能了, 但是, 从我观察到的情况看, 绝大多数人并不能深刻理解事务声明中不同事务传播属性配置的的含义, 让我们来看一下TransactionDefinition 接口中的定义 ，在 spring 中一共定义了六种事务传播属性, 如果你觉得看起来不够直观, 那么我来转贴一个满大街都有的翻译</span><span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">&nbsp;</span><span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; "><br />
</span>
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; width: 916px; word-break: break-all; padding-top: 4px; background-color: #eeeeee; color: #454545; font-family: Verdana, Helvetica, Arial; line-height: 18px; "><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" /><span style="color: #000000; ">PROPAGATION_REQUIRED&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_SUPPORTS&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;支持当前事务，如果当前没有事务，就以非事务方式执行。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_MANDATORY&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;支持当前事务，如果当前没有事务，就抛出异常。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_REQUIRES_NEW&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;新建事务，如果当前存在事务，把当前事务挂起。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_NOT_SUPPORTED&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_NEVER&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;以非事务方式执行，如果当前存在事务，则抛出异常。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />PROPAGATION_NESTED&nbsp;</span><span style="color: #000000; ">--</span><span style="color: #000000; ">&nbsp;如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则进行与PROPAGATION_REQUIRED类似的操作。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />前六个策略类似于EJB&nbsp;CMT，第七个（PROPAGATION_NESTED）是Spring所提供的一个特殊变量。&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />它要求事务管理器或者使用JDBC&nbsp;</span><span style="color: #000000; ">3.0</span><span style="color: #000000; ">&nbsp;Savepoint&nbsp;API提供嵌套事务行为（如Spring的DataSourceTransactionManager）&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" /></span></div>
<span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; "><br />
</span><span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">在我所见过的误解中, 最常见的是下面这种:</span><span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">&nbsp;</span><span  style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; "><br />
</span>
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; width: 916px; word-break: break-all; padding-top: 4px; background-color: #eeeeee; color: #454545; font-family: Verdana, Helvetica, Arial; line-height: 18px; "><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" /><span style="color: #000000; ">假如有两个业务接口&nbsp;ServiceA&nbsp;和&nbsp;ServiceB,&nbsp;其中&nbsp;ServiceA&nbsp;中有一个方法实现如下&nbsp;<br />
<img id="Codehighlighter1_55_93_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" /></span><span id="Codehighlighter1_55_93_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />*&nbsp;事务属性配置为&nbsp;PROPAGATION_REQUIRED&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" /></span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;<br />
<img id="Codehighlighter1_111_155_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" /></span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodA()&nbsp;</span><span id="Codehighlighter1_111_155_Open_Text"><span style="color: #000000; ">{&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" /></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;调用&nbsp;ServiceB&nbsp;的方法&nbsp;</span><span style="color: #008000; "><br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" /></span><span style="color: #000000; ">ServiceB.methodB();&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />}</span></span><span style="color: #000000; ">&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align="top" alt="" />那么如果&nbsp;ServiceB&nbsp;的&nbsp;methodB&nbsp;&nbsp;如果配置了事务,&nbsp;就必须配置为&nbsp;PROPAGATION_NESTED&nbsp;</span></div>
<p style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; "><br />
这种想法可能害了不少人, 认为 Service 之间应该避免互相调用, 其实根本不用担心这点，PROPAGATION_REQUIRED 已经说得很明白,&nbsp;<br />
如果当前线程中已经存在事务, 方法调用会加入此事务, 果当前没有事务，就新建一个事务, 所以 ServiceB#methodB() 的事务只要遵循最普通的规则配置为 PROPAGATION_REQUIRED 即可, 如果 ServiceB#methodB (我们称之为内部事务, 为下文打下基础) 抛了异常, 那么 ServiceA#methodA(我们称之为外部事务) 如果没有特殊配置此异常时事务提交 (即 +MyCheckedException的用法), 那么整个事务是一定要 rollback 的, 什么 Service 只能调 Dao 之类的言论纯属无稽之谈, spring 只负责配置了事务属性方法的拦截, 它怎么知道你这个方法是在 Service 还是 Dao 里 ?&nbsp;<br />
<br />
最容易弄混淆的其实是 PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED, 那么这两种方式又有何区别呢? 我简单的翻译一下 Juergen Hoeller 的话 :&nbsp;<br />
<span style="color: red; ">PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.</span>&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red; ">另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务,&nbsp; 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,&nbsp; 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.</span>&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: red; ">由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.<br />
</span><br />
&nbsp;那么外部事务如何利用嵌套事务的 savepoint 特性呢, 我们用代码来说话</p>
<p style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">&nbsp;</p>
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; width: 916px; word-break: break-all; padding-top: 4px; background-color: #eeeeee; color: #454545; font-family: Verdana, Helvetica, Arial; line-height: 18px; "><img id="Codehighlighter1_9_137_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" /><span style="color: #000000; ">ServiceA&nbsp;</span><span id="Codehighlighter1_9_137_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_22_72_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_22_72_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事务属性配置为&nbsp;PROPAGATION_REQUIRED&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;&nbsp;<br />
<img id="Codehighlighter1_95_131_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodA()&nbsp;</span><span id="Codehighlighter1_95_131_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServiceB.methodB();&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_153_264_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" />ServiceB&nbsp;</span><span id="Codehighlighter1_153_264_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_165_219_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_165_219_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事务属性配置为&nbsp;PROPAGATION_REQUIRES_NEW&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_244_253_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodB()&nbsp;</span><span id="Codehighlighter1_244_253_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;</span></div>
<p style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">这种情况下, 因为 ServiceB#methodB 的事务属性为 PROPAGATION_REQUIRES_NEW, 所以两者不会发生任何关系, ServiceA#methodA 和 ServiceB#methodB 不会因为对方的执行情况而影响事务的结果, 因为它们根本就是两个事务, 在 ServiceB#methodB 执行时 ServiceA#methodA 的事务已经挂起了 (关于事务挂起的内容已经超出了本文的讨论范围, 有时间我会再写一些挂起的文章) .&nbsp;<br />
</p>
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; width: 916px; word-break: break-all; padding-top: 4px; background-color: #eeeeee; color: #454545; font-family: Verdana, Helvetica, Arial; line-height: 18px; "><img id="Codehighlighter1_9_139_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" /><span style="color: #000000; ">ServiceA&nbsp;</span><span id="Codehighlighter1_9_139_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_21_71_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_21_71_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事务属性配置为&nbsp;PROPAGATION_REQUIRED&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;&nbsp;<br />
<img id="Codehighlighter1_94_134_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodA()&nbsp;</span><span id="Codehighlighter1_94_134_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServiceB.methodB();&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_155_263_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" />ServiceB&nbsp;</span><span id="Codehighlighter1_155_263_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_170_218_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_170_218_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事务属性配置为&nbsp;PROPAGATION_NESTED&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_243_252_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodB()&nbsp;</span><span id="Codehighlighter1_243_252_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />}</span></span><span style="color: #000000; ">&nbsp;</span></div>
<p style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint(注意, 这是本文中第一次提到它, 潜套事务中最核心的概念), 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:&nbsp;<br />
1. 改写 ServiceA 如下&nbsp;<br />
</p>
<div style="padding-right: 5px; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; width: 916px; word-break: break-all; padding-top: 4px; background-color: #eeeeee; color: #454545; font-family: Verdana, Helvetica, Arial; line-height: 18px; "><img id="Codehighlighter1_9_259_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top" alt="" /><span style="color: #000000; ">ServiceA&nbsp;</span><span id="Codehighlighter1_9_259_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_21_71_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span id="Codehighlighter1_21_71_Open_Text"><span style="color: #008000; ">/**</span><span style="color: #008000; ">&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;事务属性配置为&nbsp;PROPAGATION_REQUIRED&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span></span><span style="color: #000000; ">&nbsp;&nbsp;<br />
<img id="Codehighlighter1_94_253_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">void</span><span style="color: #000000; ">&nbsp;methodA()&nbsp;</span><span id="Codehighlighter1_94_253_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_111_159_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff; ">try</span><span style="color: #000000; ">&nbsp;</span><span id="Codehighlighter1_111_159_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServiceB.methodB();&nbsp;&nbsp;&nbsp;<br />
<img id="Codehighlighter1_183_244_Open_Image" src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000ff; ">catch</span><span style="color: #000000; ">&nbsp;(SomeException)&nbsp;</span><span id="Codehighlighter1_183_244_Open_Text"><span style="color: #000000; ">{&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;执行其他业务,&nbsp;如&nbsp;ServiceC.methodC();&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; "><br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" /></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;<br />
<img src="http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" alt="" />}</span></span><span style="color: #000000; ">&nbsp;&nbsp;</span></div>
<p style="color: #454545; font-family: Verdana, Helvetica, Arial; font-size: 12px; line-height: 18px; ">这种方式也是潜套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点. (题外话 : 看到这种代码, 似乎似曾相识, 想起了 prototype.js 中的 Try 函数 )&nbsp;<br />
<br />
2. 代码不做任何修改, 那么如果内部事务(即 ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此),&nbsp;外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback (+MyCheckedException).&nbsp;<br />
上面大致讲述了潜套事务的使用场景, 下面我们来看如何在 spring 中使用 PROPAGATION_NESTED, 首先来看 AbstractPlatformTransactionManager&nbsp;<br />
<br />
JdbcTransactionObjectSupport 告诉我们必须要满足两个条件才能 createSavepoint :&nbsp;<br />
&nbsp;&nbsp;<br />
<span style="color: red; ">2. java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+&nbsp;<br />
3. Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0&nbsp;</span><br />
<br />
确保以上条件都满足后, 你就可以尝试使用 PROPAGATION_NESTED 了.</p>
<img src ="http://www.blogjava.net/yuyee/aggbug/336885.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yuyee/" target="_blank">羔羊</a> 2010-11-03 00:11 <a href="http://www.blogjava.net/yuyee/archive/2010/11/03/336885.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate简单知识</title><link>http://www.blogjava.net/yuyee/archive/2010/10/25/336047.html</link><dc:creator>羔羊</dc:creator><author>羔羊</author><pubDate>Sun, 24 Oct 2010 16:30:00 GMT</pubDate><guid>http://www.blogjava.net/yuyee/archive/2010/10/25/336047.html</guid><description><![CDATA[<p align="center"><font size="7" face="Calibri">Session接口几个基本操作</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="6" face="Calibri">1.get()方法:先确认该ID对应的数据是否存在,<wbr>先经过session缓存,再二级缓存,之后是数据库,<wbr>如果不存在,返回null</font></li>
        <li><font size="6" face="Calibri">2.load()方法:hibernate会默认你是存在的,<wbr>他会放心的使用代理类在延迟加载数据,当用到他的其他属性时,<wbr>就会跑去数据库中查询,如果不在,抛异常</font></li>
        <li><font size="6" face="Calibri">3.list()方法:去数据库读取数据,填充缓存,</font></li>
        <li><font size="6" face="Calibri">4.iterator()方法:先去数据库select id from table,之后到缓存中查找,如果不存在,出现N+1问题.</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri">缓存</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="6" face="Calibri">1.一级缓存:session级缓存,如果session关闭,<wbr>,清空,释放内存</font></li>
    </ul>
</ul>
&nbsp;<br />
<ul>
    <ul type="DISC">
        <li><font size="6" face="Calibri">2.二级缓存:SessionFactory级别的全局缓存，<wbr>它底下可以使用不同的缓存类库，比如ehcache、<wbr>oscache等，需要设置hibernate.cache.<wbr>provider_class</font></li>
        <li><font size="6" face="Calibri">缓存可以看成是个hastable,典型的空间换时间,<wbr>一般在读写比高的情况下使用</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri">Hibernate中使用二级缓存</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="7" face="Calibri"><strong>Class的缓存</strong>&nbsp;&nbsp;<br />
        </font><font size="6" face="Calibri">对于一条记录，也就是一个PO来说，是根据ID来找的，<wbr>缓存的key就是ID，value是POJO。无论list，<wbr>load还是iterate，只要读出一个对象，都会填充缓存。<wbr>但是list不会使用缓存，<wbr>而iterate会先取数据库select id出来，然后一个id一个id的load，如果在缓存里面有，<wbr>就从缓存取，没有的话就去数据库load。假设是读写缓存，<wbr>需要设置：&nbsp;&nbsp;<br />
        &lt;cache usage=&#8220;read-write&#8221;/&gt;&lt;缓存并发策略&gt;</font></li>
        <li><font size="6" face="Calibri">使用二级缓存第三方插件ehcache.jar来实现,<wbr>在hibernate.cfg.xml中配置</font></li>
        <li><font size="6" face="Calibri">如下图:是我测试TestDAO工程的hiberante.<wbr>cfg.xml配置</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri">Hiberante.cfg.xml</font></p>
<p align="center"><font size="7" face="Calibri">ehcache.xml配置</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="6" face="Calibri">&lt;defaultCache&nbsp;&nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; maxElementsInMemory=&#8220;10000&#8221; //在缓存区最大元素 默认为10000；&nbsp;&nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eternal=&#8220;false&#8221;&nbsp; //是否永久不超时 &nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToIdleSeconds=&#8220;120&#8221;&nbsp; // ：缓存数据的钝化时间，也就是在一个元素消亡之前，<wbr>两次访问时间的最大时间间隔值 &nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeToLiveSeconds=&#8220;120&#8221;&nbsp;//<wbr>从创建后存活的最长时间 &nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflowToDisk="true" //溢出到硬盘；&nbsp;&nbsp;<br />
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /&gt;&nbsp;</font></li>
    </ul>
</ul>
&nbsp;<br />
<ul>
    <ul type="DISC">
        <li><font size="6" face="Calibri">每个存储的CLASS都要有这样的配置,如果你没配置,<wbr>Hibernate会警告你,<wbr>然后使用缺省的defaultCache</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri"><strong>查询缓存</strong>&nbsp;</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="5" face="Calibri">需要配置&lt;property name=<em>"hibernate.cache.use_<wbr>query_cache"&gt;true&lt;/property&gt;</em></font></li>
        <li><font size="5" face="Calibri">query.setCacheable(true);//<wbr>激活查询缓存&nbsp;&nbsp;<br />
        query.setCacheRegion(&#8220;<wbr>myCacheRegion&#8221;);//<wbr>指定要使用的cacheRegion,如果不做,<wbr>会使用标准的查询缓存的配置</font></li>
        <li><font size="5" face="Calibri">查询缓存来说，缓存的key是根据hql生成的sql，<wbr>再加上参数，分页等信息</font></li>
        <li><font size="5" face="Calibri"><strong><em>重点</em></strong><em>:</em>如果是list()方式的话，<wbr>value在这里并不是整个结果集，而是查询出来的一串ID.</font></li>
        <li><font size="5" face="Calibri">不管是list方法还是iterate方法，第一次查询的时候，<wbr>它们的查询方式和它们平时的方式是一样的，<wbr>list执行一条sql，iterate执行1+N条，<wbr>多出来的行为是它们填充了缓存。<wbr>但是到同样条件第二次查询的时候，<wbr>就都和iterate的行为一样了，<wbr>根据缓存的key去缓存里面查到了value，<wbr>value是一串id，<wbr>然后在到class的缓存里面去一个一个的load出来。</font></li>
        <li><font size="5" face="Calibri"><em>所以说,</em>查询缓存需要打开相关类的class缓存。<wbr>list和iterate方法第一次执行的时候，<wbr>都是既填充查询缓存又填充class缓存的,还有一点,<wbr>Class缓存的时间一定要比查询缓存长,不然还是会出现N+<wbr>1问题</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri">缓存与数据库同步</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="5" face="Calibri">hibernate在一个地方维护每个表的最后更新时间，<wbr>其实也就是放在上面org.hibernate.cache. UpdateTimestampsCache所指定的缓存配置里<wbr>面。&nbsp;</font></li>
    </ul>
</ul>
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
<ul>
    <ul type="DISC">
        <li><font size="1" face="Calibri">&nbsp;&nbsp;<br />
        </font><font size="5" face="Calibri">当通过hibernate更新的时候，<wbr>hibernate会知道这次更新影响了哪些表。<wbr>然后它更新这些表的最后更新时间。<wbr>每个缓存都有一个生成时间和这个缓存所查询的表，<wbr>当hibernate查询一个缓存是否存在的时候，<wbr>如果缓存存在，它还要取出缓存的生成时间和这个缓存所查询的表，<wbr>然后去查找这些表的最后更新时间，<wbr>如果有一个表在生成时间后更新过了，那么这个缓存是无效的。&nbsp;&nbsp;<br />
        可以看出，只要更新过一个表，<wbr>那么凡是涉及到这个表的查询缓存就失效了，<wbr>因此查询缓存的命中率可能会比较低。</font></li>
    </ul>
</ul>
<p align="center"><font size="7" face="Calibri">使用二级缓存的前置条件</font>&nbsp;<br />
</p>
<ul>
    <ul type="DISC">
        <li><font size="7" face="Calibri">使用hiberante的应用对数据库具有独占访问权,<wbr>既不能被第三方修改数据,因为那样缓存不知道你修改了数据,<wbr>无法与数据库同步.</font></li>
        <li><font size="7" face="Calibri">如果自己程序里使用了JDBC来更新，<wbr>不通过hiberante更新,也会出现跟数据库不同步的情况</font></li>
    </ul>
</ul>
<img src ="http://www.blogjava.net/yuyee/aggbug/336047.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yuyee/" target="_blank">羔羊</a> 2010-10-25 00:30 <a href="http://www.blogjava.net/yuyee/archive/2010/10/25/336047.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>