spring中事务配置的3种方式-2
http://doc.javanb.com/spring-framework-reference-zh-2-0-5/ch09s05.html
http://zpchen.iteye.com/blog/1026473
http://slsjhs.com/read/8annotation-20driven.html
(3)、<tx:annotation-driven /> @Transactional 注解可以被應用于接口定義和接口方法、類定義和類的 public 方法上。 Spring團隊的建議是你在具體的類(或類的...今天配置spring 是碰到tx:annotation-driven is not bound 的問題,網上搜到,特意記錄下來。 http://blog.csdn.net/gabriel80/archive/2008/05/29/2492608.aspx ...
The prefix "tx" for element "tx:annotation-driven " is not bound 今天配置spring 是碰到tx:annotation-driven is not bound 的問題,這個錯誤的原因很簡單是...在springmvc配置文件里面寫默認的注解映射的支持的時候:<mvc:annotation-driven />The prefix "mvc" for element "mvc:annotation-driven" is not bound。 解決...
所以要去掉<mvc:annotation-driven />,去掉其默認配置, 否則會實例化兩個DefaultAnnotationHandlerMapping,并且不使用你配置的那個 DefaultAnnotationHandlerMapping. ... According to my spring mvc knowledge <mvc:annotation-driven/> and <context:annotation-config/> these both are used to detect the annotations like @...
While I will probably chose to not use any annotation driven dependency injection, somebody else may work primarily with annotations, and then fall back ... [B]How do I extract and add the needed parts of <mvc:annotation-driven/> to return JSON from the controller?[/B] Here are the pertinent parts ...
Spring MVC的一例低級錯誤:Element 'mvc:annotation-driven' must have no character or element information item [children], because the type's content type ... <mvc:annotation-driven/> 同樣可以達到以上的結果。 2.在controller中我們是這樣配置的: package com.yx.controller.annotation; import org.springframework....
?
9.5.?聲明式事務管理
大多數Spring用戶選擇聲明式事務管理。這是對應用代碼影響最小的選擇,因此也最符合 非侵入式 輕量級容器的理念。
Spring的聲明式事務管理是通過Spring AOP實現的,因為事務方面的代碼與Spring綁定并以一種樣板式風格使用,不過盡管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的聲明式事務管理。
從考慮EJB CMT和Spring聲明式事務管理的相似以及不同之處出發是很有益的。它們的基本方法是相似的:都可以指定事務管理到單獨的方法;如果需要可以在事務上下文調用setRollbackOnly() 方法。不同之處在于:
-
不像EJB CMT綁定在JTA上,Spring聲明式事務管理可以在任何環境下使用。只需更改配置文件,它就可以和JDBC、JDO、Hibernate或其他的事務機制一起工作。
-
Spring的聲明式事務管理可以被應用到任何類(以及那個類的實例)上,不僅僅是像EJB那樣的特殊類。
-
Spring提供了聲明式的回滾規則:EJB沒有對應的特性,我們將在下面討論。回滾可以聲明式的控制,不僅僅是編程式的。
-
Spring允許你通過AOP定制事務行為。例如,如果需要,你可以在事務回滾中插入定制的行為。你也可以增加任意的通知,就象事務通知一樣。使用EJB CMT,除了使用setRollbackOnly(),你沒有辦法能夠影響容器的事務管理。
-
Spring不提供高端應用服務器提供的跨越遠程調用的事務上下文傳播。如果你需要這些特性,我們推薦你使用EJB。然而,不要輕易使用這些特性。通常我們并不希望事務跨越遠程調用。
TransactionProxyFactoryBean在哪兒?
Spring2.0及以后的版本中聲明式事務的配置與之前的版本有相當大的不同。主要差異在于不再需要配置TransactionProxyFactoryBean了。
Spring2.0之前的舊版本風格的配置仍然是有效的;你可以簡單地認為新的<tx:tags/>替你定義了TransactionProxyFactoryBean。
回滾規則的概念比較重要:它使我們能夠指定什么樣的異常(和throwable)將導致自動回滾。我們在配置文件中聲明式地指定,無須在Java代碼中。同時,我們仍舊可以通過調用TransactionStatus 的 setRollbackOnly() 方法編程式地回滾當前事務。通常,我們定義一條規則,聲明MyApplicationException 必須總是導致事務回滾。這種方式帶來了顯著的好處,它使你的業務對象不必依賴于事務設施。典型的例子是你不必在代碼中導入Spring API,事務等。
對EJB來說,默認的行為是EJB容器在遇到 系統異常(通常指運行時異常)時自動回滾當前事務。EJB CMT遇到應用異常(例如,除了 java.rmi.RemoteException 外別的checked exception)時并不會自動回滾。默認式Spring處理聲明式事務管理的規則遵守EJB習慣(只在遇到unchecked exceptions時自動回滾),但通常定制這條規則會更有用。
9.5.1.?理解Spring的聲明式事務管理實現
本節的目的是消除與使用聲明式事務管理有關的神秘性。簡單點兒總是好的,這份參考文檔只是告訴你給你的類加上@Transactional注解,在配置文件中添加('<tx:annotation-driven/>')行,然后期望你理解整個過程是怎么工作的。此節講述Spring的聲明式事務管理內部的工作機制,以幫助你在面對事務相關的問題時不至于誤入迷途,回朔到上游平靜的水域。
提示
閱讀Spring源碼是理解清楚Spring事務支持的一個好方法。Spring的Javadoc提供的信息豐富而完整。我們建議你在開發自己的Spring應用時把日志級別設為'DEBUG'級,這樣你能更清楚地看到幕后發生的事。
在理解Spring的聲明式事務管理方面最重要的概念是:Spring的事務管理是通過AOP代理實現的。其中的事務通知由元數據(目前基于XML或注解)驅動。代理對象與事務元數據結合產生了一個AOP代理,它使用一個PlatformTransactionManager實現品配合TransactionInterceptor,在方法調用前后實施事務。
注意
盡管使用Spring聲明式事務管理不需要AOP(尤其是Spring AOP)的知識,但了解這些是很有幫助的。你可以在 第?6?章 使用Spring進行面向切面編程(AOP) 章找到關于Spring AOP的全部內容。
概念上來說,在事務代理上調用方法的工作過程看起來像這樣:
9.5.2.?第一個例子
請看下面的接口和它的實現。這個例子的意圖是介紹概念,使用 Foo 和 Bar 這樣的名字只是為了讓你關注于事務的用法,而不是領域模型。
<!-- 我們想做成事務性的服務接口 -->package x.y.service;public interface FooService {Foo getFoo(String fooName);Foo getFoo(String fooName, String barName);void insertFoo(Foo foo);void updateFoo(Foo foo);} <!-- 上述接口的一個實現 -->package x.y.service;public class DefaultFooService implements FooService {public Foo getFoo(String fooName) {throw new UnsupportedOperationException();}public Foo getFoo(String fooName, String barName) {throw new UnsupportedOperationException();}public void insertFoo(Foo foo) {throw new UnsupportedOperationException();}public void updateFoo(Foo foo) {throw new UnsupportedOperationException();} }(對該例的目的來說,上例中實現類(DefaultFooService)的每個方法在其方法體中拋出UnsupportedOperationException 的做法是恰當的,我們可以看到,事務被創建出來,響應UnsupportedOperationException 的拋出,然后回滾。)
我們假定,FooService的前兩個方法(getFoo(String)和getFoo(String, String))必須執行在只讀事務上下文中,其余方法(insertFoo(Foo)和updateFoo(Foo))必須執行在讀寫事務上下文中。
使用XML方式元數據的聲明式配置的話,你得這么寫(不要想著一次全部理解,所有內容會在后面的章節詳細討論):
<!-- 'context.xml'文件的內容如下: --> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><!-- 這是我們將要配置并使它具有事務性的Service對象 --><bean id="fooService" class="x.y.service.DefaultFooService"/><!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) --><tx:advice id="txAdvice" transaction-manager="txManager"><!-- the transactional semantics... --><tx:attributes><!-- all methods starting with 'get' are read-only --><tx:method name="get*" read-only="true"/><!-- other methods use the default transaction settings (see below) --><tx:method name="*"/></tx:attributes></tx:advice><!-- ensure that the above transactional advice runs for any executionof an operation defined by the FooService interface --><aop:config><aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/></aop:config><!-- don't forget the DataSource --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/><property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/><property name="username" value="scott"/><property name="password" value="tiger"/></bean><!-- similarly, don't forget the (particular) PlatformTransactionManager --><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- other <bean/> definitions here --> </beans>我們來分析一下上面的配置。我們要把一個服務對象('fooService' bean)做成事務性的。我們想施加的事務語義封裝在<tx:advice/>定義中。<tx:advice/> “把所有以'get' 開頭的方法看做執行在只讀事務上下文中,其余的方法執行在默認語義的事務上下文中”。 其中的'transaction-manager' 屬性被設置為一個指向 PlatformTransactionManager bean的名字(這里指 'txManager'),該bean將實際上實施事務管理。
提示
事實上,如果 PlatformTransactionManager bean的名字是 'transactionManager' 的話,你的事務通知(<tx:advice/>)中的'transaction-manager' 屬性可以忽略。否則你則需要像上例那樣明確指定。
配置中最后一段是 <aop:config/> 的定義,它確保由 'txAdvice' bean定義的事務通知在應用中合適的點被執行。首先我們定義了 一個切面,它匹配 FooService 接口定義的所有操作,我們把該切面叫做 'fooServiceOperation'。然后我們用一個通知器(advisor)把這個切面與'txAdvice' 綁定在一起,表示當 'fooServiceOperation' 執行時,'txAdvice' 定義的通知邏輯將被執行。
<aop:pointcut/> 元素定義是AspectJ的切面表示法,可參考Spring 2.0 第?6?章 使用Spring進行面向切面編程(AOP)章獲得更詳細的內容。
一個普遍性的需求是讓整個服務層成為事務性的。滿足該需求的最好方式是讓切面表達式匹配服務層的所有操作方法。例如:
<aop:config><aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/></aop:config>(這個例子中假定你所有的服務接口定義在 'x.y.service' 包中。你同樣可以參考第?6?章 使用Spring進行面向切面編程(AOP) 章獲得更詳細內容。)
現在,既然我們已經分析了整個配置,你可能會問了,“好吧,但是所有這些配置做了什么?”。
上面的配置將為由 'fooService' 定義的bean創建一個代理對象,這個代理對象被裝配了事務通知,所以當它的相應方法被調用時,一個事務將被啟動、掛起、被標記為只讀,或者其它(根據該方法所配置的事務語義)。
我們來看看下面的例子,測試一下上面的配置。
public final class Boot {public static void main(final String[] args) throws Exception {ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);FooService fooService = (FooService) ctx.getBean("fooService");fooService.insertFoo (new Foo());} }運行上面程序的輸出結果看起來像這樣(注意為了清楚起見,Log4J的消息和從 DefaultFooService 的insertFoo(..) 方法拋出的 UnsupportedOperationException 異常堆棧信息被省略了)。
<!-- Spring容器開始啟動... --> [AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxyfor bean 'fooService' with 0 common interceptors and 1 specific interceptors<!-- the DefaultFooService is actually proxied --> [JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]<!-- ... the insertFoo(..) method is now being invoked on the proxy -->[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo<!-- the transactional advice kicks in here... --> [DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo] [DataSourceTransactionManager] - Acquired Connection[org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction<!-- the insertFoo(..) method from DefaultFooService throws an exception... --> [RuleBasedTransactionAttribute] - Applying rules to determine whether transaction shouldrollback on java.lang.UnsupportedOperationException [TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoodue to throwable [java.lang.UnsupportedOperationException]<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) --> [DataSourceTransactionManager] - Rolling back JDBC transaction on Connection[org.apache.commons.dbcp.PoolableConnection@a53de4] [DataSourceTransactionManager] - Releasing JDBC Connection after transaction [DataSourceUtils] - Returning JDBC Connection to DataSourceException in thread "main" java.lang.UnsupportedOperationExceptionat x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)<!-- AOP infrastructure stack trace elements removed for clarity -->at $Proxy0.insertFoo(Unknown Source)at Boot.main(Boot.java:11)9.5.3.?回滾
在前面的章節里,概述了如何在你的應用里為類特別是服務層的類指定事務性的基本方法。這一章將描述在一個簡單的聲明式配置中如何你才能控制事務的回滾。
一個容易的(和被推薦的)方法是在Spring框架的事務架構里指出當context的事務里的代碼拋出 Exception 時事務進行回滾。Spring框架的事務基礎架構代碼將從調用的堆棧里捕獲到任何未處理的 Exception,并將標識事務將回滾。
然而,請注意Spring框架的事務基礎架構代碼將默認地 只 在拋出運行時和unchecked exceptions時才標識事務回滾。 也就是說,當拋出一個RuntimeException 或其子類例的實例時。(Errors 也一樣 - 默認地 - 標識事務回滾。)從事務方法中拋出的Checked exceptions將不 被標識進行事務回滾。
就是這些默認的設置;嚴格規定了哪些 Exception 類型將被標識進行事務回滾。 下面的XML配置片斷里示范了如何配置一個checked,應用程序指定的Exception 類型來標識事務回滾。
<tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="get*" read-only="false" rollback-for="NoProductInStockException"/><tx:method name="*"/></tx:attributes> </tx:advice>第二方法是在Spring框架的事務架構里通過 編程式 方式指出一個事務將被回滾。 雖然這個非常簡單,但是這個方法對于Spring框架的事務架構來說,在你的代碼是高入侵的和緊藕合的 下面的代碼片斷里示范了Spring框架管理事務的編程式回滾:
public void resolvePosition() {try {// some business logic...} catch (NoProductInStockException ex) {// trigger rollback programmaticallyTransactionAspectSupport.currentTransactionStatus().setRollbackOnly();} }強烈推薦你盡可能地使用聲明式事務回滾方法。 編程式方法的回滾對你來說是可見,如果你需要它你就可以使用,但是使用它就直接違反了在你的應用中使用一個純基于POJO的模型。
9.5.4.?為不同的bean配置不同的事務語義
現在我們考慮一下這樣的場景,你有許多服務對象,而且想為不同組的對象設置 完全不同 的事務語義。在Spring中,你可以通過定義各自特定的<aop:advisor/> 元素,每個advisor采用不同的 'pointcut' 和 'advice-ref' 屬性,來達到目的。
借助于一個例子,我們假定你所有的服務層類定義在以 'x.y.service' 為根的包內。為了讓service包(或子包)下所有名字以'Service' 結尾的類的對象擁有默認的事務語義,你可以配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><aop:config><aop:pointcut id="serviceOperation" expression="execution(* x.y.service..*Service.*(..))"/><aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><!-- these two beans will be transactional... --> <bean id="fooService" class="x.y.service.DefaultFooService"/> <bean id="barService" class="x.y.service.extras.SimpleBarService"/><!-- ...and these two beans won't --> <bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) --><bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') --><tx:advice id="txAdvice"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice><!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... --></beans>下面的配置示例演示了兩個不同的bean擁有完全不同的事務配置。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><aop:config><aop:pointcut id="defaultServiceOperation" expression="execution(* x.y.service.*Service.*(..))"/><aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/><aop:pointcut id="noTxServiceOperation" expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/><aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/></aop:config><!-- this bean will be transactional (c.f. the 'defaultServiceOperation' pointcut) --><bean id="fooService" class="x.y.service.DefaultFooService"/><!-- this bean will also be transactional, but with totally different transactional settings --><bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/><tx:advice id="defaultTxAdvice"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice><tx:advice id="noTxAdvice"><tx:attributes><tx:method name="*" propagation="NEVER"/></tx:attributes></tx:advice><!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... --></beans>9.5.5.?<tx:advice/> 有關的設置
這一節里將描述通過 <tx:advice/> 標簽來指定不同的事務性設置。默認的 <tx:advice/> 設置如下:
-
事務傳播設置是 REQUIRED
-
隔離級別是 DEFAULT
-
事務是 讀/寫
-
事務超時默認是依賴于事務系統的,或者事務超時沒有被支持。
-
任何 RuntimeException 將觸發事務回滾,但是任何 checked Exception 將不觸發事務回滾
這些默認的設置當然也是可以被改變的。 <tx:advice/> 和 <tx:attributes/> 標簽里的 <tx:method/> 各種屬性設置總結如下:
表?9.1.?<tx:method/> 有關的設置
| name | 是 | ? | 與事務屬性關聯的方法名。通配符(*)可以用來指定一批關聯到相同的事務屬性的方法。 如:'get*'、'handle*'、'on*Event'等等。 |
| propagation | 不 | REQUIRED | 事務傳播行為 |
| isolation | 不 | DEFAULT | 事務隔離級別 |
| timeout | 不 | -1 | 事務超時的時間(以秒為單位) |
| read-only | 不 | false | 事務是否只讀? |
| rollback-for | 不 | ? | 將被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException' |
| no-rollback-for | 不 | ? | 不 被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException' |
9.5.6.?使用@Transactional
注意
@Transactional 注解及其支持類所提供的功能最低要求使用Java 5(Tiger)。
除了基于XML文件的聲明式事務配置外,你也可以采用基于注解式的事務配置方法。直接在Java源代碼中聲明事務語義的做法讓事務聲明和將受其影響的代碼距離更近了,而且一般來說不會有不恰當的耦合的風險,因為,使用事務性的代碼幾乎總是被部署在事務環境中。
下面的例子很好地演示了 @Transactional 注解的易用性,隨后解釋其中的細節。先看看其中的類定義:
<!-- the service class that we want to make transactional --> @Transactional public class DefaultFooService implements FooService {Foo getFoo(String fooName);Foo getFoo(String fooName, String barName);void insertFoo(Foo foo);void updateFoo(Foo foo); }當上述的POJO定義在Spring IoC容器里時,上述bean實例僅僅通過一 行xml配置就可以使它具有事務性的。如下:
<!-- from the file 'context.xml' --> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><!-- this is the service object that we want to make transactional --><bean id="fooService" class="x.y.service.DefaultFooService"/><!-- enable the configuration of transactional behavior based on annotations --><tx:annotation-driven transaction-manager="txManager"/><!-- a PlatformTransactionManager is still required --><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- (this dependency is defined somewhere else) --><property name="dataSource" ref="dataSource"/></bean><!-- other <bean/> definitions here --></beans>提示
實際上,如果你用 'transactionManager' 來定義 PlatformTransactionManager bean的名字的話,你就可以忽略 <tx:annotation-driven/> 標簽里的'transaction-manager' 屬性。 如果 PlatformTransactionManager bean你要通過其它名稱來注入的話,你必須用 'transaction-manager' 屬性來指定它,如上所示。
方法的可見度和 @Transactional
@Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不會展示已配置的事務設置。
@Transactional 注解可以被應用于接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足于開啟事務行為,它僅僅是一種元數據,能夠被可以識別 @Transactional 注解和上述的配置適當的具有事務行為的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啟 了事務行為。
Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用@Transactional 注解,但是這將只能當你設置了基于接口的代理時它才生效。因為注解是不能繼承 的,這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因此,請接受Spring團隊的建議并且在具體的類上使用@Transactional 注解。
注意
當使用 @Transactional 風格的進行聲明式事務定義時,你可以通過 <tx:annotation-driven/> 元素的 "proxy-target-class" 屬性值來控制是基于接口的還是基于類的代理被創建。如果 "proxy-target-class" 屬值被設置為 "true",那么基于類的代理將起作用(這時需要CGLIB庫cglib.jar在CLASSPATH中)。如果 "proxy-target-class" 屬值被設置為 "false" 或者這個屬性被省略,那么標準的JDK基于接口的代理將起作用。
在多數情形下,方法的事務設置將被優先執行。在下列情況下,例如: DefaultFooService 類被注解為只讀事務,但是,這個類中的updateFoo(Foo) 方法的 @Transactional 注解的事務設置將優先于類級別注解的事務設置。
@Transactional(readOnly = true) public class DefaultFooService implements FooService {public Foo getFoo(String fooName) {// do something}// these settings have precedence for this method@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)public void updateFoo(Foo foo) {// do something} }9.5.6.1.?@Transactional 有關的設置
@Transactional 注解是用來指定接口、類或方法必須擁有事務語義的元數據。 如:“當一個方法開始調用時就開啟一個新的只讀事務,并停止掉任何現存的事務”。 默認的@Transactional 設置如下:
-
事務傳播設置是 PROPAGATION_REQUIRED
-
事務隔離級別是 ISOLATION_DEFAULT
-
事務是 讀/寫
-
事務超時默認是依賴于事務系統的,或者事務超時沒有被支持。
-
任何 RuntimeException 將觸發事務回滾,但是任何 checked Exception 將不觸發事務回滾
這些默認的設置當然也是可以被改變的。 @Transactional 注解的各種屬性設置總結如下:
表?9.2.?@Transactional 注解的屬性
| 傳播性 | 枚舉型:Propagation | 可選的傳播性設置 |
| 隔離性 | 枚舉型:Isolation | 可選的隔離性級別(默認值:ISOLATION_DEFAULT) |
| 只讀性 | 布爾型 | 讀寫型事務 vs. 只讀型事務 |
| 超時 | int型(以秒為單位) | 事務超時 |
| 回滾異常類(rollbackFor) | 一組 Class 類的實例,必須是Throwable 的子類 | 一組異常類,遇到時 必須 進行回滾。默認情況下checked exceptions不進行回滾,僅unchecked exceptions(即RuntimeException的子類)才進行事務回滾。 |
| 回滾異常類名(rollbackForClassname) | 一組 Class 類的名字,必須是Throwable的子類 | 一組異常類名,遇到時 必須 進行回滾 |
| 不回滾異常類(noRollbackFor) | 一組 Class 類的實例,必須是Throwable 的子類 | 一組異常類,遇到時 必須不 回滾。 |
| 不回滾異常類名(noRollbackForClassname) | 一組 Class 類的名字,必須是Throwable 的子類 | 一組異常類,遇到時 必須不 回滾 |
9.5.7.?插入事務操作
考慮這樣的情況,你有一個類的實例,而且希望 同時插入事務性通知(advice)和一些簡單的剖析(profiling)通知。那么,在<tx:annotation-driven/>環境中該怎么做?
我們調用 updateFoo(Foo) 方法時希望這樣:
-
配置的剖析切面(profiling aspect)開始啟動,
-
然后進入事務通知(根據配置創建一個新事務或加入一個已經存在的事務),
-
然后執行原始對象的方法,
-
然后事務提交(我們假定這里一切正常),
-
最后剖析切面報告整個事務方法執行過程花了多少時間。
注意
這章不是專門講述AOP的任何細節(除了應用于事務方面的之外)。請參考 第?6?章 使用Spring進行面向切面編程(AOP) 章以獲得對各種AOP配置及其一般概念的詳細敘述。
這里有一份簡單的剖析切面(profiling aspect)的代碼。(注意,通知的順序是由 Ordered 接口來控制的。要想了解更多細節,請參考 第?6.2.4.7?節 “通知(Advice)順序” 節。)
package x.y;import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.util.StopWatch; import org.springframework.core.Ordered;public class SimpleProfiler implements Ordered {private int order;// allows us to control the ordering of advicepublic int getOrder() {return this.order;}public void setOrder(int order) {this.order = order;}// this method is the around advicepublic Object profile(ProceedingJoinPoint call) throws Throwable {Object returnValue;StopWatch clock = new StopWatch(getClass().getName());try {clock.start(call.toShortString());returnValue = call.proceed();} finally {clock.stop();System.out.println(clock.prettyPrint());}return returnValue;} }這里是幫助滿足我們上述要求的配置數據。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><bean id="fooService" class="x.y.service.DefaultFooService"/><!-- this is the aspect --><bean id="profiler" class="x.y.SimpleProfiler"><!-- execute before the transactional advice (hence the lower order number) --><property name="order" value="1"/></bean><tx:annotation-driven transaction-manager="txManager"/><aop:config><!-- this advice will execute around the transactional advice --><aop:aspect id="profilingAspect" ref="profiler"><aop:pointcut id="serviceMethodWithReturnValue" expression="execution(!void x.y..*Service.*(..))"/><aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/></aop:aspect></aop:config><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/><property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/><property name="username" value="scott"/><property name="password" value="tiger"/></bean><bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean></beans>上面配置的結果將獲得到一個擁有剖析和事務方面的 按那樣的順序 應用于它上面的 'fooService' bean。 許多附加的方面的配置將一起達到這樣的效果。
最后,下面的一些示例演示了使用純XML聲明的方法來達到上面一樣的設置效果。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"><bean id="fooService" class="x.y.service.DefaultFooService"/><!-- the profiling advice --><bean id="profiler" class="x.y.SimpleProfiler"><!-- execute before the transactional advice (hence the lower order number) --><property name="order" value="1"/></bean><aop:config><aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/><!-- will execute after the profiling advice (c.f. the order attribute) --><aop:advisor advice-ref="txAdvice" pointcut-ref="entryPointMethod"order="2"/> <!-- order value is higher than the profiling aspect --><aop:aspect id="profilingAspect" ref="profiler"><aop:pointcut id="serviceMethodWithReturnValue" expression="execution(!void x.y..*Service.*(..))"/><aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/></aop:aspect></aop:config><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice><!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here --></beans>上面配置的結果是創建了一個 'fooService' bean,剖析方面和事務方面被 依照順序 施加其上。如果我們希望剖析通知在目標方法執行之前 后于 事務通知執行,而且在目標方法執行之后先于 事務通知,我們可以簡單地交換兩個通知bean的order值。
如果配置中包含更多的方面,它們將以同樣的方式受到影響。
9.5.8.?結合AspectJ使用@Transactional
通過AspectJ切面,你也可以在Spring容器之外使用Spring框架的 @Transactional 功能。要使用這項功能你必須先給相應的類和方法加上@Transactional注解,然后把 spring-aspects.jar 文件中定義的org.springframework.transaction.aspectj.AnnotationTransactionAspect 切面連接進(織入)你的應用。同樣,該切面必須配置一個事務管理器。你當然可以通過Spring框架容器來處理注入,但因為我們這里關注于在Spring容器之外運行應用,我們將向你展示如何通過手動書寫代碼來完成。
注意
在我們繼續之前,你可能需要好好讀一下前面的第?9.5.6?節 “使用@Transactional” 和 第?6?章 使用Spring進行面向切面編程(AOP) 兩章。
// construct an appropriate transaction manager DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods AnnotationTransactionAspect.aspectOf().setTransactionManager (txManager);注意
使用此切面(aspect),你必須在 實現 類(和/或類里的方法)、而 不是 類的任何所實現的接口上面進行注解。AspectJ遵循Java的接口上的注解 不被繼承 的規則。
類上的 @Transactional 注解指定了類里的任何 public 方法執行的默認事務語義。
類里的方法的 @Transactional 將覆蓋掉類注解的默認事務語義(如何存在的話)。public、protected和默認可見的方法可能都被注解。直接對protected和默認可見的方法進行注解,讓這些方法在執行時去獲取所定義的事務劃分是唯一的途徑。
要把 AnnotationTransactionAspect 織入你的應用,你或者基于AspectJ構建你的應用(參考AspectJ Development Guide),或者采取“載入時織入”(load-time weaving),參考 第?6.8.4?節 “在Spring應用中使用AspectJ Load-time weaving(LTW)” 獲得關于使用AspectJ進行“載入時織入”的討論。
Spring基于tx/aop聲明式事務配置
http://blog.csdn.net/trwhoya/article/details/4535433
一、引入aop/tx命名空間
<beans
????xmlns="http://www.springframework.org/schema/beans"
????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
????xmlns:aop="http://www.springframework.org/schema/aop"
????xmlns:tx="http://www.springframework.org/schema/tx"
????xsi:schemaLocation="http://www.springframework.org/schema/beans
????http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
????http://www.springframework.org/schema/aop
????http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
????http://www.springframework.org/schema/tx
????http://www.springframework.org/schema/tx/spring-tx-2.0.xsd ">
?
二、基于tx/aop配置
<!--?事務管理器?-->
????<bean?id="transactionManager"?class="org.springframework.orm.hibernate3.HibernateTransactionManager">
????????<property?name="sessionFactory">
????????????<ref?bean="sessionFactory"/>
????????</property>
????</bean>
????<!--?通過aop定義事務增強切面?-->
????<aop:config>
????????<aop:pointcut?id="serviceMethod"?expression="execution(* com.cj.transaction.service.*.*(..))"/>
????????<aop:advisor?pointcut-ref="serviceMethod"?advice-ref="txAdvice"/>
????</aop:config>
????<tx:advice?id="txAdvice"?transaction-manager="transactionManager">
????????<tx:attributes>
????????????<tx:method?name="find*"?read-only="false"/>
????????????<tx:method?name="add*"?rollback-for="Exception"/>
????????</tx:attributes>
????</tx:advice>
?
expression="execution(* com.cj.transaction.service.*.*(..))"?中幾個通配符的含義:
第一個?* ——?通配?任意返回值類型
第二個?* ——?通配?包com.cj.transaction.service下的任意class
第三個?* ——?通配?包com.cj.transaction.service下的任意class的任意方法
第四個?.. ——?通配?方法可以有0個或多個參數
?
注意:第一個*后面有一個空格
?
總結
以上是生活随笔為你收集整理的spring中事务配置的3种方式-2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TIBCO EMS MESSAGE
- 下一篇: clojure source code