<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3 ## 9.4? 聲明式事務 ### 9.4.1? 聲明式事務概述 從上節編程式實現事務管理可以深刻體會到編程式事務的痛苦,即使通過代理配置方式也是不小的工作量。 本節將介紹聲明式事務支持,使用該方式后最大的獲益是簡單,事務管理不再是令人痛苦的,而且此方式屬于無侵入式,對業務邏輯實現無影響。 接下來先來看看聲明式事務如何實現吧。 ### 9.4.2? 聲明式實現事務管理 **1、定義業務邏輯實現,此處使用ConfigUserServiceImpl和ConfigAddressServiceImpl:** **2、定義配置文件(chapter9/service/ applicationContext-service-declare.xml):** **2.1、XML命名空間定義,定義用于事務支持的tx命名空間和AOP支持的aop命名空間:** ``` <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> ``` **2.2、業務實現配置,非常簡單,使用以前定義的非侵入式業務實現:** ``` <bean id="userService" class="cn.javass.spring.chapter9.service.impl.ConfigUserServiceImpl"> <property name="userDao" ref="userDao"/> <property name="addressService" ref="addressService"/> </bean> <bean id="addressService" class="cn.javass.spring.chapter9.service.impl.ConfigAddressServiceImpl"> <property name="addressDao" ref="addressDao"/> </bean> ``` **2.3、事務相關配置:** ``` <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED" read-only="true"/> </tx:attributes> </tx:advice> ``` ``` <aop:config> <aop:pointcut id="serviceMethod" expression="execution(* cn..chapter9.service..*.*(..))"/> <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/> </aop:config> ``` * &lt;tx:advice&gt;:事務通知定義,用于指定事務屬性,其中“transaction-manager”屬性指定事務管理器,并通過&lt; tx:attributes &gt;指定具體需要攔截的方法; * &lt;tx:method name="save*"&gt;:表示將攔截以save開頭的方法,被攔截的方法將應用配置的事務屬性:propagation="REQUIRED"表示傳播行為是Required,isolation="READ_COMMITTED"表示隔離級別是提交讀; * &lt;tx:method name="*"&gt;:表示將攔截其他所有方法,被攔截的方法將應用配置的事務屬性:propagation="REQUIRED"表示傳播行為是Required,isolation="READ_COMMITTED"表示隔離級別是提交讀,read-only="true"表示事務只讀; * &lt;aop:config&gt;:AOP相關配置: * &lt;aop:pointcut/&gt;:切入點定義,定義名為"serviceMethod"的aspectj切入點,切入點表達式為"execution(* cn..chapter9.service..*.*(..))"表示攔截cn包及子包下的chapter9\. service包及子包下的任何類的任何方法; * &lt;aop:advisor&gt;:Advisor定義,其中切入點為serviceMethod,通知為txAdvice。 從配置中可以看出,將對cn包及子包下的chapter9\. service包及子包下的任何類的任何方法應用“txAdvice”通知指定的事務屬性。 **3、修改測試方法并測試該配置方式是否好用:** 將TransactionTest 類的testServiceTransaction測試方法拷貝一份命名為testDeclareTransaction: 并在testDeclareTransaction測試方法內將: ``` classpath:chapter9/service/applicationContext-service.xml" ``` 替換為: ``` classpath:chapter9/service/applicationContext-service-declare.xml" ``` **4、執行測試,測試正常通過,說明該方式能正常工作,**當調用save方法時將匹配到事務通知中定義的“&lt;tx:method name="save*"&gt;”中指定的事務屬性,而調用countAll方法時將匹配到事務通知中定義的“&lt;tx:method name="*"&gt;”中指定的事務屬性。 聲明式事務是如何實現事務管理的呢?還記不記得TransactionProxyFactoryBean實現配置式事務管理,配置式事務管理是通過代理方式實現,而聲明式事務管理同樣是通過AOP代理方式實現。 聲明式事務通過AOP代理方式實現事務管理,利用環繞通知TransactionInterceptor實現事務的開啟及關閉,而TransactionProxyFactoryBean內部也是通過該環繞通知實現的,因此可以認為是&lt;tx:tags/&gt;幫你定義了TransactionProxyFactoryBean,從而簡化事務管理。 了解了實現方式后,接下來詳細學習一下配置吧: ### 9.4.4? &lt;tx:advice/&gt;配置詳解 聲明式事務管理通過配置&lt;tx:advice/&gt;來定義事務屬性,配置方式如下所示: ``` <tx:advice id="……" transaction-manager="……"> <tx:attributes> <tx:method name="……" propagation=" REQUIRED" isolation="READ_COMMITTED" timeout="-1" read-only="false" no-rollback-for="" rollback-for=""/> …… </tx:attributes> </tx:advice> ``` * **&lt;tx:advice&gt;:**id用于指定此通知的名字, transaction-manager用于指定事務管理器,默認的事務管理器名字為“transactionManager”; * &lt;tx:method&gt;:用于定義事務屬性即相關聯的方法名; **name:**定義與事務屬性相關聯的方法名,將對匹配的方法應用定義的事務屬性,可以使用“*”通配符來匹配一組或所有方法,如“save*”將匹配以save開頭的方法,而“*”將匹配所有方法; **pro**pagation:事務傳播行為定義,默認為“REQUIRED”,表示Required,其值可以通過TransactionDefinition的靜態傳播行為變量的“PROPAGATION_”后邊部分指定,如“TransactionDefinition.PROPAGATION_REQUIRED”可以使用“REQUIRED”指定; isolation:事務隔離級別定義;默認為“DEFAULT”,其值可以通過TransactionDefinition的靜態隔離級別變量的“ISOLATION_”后邊部分指定,如“TransactionDefinition. ISOLATION_DEFAULT”可以使用“DEFAULT”指定: **timeout:**事務超時時間設置,單位為秒,默認-1,表示事務超時將依賴于底層事務系統; **read-only:**事務只讀設置,默認為false,表示不是只讀; **rollback-for:**需要觸發回滾的異常定義,以“,”分割,默認任何RuntimeException 將導致事務回滾,而任何Checked Exception 將不導致事務回滾;異常名字定義和TransactionProxyFactoryBean中含義一樣 **no-rollback-for:**不被觸發進行回滾的 Exception(s);以“,”分割;異常名字定義和TransactionProxyFactoryBean中含義一樣; 記不記得在配置方式中為了解決“自我調用”而導致的不能設置正確的事務屬性問題,使用“**((IUserService)AopContext.currentProxy()).otherTransactionMethod()”**方式解決,在聲明式事務要得到支持需要使用&lt;aop:config expose-proxy="true"&gt;來開啟。 ### 9.4.5? 多事務語義配置及最佳實踐 什么是多事務語義?說白了就是為不同的Bean配置不同的事務屬性,因為我們項目中不可能就幾個Bean,而可能很多,這可能需要為Bean分組,為不同組的Bean配置不同的事務語義。在Spring中,可以通過配置多切入點和多事務通知并通過不同方式組合使用即可。 **?????? 1、首先看下聲明式事務配置的最佳實踐吧:** ``` <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config> ``` 該聲明式事務配置可以應付常見的CRUD接口定義,并實現事務管理,我們只需修改切入點表達式來攔截我們的業務實現從而對其應用事務屬性就可以了,如果還有更復雜的事務屬性直接添加即可,即 如果我們有一個batchSaveOrUpdate方法需要“REQUIRES_NEW”事務傳播行為,則直接添加如下配置即可: ``` <tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" /> ``` **2、接下來看一下多事務語義配置吧,**聲明式事務最佳實踐中已經配置了通用事務屬性,因此可以針對需要其他事務屬性的業務方法進行特例化配置: ``` <tx:advice id="noTxAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" propagation="NEVER" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="noTxPointcut" expression="execution(* cn.javass..util.*.*())" /> <aop:advisor advice-ref="noTxPointcut" pointcut-ref="noTxAdvice" /> </aop:config> ``` 該聲明將對切入點匹配的方法所在事務應用“Never”傳播行為。 多事務語義配置時,切入點一定不要疊加,否則將應用兩次事務屬性,造成不必要的錯誤及麻煩。 ### 9.4.6? @Transactional實現事務管理 對聲明式事務管理,Spring提供基于@Transactional注解方式來實現,但需要Java 5+。 注解方式是最簡單的事務配置方式,可以直接在Java源代碼中聲明事務屬性,且對于每一個業務類或方法如果需要事務都必須使用此注解。 接下來學習一下注解事務的使用吧: **1、定義業務邏輯實現:** ``` package cn.javass.spring.chapter9.service.impl; //省略import public class AnnotationUserServiceImpl implements IUserService { private IUserDao userDao; private IAddressService addressService; public void setUserDao(IUserDao userDao) { this.userDao = userDao; } public void setAddressService(IAddressService addressService) { this.addressService = addressService; } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED) @Override public void save(final UserModel user) { userDao.save(user); user.getAddress().setUserId(user.getId()); addressService.save(user.getAddress()); } @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED, readOnly=true) @Override public int countAll() { return userDao.countAll(); } } ``` **2、定義配置文件(chapter9/service/ applicationContext-service-annotation.xml):** **2.1、XML命名空間定義,定義用于事務支持的tx命名空間和AOP支持的aop命名空間:** ``` <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> ``` **2.2、業務實現配置,非常簡單,使用以前定義的非侵入式業務實現:** ``` <bean id="userService" class="cn.javass.spring.chapter9.service.impl.ConfigUserServiceImpl"> <property name="userDao" ref="userDao"/> <property name="addressService" ref="addressService"/> </bean> <bean id="addressService" class="cn.javass.spring.chapter9.service.impl.ConfigAddressServiceImpl"> <property name="addressDao" ref="addressDao"/> </bean> ``` **2.3、事務相關配置:** ``` <tx:annotation-driven transaction-manager="txManager"/> ``` 使用如上配置已支持聲明式事務。 **3、修改測試方法并測試該配置方式是否好用:** 將TransactionTest 類的testServiceTransaction測試方法拷貝一份命名為testAnntationTransactionTest: 將測試代碼片段: ``` classpath:chapter9/service/applicationContext-service.xml" ``` 替換為: ``` classpath:chapter9/service/applicationContext-service-annotation.xml" ``` 將測試代碼段 ``` userService.save(user); ``` **替換為:** ``` try { userService.save(user); Assert.fail(); } catch (RuntimeException e) { } Assert.assertEquals(0, userService.countAll()); Assert.assertEquals(0, addressService.countAll()); ``` **4、執行測試,測試正常通過,說明該方式能正常工作,**因為在AnnotationAddressServiceImpl類的save方法中拋出異常,因此事務需要回滾,所以兩個countAll操作都返回0。 ### 9.4.7? @Transactional配置詳解 Spring提供的&lt;tx:annotation-driven/&gt;用于開啟對注解事務管理的支持,從而能識別Bean類上的@Transactional注解元數據,其具有以下屬性: * transaction-manager:指定事務管理器名字,默認為transactionManager,當使用其他名字時需要明確指定; * proxy-target-class:表示將使用的代碼機制,默認false表示使用JDK代理,如果為true將使用CGLIB代理 * order:定義事務通知順序,默認Ordered.LOWEST_PRECEDENCE,表示將順序決定權交給AOP來處理。 Spring使用@Transaction來指定事務屬性,可以在接口、類或方法上指定,如果類和方法上都指定了@Transaction,則方法上的事務屬性被優先使用,具體屬性如下: * value:指定事務管理器名字,默認使用&lt;tx:annotation-driven/&gt;指定的事務管理器,用于支持多事務管理器環境; * **propagation**:指定事務傳播行為,默認為Required,使用Propagation.REQUIRED指定; * **isolation**:指定事務隔離級別,默認為“DEFAULT”,使用Isolation.DEFAULT指定; * **readOnly**:指定事務是否只讀,默認false表示事務非只讀; * **timeout**:指定事務超時時間,以秒為單位,默認-1表示事務超時將依賴于底層事務系統; * **rollbackFor**:指定一組異常類,遇到該類異常將回滾事務; * **rollbackForClassname**:指定一組異常類名字,其含義與&lt;tx:method&gt;中的rollback-for屬性語義完全一樣; * **noRollbackFor**:指定一組異常類,即使遇到該類異常也將提交事務,即不回滾事務; * **noRollbackForClassname**:指定一組異常類名字,其含義與&lt;tx:method&gt;中的no-rollback-for屬性語義完全一樣; Spring提供的@Transaction注解事務管理內部同樣利用環繞通知TransactionInterceptor實現事務的開啟及關閉。 使用@Transactional注解事務管理需要特別注意以下幾點: * 如果在接口、實現類或方法上都指定了@Transactional 注解,則優先級順序為方法&gt;實現類&gt;接口; * 建議只在實現類或實現類的方法上使用@Transactional,而不要在接口上使用,這是因為如果使用JDK代理機制是沒問題,因為其使用基于接口的代理;而使用使用CGLIB代理機制時就會遇到問題,因為其使用基于類的代理而不是接口,這是**因為接口上的@Transactional注解是“不能繼承的”**; 具體請參考[基于JDK動態代理和CGLIB動態代理的實現Spring注解管理事務(@Trasactional)到底有什么區別。](http://www.iteye.com/topic/1121357) * 在Spring代理機制下(不管是JDK動態代理還是CGLIB代理),“自我調用”同樣不會應用相應的事務屬性,其語義和&lt;tx:tags&gt;中一樣; * 默認只對RuntimeException異常回滾; * 在使用Spring代理時,默認只有在public可見度的方法的@Transactional 注解才是有效的,其它可見度(protected、private、包可見)的方法上即使有@Transactional 注解也不會應用這些事務屬性的,Spring也不會報錯,如果你非要使用非公共方法注解事務管理的話,可考慮使用AspectJ。 ### 9.4.9? 與其他AOP通知協作 Spring聲明式事務實現其實就是Spring AOP+線程綁定實現,利用AOP實現開啟和關閉事務,利用線程綁定(ThreadLocal)實現跨越多個方法實現事務傳播。 由于我們不可能只使用一個事務通知,可能還有其他類型事務通知,而且如果這些通知中需要事務支持怎么辦?這就牽扯到通知執行順序的問題上了,因此如果可能與其他AOP通知協作的話,而且這些通知中需要使用聲明式事務管理支持,事務通知應該具有最高優先級。 ### 9.4.10? 聲明式or編程式 編程式事務時不推薦的,即使有很少事務操作,Spring發展到現在,沒有理由使用編程式事務,只有在為了深入理解Spring事務管理才需要學習編程式事務使用。 推薦使用聲明式事務,而且強烈推薦使用&lt;tx:tags&gt;方式的聲明式事務,因為其是無侵入代碼的,可以配置模板化的事務屬性并運用到多個項目中。 而@Transaction注解事務,可以使用,不過作者更傾向于使用&lt;tx:tags&gt;聲明式事務。 能保證項目正常工作的事務配置就是最好的。 ### 9.4.11? 混合事務管理 所謂混合事務管理就是混合多種數據訪問技術使用,如混合使用Spring JDBC + Hibernate,接下來讓我們學習一下常見混合事務管理: 1、? Hibernate + Spring JDBC/iBATIS:使用HibernateTransactionManager即可支持; 2、? JPA + Spring JDBC/iBATIS:使用JpaTransactionManager即可支持; 3、? JDO + Spring JDBC/iBATIS:使用JtaTransactionManager即可支持; 混合事務管理最大問題在于如果我們使用第三方ORM框架,如Hibernate,會遇到一級及二級緩存問題,尤其是二級緩存可能造成如使用Spring JDBC和Hibernate查詢出來的數據不一致等。 因此不建議使用這種混合使用和混合事務管理。 原創內容,轉載請注明出處【[http://sishuok.com/forum/blogPost/list/0/2508.html](http://sishuok.com/forum/blogPost/list/0/2508.html#7228)】
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看