程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在Spring中實現事務掛起

在Spring中實現事務掛起

編輯:關於JAVA

Spring Framework是一個流行的Java/J2EE應用框架,它構建於一個輕量級的反向控制(Inversion-of-Control,QoC)模式的容器的基礎之上,以其數據訪問和事務管理能力而著稱。Spring的聲明性事務劃分適用於任何的POJO(pure old java object或plain ordinary Java object,無格式普通Java對象)目標對象,其聲明性事務如同EJB容器托管事務(Container-Managed Transaction,CMT)一樣完善。後端事務管理器的選擇包括簡單的基於JDBC的事務和完善的J2EE事務(借助於JTA策略)。

本文詳細討論了Spring的事務管理功能。重點介紹了如何以JTA作為後端事務策略,使用Spring的針對POJO的聲明性事務。本文說明了Spring的事務服務可以與J2EE服務器的事務協調程序(如BEA WebLogic Server的事務協調程序)進行無縫交互,實際上已經成為EJB CMT的傳統事務劃分方式的替代方案。

針對POJO的聲明性事務

為了說明Spring的聲明性事務劃分方式,讓我們來看看Spring的PetClinic示例應用程序的中央服務外觀(facade)的配置:

<bean id="dataSource"
   class="org.springframework.jndi.JndiObjectFactoryBean">
   <property name="jndiName">
   <value>java:comp/env/jdbc/petclinic</value>
   </property>
   </bean>
   <bean id="transactionManager"
   class="org.springframework.transaction.jta.JtaTransactionManager"/>

   <bean id="clinicTarget"
   class="org.springframework.samples.petclinic.jdbc.JdbcClinic">
   <property name="dataSource"><ref bean="dataSource"/></property>
   </bean>

   <bean id="clinic"
   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager"><ref bean="transactionManager"/></property>
   <property name="target"><ref bean="clinicTarget"/></property>
   <property name="transactionAttributes">
   <props>
   <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
   <prop key="store*">PROPAGATION_REQUIRED</prop>
   </props>
   </property>
   </bean>

它遵從了Spring的標准XMLBean定義格式。它定義了:

一個DataSource引用,指向一個JNDI位置--這將從J2EE服務器托管的JNDI環境中獲取指定的DataSource。

一個PlatformTransactionManage實現--在本例中,該實現指定Spring的JtaTransactionManager,它委托給J2EE服務器的事務協調程序。

應用程序服務實現--這是一個簡單的POJO,它封裝了業務和數據訪問邏輯。它實現應用程序的Clinic服務接口。

一個應用程序服務的事務代理--該代理定義了目標服務的事務屬性,提供具體的方法命名模式,並創建相應的事務。對於實際的事務管理,代理指向PlatformTransactionManager實現。

注意:Spring還通過通用屬性(Commons Attribute)或者J2SE 5.0的注釋(annotation),支持一種自動代理機制和對源級(source-level)元數據的使用,作為顯示代理定義的替代方案。這些替代方案不在本文的討論范圍之內;其詳細資料請參考Spring說明文檔。

使用的服務接口和服務實現是特定於應用程序的,無需了解Spring(具體說是Spring的事務管理)就可以實現。純Java對象可以用作目標對象,而任何一個純Java接口都可以用作服務接口。下面是一個Clinic接口的例子:

public interface Clinic {
   Pet loadPet(int id);
   void storePet(Pet pet);
   ...
   }

下面顯示了該接口的一個簡單實現,假定它使用JDBC來執行必要的數據訪問。它通過一個bean屬性的setter方法接收JDBC DataSource,這直接對應上面配置中的dataSource屬性定義。

public class JdbcClinic implements Clinic {

   private DataSource dataSource;

   public void setDataSource(DataSource dataSource) {
   this.dataSource = dataSource;
   }

   public Pet loadPet(int id) {
   try {
   Connection con = this.dataSource.getConnection();
   ...
   }
   catch (SQLException ex) {
   ...
   }
   }

   public void storePet(Pet pet) {
   try {
   Connection con = this.dataSource.getConnection();
   ...
   }
   catch (SQLException ex) {
   ...
   }
   }

   ...
   }

正如您所看到的,代碼簡單明了。使用了一個簡單Java對象。事務管理由事務代理處理,我們隨後再對其進行說明。

注意,PetClinic示例應用程序中實際的基於JDBC的Clinic實現利用了Spring的JDBC支持類,以免只工作在簡單的JDBC API級別上。但是,Spring的事務管理還將使用簡單的基於JDBC的實現,比如上面的實現。

定義事務代理

除JdbcClinic實例之外,配置還為其定義了一個事務代理。如果需要,可以顯式地指定該事務代理所暴露的實際接口。默認狀態下,目標對象實現的所有接口都將被暴露--在本例中是應用程序的Clinic服務接口。

從客戶端的角度來看,“clinic”bean只是應用程序的Clinic接口的實現。客戶端不必知道自己正在和事務代理打交道。這就是接口的力量:目標對象的直接引用可以很輕松地由實現了相同接口的代理取代--在本例中是一個隱式地創建事務的代理。

對於特定的方法或方法命名模式,代理的具體事務行為由事務屬性驅動,如下面的例子所示:

<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop><prop key="store*">PROPAGATION_REQUIRED</prop>

key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用:

PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。

PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。

PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。

PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。

PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。

PROPAGATION_NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。

前六個策略類似於EJB CMT:常量名相同,因此,對EJB開發人員來說,應該立刻就感到熟悉。第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行為(如Spring的DataSourceTransactionManager),或者通過JTA支持嵌套事務。

事務屬性中的readOnly標志表示對應的事務應該被最優化為只讀事務。這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。

在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,並據此得到相應的解釋。

使用事務代理

在運行時,客戶端將獲取到“clinic”bean的引用,將其轉換為Clinic接口,同時在它上面調用諸如loadPet或storePet之類的操作。這將隱式地使用在目標對象之前注冊的“事務攔截器”檢查Spring的事務代理;新的事務將被創建,然後調用將被委派給JdbcClinic目標方法。

圖1說明了一個具有“advisor鏈”和終端目標的AOP代理的底層概念。其中,唯一的advisor就是將事務行為包裝到目標方法的事務攔截器。這是在Spring的聲明性事務功能的幫助下產生的基於代理的AOP(面向方面編程)。

圖1. 具有“advisor鏈”和終端目標的AOP代理

例如,PetClinic web應用程序中的web層組件能夠執行ServletContext查詢操作來獲取對Spring WebApplicationContext的引用,然後獲得那裡托管的“Clinic”bean:

WebApplicationContext ctx =
   WebApplicationContexUtils.getWebApplicationContext(servletContext);
   Clinic clinic = (Clinic) ctx.getBean("clinic);

   Pet pet = new Pet();
   pet.setName("my new cat");

   clinic.storePet(pet); 
 

在storePet()調用的開始,Spring的事務代理將隱式地創建一個事務。在storePet()調用返回時,將提交或回滾事務。默認情況下,任何RuntimeException或Error的拋出均會導致回滾。可以指定何時提交和何時回滾的實際規則:Spring的事務屬性支持一個稱為“回滾規則”的概念。

例如,我們可以引入一個檢查性的PetClinicException,並告訴事務代理,在拋出該異常時執行進行回滾。

<prop key="load*">PROPAGATION_REQUIRED,readOnly,-PetClinicException</prop>

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved