Spring:事務管理
技術標籤:Spring
Spring的事務管理不需要與任何特定的事務API耦合。對不同的持久層訪問技術,程式設計式事務提供了一致的事務程式設計風格,通過模板化操作一致性地管理事務。宣告式事務基於Spring AOP實現,但並不需要開發者真正精通AOP技術,即可容易地使用Spring的宣告式事務管理。
1,Spring支援的事務策略
1.1,傳統的事務策略
Java EE應用的傳統事務有兩個策略:全域性事務和區域性事務。
- 全域性事務由應用伺服器管理,需要底層伺服器的JTA支援。可以跨多個事務資源(典型的例子是關係資料庫和訊息佇列);使用區域性事務,應用伺服器不需要參與事務管理,因此不能保證跨多個事務性資源的事務的正確性。
- 區域性事務和底層所採用的持久化技術有關,當採用JDBC持久化技術時,需要使用Connection物件來操作事務。而採用Hibernate持久化技術時,需要使用Session物件來操作事務。
JTA全域性事務、JDBC區域性事務、Hibernate事務的事務操作程式碼:
JTA全域性事務 JDBC區域性事務 Hibernate事務 Transaction tx = ctx.lookup(); Connection conn = getConnection();
conn.setAutoCommit(false);
Session s = getSession();
Transaction tx = s.beginTransaction;
//業務實現 if 正常
tx.commit();
if 失敗
tx.rollback();
if 正常
conn.commit();
if 失敗
conn.rollback();
if 正常
tx.commit();
if 失敗
tx.rollback();
事務結束 當採用傳統的事務程式設計策略時,程式程式碼必然和具體的事務操作程式碼耦合,這樣造成的後果是:當應用需要在不同的事務策略之間切換時,開發者必須手動修改程式程式碼。如果使用Spring事務管理,就可以改變這種現狀。
1.2,PlatformTransactionManager
Spring事務策略是通過PlatformTransactionManager
介面體現的,該介面是Spring事務策略的核心。該介面的原始碼如下:public interface PlatformTransactionManager extends TransactionManager { //平臺無關的獲得事務方法 TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; //平臺無關的事務提交方法 void commit(TransactionStatus var1) throws TransactionException; //平臺無關的事務回滾方法 void rollback(TransactionStatus var1) throws TransactionException; }
PlatformTransactionManager是一個與任何事務策略分離的介面,隨著底層不同事務策略的切換,應用必須採用不同的實現類。PlatformTransactionManager介面沒有與任何事務性資源捆綁在一起,它可以適應於任何事務策略,結合Spring的IoC容器,可以向PlatformTransactionManager注入相關的平臺特性。
PlatformTransactionManager介面有許多不同的實現類,應用程式面向與平臺無關的介面程式設計,當底層採用不同的持久化層技術時,系統只需使用不同的PlatformTransactionManager實現類即可——而這種切換通常由Spring容器負責管理,應用程式無須與具體的事務API耦合,也無須與特定實現類耦合,從而將應用和持久化技術、事務API徹底分離開來。
Spring的事務機制使一種典型的策略模式,PlatformTransactionManager代表事務管理介面,但它並不知道底層是如何管理事務,它只要求事務管理需要提供開始事務(getTransaction())、提交事務(commit())和回滾事務(rollbackj())方法,但具體如何實現則交給其他實現類完成——不同的實現類則代表不同的事務管理策略。
在PlatformTransactionManager介面內,包含一個getTransaction(TransactionDefinition definition)方法,該方法根據TransactionDefinition引數返回一個TransactionStatus物件。TransactionStatus物件表示一個事務,TransactionStatus被關聯在當前執行的執行緒上。
getTransaction(TransactionDefinition definition)返回的TransactionStatus物件,可能是一個新的事務,也可能是一個已經存在的事務物件。如果當前執行的執行緒已經處於事務管理下,則返回當前執行緒的事務物件;否則,系統將新建一個事務物件後返回。
TransactionDefinition介面定義了一個事務規則,該介面必須指定如下幾個屬性:
- 事務隔離:當前事務和其他事務的隔離程度。例如,這個事務能否看到其他事務未提交的資料等。
- 事務傳播:通常,在事務中執行的程式碼都會在當前事務中執行。但是,如果一個事務上下文已經存在,有幾個選項可指定該事務性方法的執行行為。例如,在大多數情況下,簡單地在現有的事務上下文中執行;或者掛起現有事務,建立一個新的事務。
- 事務超時:事務在超時前能執行多久,也就是事務的最長持續時間。如果事務一直沒有被提交和回滾,將在超出該事件後,系統自動回滾事務。
- 只讀狀態:只讀事務不修改任何資料。在某些情況下(例如使用HIbernate時),只讀事務是非常有用的優化。
TransactionStatus代表事務本身,它提供了簡單的控制事務執行和查詢事務狀態的方法,這些方法在所有的事務API中都是相同的。
public interface TransactionExecution { //判斷事務是否為新建的事務 boolean isNewTransaction(); //設定事務回滾 void setRollbackOnly(); //判斷是否已回滾 boolean isRollbackOnly(); //判斷是否提交完成 boolean isCompleted(); } public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable { boolean hasSavepoint(); void flush(); }
Spring具體的事務管理由PlatformTransactionmanager的不同實現類完成。在Spring容器中配置PlatformTransactionManagerBean時,必須針對不同的環境提供不同的實現類。
1.3,不同持久層訪問環境及其對應的PlatformTransactionManager實現類的配置。
容器管理的JTA全域性事務管理器的配置
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--配置JNDI資料來源Bean,其中jndiName指定容器管理資料來源的JNDI--> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/jpetstore"/> <!--使用JtaTransactionManager類,該類實現了PlatformTransactionManager介面--> <!--針對採用全域性事務管理的特定實現--> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> </beans>
當配置JtaTransactionManager全域性事務管理策略時,只需指定事務管理器實現類即可,無須傳入額外的事務性資源。這是因為全域性事務的JTA資源由Java EE伺服器提供,而Spring容器能自行從Java EE伺服器中獲取該事務性資源,所以無須使用依賴注入來配置。
JDBC資料來源的區域性事務管理的配置
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--定義資料來源Bean,使用C3P0資料來源實現,並注入資料來源的必要資訊--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/spring" p:user="root" p:password="123456" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30"/> <!--配置JDBC的區域性事務管理器,使用DataSourceTransactionManager類--> <!--該類實現PlatformTransactionManager介面,是針對採用資料來源連線的特定實現--> <!--配置DataSourceTransactionManager時需要依賴注入DataSource的引用--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> </beans>
Hibernate持久層訪問策略,區域性事務策略的配置
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--定義資料來源Bean,使用C3P0資料來源實現,並注入資料來源的必要資訊--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/spring" p:user="root" p:password="123456" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30"/> <!--定義Hibernate的SessionFactory,SessionFactory需要依賴資料來源,注入dataSource--> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" p:dataSource-ref="dataSource"> <!--annotatedClasses用來列出全部持久化類--> <property name="annotatedClasses"> <list> <!--以下用來列出所有的PO類--> <value>Pojo.User</value> </list> </property> <!--定義Hibernate SessionFactory的屬性--> <property name="hibernateProperties"> <props> <!--指定Hibernate的連線方言--> <prop key="hibernate.dialect">org.hibernate.dialect.MYSQL5InnoDBDialect</prop> <!--是否根據Hibernate對映建立資料表--> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!--配置Hibernate的區域性事務管理器,使用HibernateTransactionManager類--> <!--該類是PlatformTransactionManager介面針對採用Hibernate的特定實現類--> <!--配置HibernateTransactionManager需要依賴注入SessionFactory--> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"/> </beans>
如果底層採用的是Hibernate持久層技術,但事務採用JTA全域性事務,則Spring配置檔案如下:
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--配置JNDI資料來源Bean,其中jndiName指定容器管理資料來源的JNDI--> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName="jdbc/jpetstore"/> <!--定義Hibernate的SessionFactory,SessionFactory需要依賴資料來源,注入dataSource--> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" p:dataSource-ref="dataSource"> <!--annotatedClasses用來列出全部持久化類--> <property name="annotatedClasses"> <list> <!--以下用來列出所有的PO類--> <value>Pojo.User</value> </list> </property> <!--定義Hibernate SessionFactory的屬性--> <property name="hibernateProperties"> <props> <!--指定Hibernate的連線方言--> <prop key="hibernate.dialect">org.hibernate.dialect.MYSQL5InnoDBDialect</prop> <!--是否根據Hibernate對映建立資料表--> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!--使用JtaTransactionManager類,該類實現了PlatformTransactionManager介面--> <!--針對採用全域性事務管理的特定實現--> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> </beans>
從配置可以看出,不論採用哪種持久層訪問技術,只要使用JTA去全域性事務,Spring事務管理的配置就完全一樣,因為它們採用的全都是全域性事務管理策略。
當程式採用Spring事務管理策略時,應用程式無須與具體的事務策略耦合,應用程式只要面向PlatformTransactionManager策略介面程式設計,ApplicationContext將會根據配置檔案選擇合適的事務策略實現類。
實際上,Spring提供瞭如下兩種事務管理方式:
- 程式設計式事務管理:即使使用Spring的程式設計式事務,程式也可直接獲取容器中的transacntionManager Bean,該Bean總是PlatformTransactionManager的例項,所有可以通過該介面體用的三個方法來開始事務、提交事務和回滾事務。
- 宣告式事務管理:無須在Java程式中書寫任何事務操作程式碼,而是通過在XML檔案中為業務組配置事務代理(AOP代理的一種),AOP為事務代理所織入的增強處理也由Spring提供——在目標方法執行之前,織入開始事務;在目標方法執行之後,織入結束事務。
不論採用何種持久化策略,Spring都提供了一致的事務抽象,因此,應用開發者能在任何環境下,使用一致的程式設計模型。無須更改程式碼,應用就可在不同的事務管理策略中切換。
(1)當使用程式設計式事務時,開發者使用的是Spring事務抽象,而無需使用任何具體的底層事務API。Spring的事務管理將程式碼從底層具體的事務API中抽象出來,該抽象能以任何底層事務為基礎。Spring的程式設計式事務還可通過TransactionTemplace類來完成,該類體用了一個execute方法,可以更簡潔的方式來進行事務操作。
(2)當使用宣告式事務時,開發者無須書寫任何事務管理程式碼,不依賴Spring或任何其他事務API。Spring的宣告式事務無須任何額外的容器支援,Spring容器本身管理宣告式事務。使用宣告式事務策略,可以讓開發者更好地專注於業務邏輯的實現。Spring所支援的事務策略非常靈活,Spring的事務策略允許應用程式在不同的事務策略之間自由切換,即使需要在區域性事務策略和全域性事務策略之間切換,也只需要修改配置檔案計科,而應用程式的程式碼無須任何改變,這種靈活的設計,正是面向介面程式設計帶來的優勢。
2,使用XML Schema配置事務策略(宣告式事務策略)
Spring同時支援程式設計式事務策略和宣告式事務策略,通常都推薦採用宣告式事務策略。使用宣告式事務策略的優勢十分明顯:
- 宣告式事務能大大降低開發者的程式碼書寫數量,而且宣告式事務幾乎不影響應用的程式碼。因此,無論底層事務策略如何變化,應用程式都無須任何改變。
- 應用程式程式碼無須任何事務處理程式碼,可以更專注於業務邏輯的實現。
- Spring則可對任何POJO的方法提供事務管理,而且Spring的宣告式事務管理無須容器的支援,可在任何環境下使用。
- EJB的CMT無法提供宣告式回滾規則;而通過配置檔案,Spring可指定事務在遇到特定異常時自動回滾。Spring不僅可以在程式碼中使用setRollbackOnly回滾事務,也可以在配置檔案中配置回滾規則。
- 由於Spring採用AOP的方式管理事務,可以在事務回滾動作中插入使用者自己的動作,而不僅僅是執行系統預設的回滾。
2.1,配置方法
Spring的XML Schema方式提供了簡潔的事務配置策略,Spring2.x提供了tx:名稱空間來配置事務管理,tx:名稱空間下提供了<tx:advice.../>元素來配置事務增強處理,一旦使用該元素配置了事務增強增強處理,就可直接使用<aop:advisor.../>元素啟用自動代理。
配置<tx:advice.../>元素時除了需要transaction-manager屬性指定事務管理器之外,還需要配置一個<attributes.../>子元素,該子元素裡又可包含多個<method.../>子元素。
配置<tx:advice.../>的重點就是配置<method.../>子元素,實際上每個<method.../>子元素都為一批方法指定了所需的事務定義,包括事務傳播屬性、事務隔離屬性、事務超時屬性、只讀事務、對指定異常回滾、對指定異常不會滾等。
配置<method.../>子元素可以指定如下幾個屬性:
- name:必選屬性,與該事務語義關聯的方法名。該屬性支援使用萬用字元,例如'get*'、'handle*'、'on*Event'等。
- propagation:指定事務傳播行為,該屬性值可為Propagation列舉類的前一列舉值。預設值為Propagation.REQUIRED。
- isolation:指定事務隔離級別,該屬性可為Isolation列舉類的任一列舉值。該屬性的預設值為Isolation.DEFAULT。
- timeout:指定事務超時的時間(以秒為單位),指定-1意味著不超時,該屬性的預設值是-1。
- read-only:指定事務是否只讀。該屬性的預設值是false。
- rollback-for:指定觸發事務回滾的異常類(應使用全限定類名),該屬性可指定多個異常類,多個異常類之間以英文逗號隔開。
- no-rollback-for:指定不觸發事務回滾的異常類(應使用全限定類名),該屬性可指定多個異常類,多個異常類之間用英文逗號隔開。
2.2,隔離級別
<method.../>子元素的propagation屬性用於指定事務傳播行為,Spring支援事務傳播行為如下:
- PROPAGATION_MANDATORY:要求呼叫該方法必須處於事務環境中,否則丟擲異常。
- PROPAGATION_NESTED:即使執行該方法的執行緒已處於事物環境中,也依然啟動新的事務,方法在巢狀的事務裡執行;即使執行該方法的執行緒並未處於事務環境中,也啟動新的事務,然後執行該方法,此時PROPAGATION_REQIRED相同。
- PROPAGATION_NEVER:不允許呼叫該方法的執行緒處於事務環境中,如果呼叫該方法的執行緒處於事務環境中,則丟擲異常。
- PROPAGATION_NOT_SUPPORTED:如果呼叫該方法的執行緒處於事務環境中,則先暫停當前事務,然後執行該方法。
- PROPAGATION_REQUIRED:要求在事務環境中執行該方法,如果當前執行執行緒已處於事務環境中,則直接呼叫;如果當前執行執行緒不處於事務環境中,則啟動新的事務環境中,則啟動新的事務後執行該方法。
- PROPAGATION_REQUIRES_NEW:該方法要求在新的事務環境中執行,如果當前執行執行緒已處於事務環境中,則先暫停當前事務,啟動新事務後執行該方法;如果當前呼叫執行緒不處於事物環境中,則啟動新的事務後執行方法。
- PROPAGATION_SUPPORTS:如果當前執行執行緒處於事務管敬仲,則使用當前事務,否則不使用事務。
2.3,事務案例
本例使用NewsDao元件來測試Spring的事務功能,程式將使用<tx:advice.../>元素來配置事務增強處理,再使用<aop:advisor.../>為容器中的一批Bean配置自動事務代理。
NewDao元件包含一個insert()方法,該方法同時插入兩條記錄,但插入第二條記錄將會違反唯一性約束,引發異常。
package Dao; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; public class NewsDao { private DataSource ds; public void setDs(DataSource ds) { this.ds = ds; } public void insert(String title,String content){ JdbcTemplate jt = new JdbcTemplate(ds); jt.update("insert into sutdent values(1,?,?)",title,content); jt.update("insert into sutdent values(1,?,?)",title,content); } }
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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-4.0.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop htpp://www.springframework.org/schema/tx htpp://www.springframework.org/schema/tx/spring-tx-4.0xsd https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--定義資料來源Bean,使用C3P0資料來源實現,並注入資料來源的必要資訊--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/spring" p:user="root" p:password="123456" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30"/> <!--配置JDBC資料來源的區域性事務管理器,使用DataSourceTransactionManager類--> <!--該類實現了PlatformTransactionManager介面,是針對採用資料來源連線的特定實現--> <!--配置DataSourceTransactionManager時需要依賴注入DataSource的應用--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <!--配置業務邏輯Bean--> <bean id="newDao" class="Dao.NewsDao" p:ds-ref="dataSource"/> <!--配置事務增強處理Bean,指定事務管理器--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--所有以get開頭的方法是隻讀--> <tx:attributes> <tx:method name="get*" read-only="true"/> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5"/> </tx:attributes> </tx:advice> <aop:config> <!--配置一個切入點,匹配Dao包下的所有方法--> <aop:pointcut id="myPoint" expression="execution(* Dao.*.*(..))"/> <!--aop:advisor與aop:aspect一樣,用處不一樣,前者用於事務,後者用於切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint"/> </aop:config> </beans>
<aop:advisor.../>元素是一個很奇怪的東西,標準的AOP機制裡並沒有所謂的Advisor,Advisor是Spring1.x遺留下來的。Advisor的作用非常簡單:將Advice和切入點繫結在一起,保證Advice所包含的增強處理將在對應的切入點被織入。
package Service; import Dao.NewsDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); NewsDao dao = applicationContext.getBean("newDao",NewsDao.class); dao.insert("燕雙嚶","我賭你的槍裡沒有子彈!"); } }
上面程式會產生一個異常,而且insert()方法所執行的兩條SQL語句全部回滾——因為事務控制。
3,使用@Transactional註解配置事務代理
Spring還允許將事務配置放在Java類中定義,這需要藉助於@Transactional註解,該註解既可用於修飾SpringBean類,也可用於修飾Bean類中的方法。
如果使用@Transactional修飾Bean類,則表明這些事務設定對整個Bean類其作用;如果使用@Transactional修飾Bean類的某個方法,則表明這些事務設定只對該方法有效。
使用@Transactional時可指定如下屬性:
- isolation:用於指定事務的隔離級別。預設為底層事務的隔離級別。
- noRollbackFor:指定遇到特定異常時強制不回滾事務。
- noRollbackForClassName:指定遇到特定的多個異常時強制不回滾事務。該屬性可以指定多個異常類名。
- propagation:指定事務傳播行為。
- readOnly:指定事務是否只讀。
- rollbackFor:指定遇到特定異常時強制回滾事務。
- rollbackForClassName:指定遇到特定的多個異常時強制回滾事務。該屬性值可以指定多個異常類名。
- timeout:指定事務的超時時長。
其實該註解所指定的屬性與<tx:advice.../>元素中所指定的事務屬性基本上是對應的,它們的意義也基本相似。
package Dao; import org.aspectj.lang.annotation.Aspect; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import javax.sql.DataSource; @Aspect public class NewsDao { private DataSource ds; public void setDs(DataSource ds) { this.ds = ds; } @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = 5) public void insert(String title,String content){ JdbcTemplate jt = new JdbcTemplate(ds); jt.update("insert into student values(1,?,?)",title,content); jt.update("insert into student values(1,?,?)",title,content); } }
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd"> <!--定義資料來源Bean,使用C3P0資料來源實現,並注入資料來源的必要資訊--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/spring" p:user="root" p:password="123456" p:maxPoolSize="40" p:minPoolSize="2" p:initialPoolSize="2" p:maxIdleTime="30"/> <!--配置JDBC資料來源的區域性事務管理器,使用DataSourceTransactionManager類--> <!--該類實現了PlatformTransactionManager介面,是針對採用資料來源連線的特定實現--> <!--配置DataSourceTransactionManager時需要依賴注入DataSource的應用--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <!--配置業務邏輯Bean--> <bean id="newDao" class="Dao.NewsDao" p:ds-ref="dataSource"/> <!--根據Annotation來生成事務代理--> <tx:annotation-driven/> </beans>