生活随笔
收集整理的這篇文章主要介紹了
spring的annotation-driven配置事务管理器详解
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
來源:http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html
這篇文章是我從ITeye上復(fù)制來的,看了一遍,覺得很深刻,決定把他復(fù)制來,對原作者表示感謝。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
本文僅基于3.0+版本作為測試) 假定spring?容器中定義了兩個事務(wù)管理器:
transactionManagerX,
transactionManagerY,分管兩個數(shù)據(jù)源datasourceX和datasourceY. <tx:annotation-driven?transaction-manager="transactionManagerX"?/> <tx:annotation-driven?transaction-manager="transactionManagerY"?/> (spring容器中的定義順序如上) 有如下應(yīng)用代碼: public?interface?TestEntityService?{ public?void?methodX(); public?void?methodY(); } 接口實(shí)現(xiàn)類1 public?class?
TestEntityServiceImpl?implements?TestEntityService?{ @Resource private?TestEntityDao?testEntityDao;//實(shí)際操作的是
datasourceX. @Transactional public?void?methodX()?{ testEntityDao.xxx(); testEntityDao.zzz(); } public?void?methodY()?{ } } 接口實(shí)現(xiàn)類2 public?class?
AnotherTestEntityServiceImpl?implements?TestEntityService?{ @Resource private?TestEntityDao?anOtherTestEntityDao;//實(shí)際操作的是
datasourceY. @Transactional public?void?methodX()?{ testEntityDao.mmm(); testEntityDao.nnn(); } public?void?methodY()?{ } } 假設(shè)方法methodX需要事務(wù)控制的,通常我們是直接在方法上添加@Transactional標(biāo)注, 但是好像spring3.0(具體版本沒弄清)之前的Transactional標(biāo)注不支持區(qū)分使用哪個事務(wù)管理器。3.0之后的版本Transactional增加了個string類型的value屬性來特殊指定加以區(qū)分。 例如@Transactional("
aaaaa"),即顯示的要求spring用id="
aaaaa"的事務(wù)管理器來管理事務(wù)。該屬性亦可省略(省略的話用容器中缺省的transactionManager) 對于該屬性的用法做了如下測試來
| methodX()事務(wù)生效測試結(jié)果 | @Transactional ("transactionManagerX") ? | @Transactional ("transactionManagerY") ? | @Transactional ("transactionManagerZ") transactionManagerZ為未定義過的 | @Transactional?? |
| TestEntityServiceImpl(實(shí)際使用datasourceX) | Y | N | Y | Y |
| AnotherTestEntityServiceImpl?(實(shí)際使用datasourceY) | N | Y | N | N |
如果調(diào)換兩個事務(wù)管理器在容器中的定義順序,如 <tx:annotation-driven?transaction-manager="transactionManagerY"?/> <tx:annotation-driven?transaction-manager="transactionManagerX"?/> 得到的結(jié)果
| methodX()事務(wù)生效測試結(jié)果 | @Transactional ("transactionManagerX") ? | @Transactional ("transactionManagerY") ? | @Transactional ("transactionManagerZ") transactionManagerZ為未定義過的 | @Transactional?? |
| TestEntityServiceImpl(實(shí)際使用datasourceX) | Y | N | N | N |
| AnotherTestEntityServiceImpl?(實(shí)際使用datasourceY) | N | Y | Y | Y |
分析結(jié)果(其實(shí)源碼就可以反應(yīng)出):容器指定一個默認(rèn)的事務(wù)管理器 ? 1.當(dāng)在@Transactional("xxx")中正確指定了需要使用的事務(wù)管理器時,事務(wù)控制正常。 2.如果@Transactional指定了未定義過的事務(wù)管理器,spring以缺省默認(rèn)的事務(wù)管理器來處理。(如果程序正好使用的是缺省事務(wù)管理器同一個數(shù)據(jù)源,事務(wù)控制將生效)。 3.如果@Transactional不指定事務(wù)管理器,使用缺省。 4.如果@Transactional指定了不匹配的事務(wù)管理器(實(shí)際用到的數(shù)據(jù)源和指定的事務(wù)管理器控制的數(shù)據(jù)源不一致),事務(wù)控制將失效.
注:spring容器缺省事務(wù)管理器:以加載順序,首先加載的作為缺省。例如 如果 <tx:annotation-driven?transaction-manager="transactionManagerX"?/> <tx:annotation-driven?transaction-manager="transactionManagerY"?/> 定義在同一個文件中,則第一個transactionManagerX作為缺省。 定義在不同文件,則按文件的加載順序,首先加載的作為缺省。
建議:實(shí)際代碼中需要用到@Transactional時,即使默認(rèn)只有一個transactionManager,@Transactional也將其標(biāo)明。以提高新增數(shù)據(jù)源后代碼可讀性,另外防止定義多個數(shù)據(jù)源后,以前缺省的不被spring默認(rèn)為缺省了(比如哪天上線新定義了一個數(shù)據(jù)源,剛好新定義的transactionManager被先加載了,那就悲劇了。) ? ? 二.bean的配置使用 容器中加了<tx:annotation-driven?>(需要增加一些xsd)之后,需要事務(wù)控制的的service,不需要再具體的bean上做其他的配置,例如用代理包裝。直接配置即可 <bean?id="testEntityService"?class="com.xxx.impl.TestEntityServiceImpl"/> spring將由JdkDynamicAopProxy 生成代理過的類提供使用。 這種用法的效果和下面配置使用效果一樣。都是由JdkDynamicAopProxy 生成代理對象提供使用。 我覺得區(qū)別是下面的方法在事務(wù)控制的代碼可讀性上不好,因?yàn)槟膫€方法需要事務(wù)控制和控制粒度都在配置文件中,和代碼分開了。 <bean?id="testEntityService3"?class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> ?????<property?name="transactionManager"?ref="transactionManagerX"?/> ?????<property?name="target"> ????????<bean?class="com.xxxx.impl.TestEntityServiceImpl"?/> ?????</property> ?????<property?name="proxyInterfaces"?value="com.xxxx.TestEntityService"/> ?????<property?name="transactionAttributes"> ????????<props> ??????????<prop?key="*">PROPAGATION_REQUIRED</prop> ????????</props> ?????</property> </bean> 方法的可見度和?@Transactional @Transactional?注解應(yīng)該只被應(yīng)用到?public?可見度的方法上。?如果你在?protected、private?或者?package-visible?的方法上使用?@Transactional?注解,它也不會報(bào)錯,?但是這個被注解的方法將不會展示已配置的事務(wù)設(shè)置。 @Transactional?注解可以被應(yīng)用于接口定義和接口方法、類定義和類的?public?方法上。然而,請注意僅僅?@Transactional?注解的出現(xiàn)不足于開啟事務(wù)行為,它僅僅?是一種元數(shù)據(jù),能夠被可以識別?@Transactional?注解和上述的配置適當(dāng)?shù)木哂惺聞?wù)行為的beans所使用。上面的例子中,其實(shí)正是?<tx:annotation-driven/>元素的出現(xiàn)?開啟?了事務(wù)行為。 Spring團(tuán)隊(duì)的建議是你在具體的類(或類的方法)上使用?@Transactional?注解,而不要使用在類所要實(shí)現(xiàn)的任何接口上。你當(dāng)然可以在接口上使用?@Transactional?注解,但是這將只能當(dāng)你設(shè)置了基于接口的代理時它才生效。因?yàn)樽⒔馐?不能繼承?的。 實(shí)際開發(fā)中,多半喜歡將持久化操作的代碼集中抽出為另一個方法(因?yàn)椴幌胧聞?wù)被無關(guān)的業(yè)務(wù)代碼托的持續(xù)太長),然后在抽取出來的方法上加上@Transactional,這樣的結(jié)果是被抽離出的代碼即使加了事務(wù)標(biāo)記,也根本起不到事務(wù)控制的效果(不管是private和public)。 例如: public?class?TestEntityServiceImpl?implements?TestEntityService?{ @Resource private?TestEntityDao?testEntityDao;//實(shí)際操作的是datasourceX. @Transactional public?void?methodX()?{ testEntityDao.xxx(); testEntityDao.zzz(); } public?void?methodY()?{ methodX()? } } 如果執(zhí)行TestEntityService.methodY();事務(wù)是不生效的。只有TestEntityService.methodY();才生效。 從spring實(shí)現(xiàn)這些的原理(動態(tài)代理和aop)上來看,只攔截外部調(diào)用,方法的內(nèi)部調(diào)用通常是不被aop支持的。 從網(wǎng)上扒到一篇文章,可以解決這個問題。
http://blog.csdn.net/quzishen/archive/2010/08/11/5803721.aspx
總結(jié)
以上是生活随笔為你收集整理的spring的annotation-driven配置事务管理器详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。