我們都知道sPRing提供兩種管理事務的方式,一種是聲明式事務,一種是編程式事務。
Spring的聲明式事務管理,基于Spring的AOP,不再需要不停地寫commit,rollback,(但Spring仍然沒有放棄編程式的事務管理策略)。
Spring的編程式事務管理,為我們提供了一個TransactionTemplate,使用回調機制,將應用代碼從樣板式的資源獲取和釋放代碼中解放出來,不再有大量的try/catch/finally/try/catch代碼塊。
這兩種事務處理方式都非常地優雅,它不需要與任何特定的事務API耦合,并支持多種持久層方案。
(1)聲明式事務:基于Spring AOP實現,幾乎就是xml文件的配置
(2)編程式事務:統一的事務編碼風格,幾乎是一個模板化的。
以下將對這兩種事務管理方式進行探討:
首先探討一下聲明式事務:
我們知道Spring事務管理的核心接口是:
org.springframework.transaction.PlatformTransactionManager
它定義了三個待實現的方法:
(1)public TransactionStatus getTransaction(TransactionDefinition definition);
//返回當前活動的事務或根據相應的行為創建一個新的事務(可以查閱API理解)
(2)public void commit(TransactionStatus status);//提交事務
(3)public void rollback(TransactionStatus status); //回滾事務
PlatformTransactionManager是一個與特定平臺無關的事務操作接口,不同的底層事務平臺應通過Spring的Ioc注入相應的事務操作實現類 (這些實現類也不需要我們去完成,Spring已經為我們提供了)。那么我們來看看針對不同的底層持久化平臺,我們需要為PlatformTransactionManager接口注入何種實現類:
在上面的配置中,對于采用jdbc,hibernate等,我們只要提供相應的PlatformTransactionManager實現類即可。可見Spring對事務的操作僅僅修改一下配置文件,不需要修改任何實際的代碼,就可以在不同的事務管理策略之間切換,非常地方便,Spring為我們提供了高度的解耦。
以上就是我們在spring中處理事務所需要的事務管理器的配置,那么在具體的業務處理bean中我們如何控制事務呢?
一般都推薦事務最好做在service層,底層的dao可以不考慮事務,有時設計得不好可能會出現事務的嵌套,增加程序復雜度。而且將事務的處理放在service層中進行,對于我們異常體系的設計也帶來好處,service層拋出的異常可以在web捕獲,并將異常信息在web頁面給用戶提示。所以接下來我們就將在service層開始事務,提交事務,回滾事務等。作為聲明式事務管理,spring已經幫我們做好了這一切,基本上就是代理模式。
以下就是Spring提供的4種事務代理方式:
1.使用TransactionProxyFactoryBean為目標bean生成事務代理,此方式是最傳統,也是配置文件最臃腫的一種方式。
2.使用bean繼承的事務代理方式,此方式比較簡潔,但依然是增量式配置,bean越多配置文件越臃腫。
3.使用BeanNameAutoProxyCreator,根據bean name自動生成事務代理的方式,這是直接利用Spring的AOP框架配置事務代理的方式,需要對Spring的AOP框架有所了解,但也不必成為AOP專家,這種方式避免了增量式配置,也是推薦的方式。
4.使用DefaultAdvisorAutoProxyCreator,這也是直接利用Spring的AOP框架配置事務代理的方式,只是這種配置方式的可讀性不如第三種方式。
對于第一種:使用TransactionProxyFactoryBean為目標bean生成事務代理:
因為TransactionProxyFactoryBean產生的是代理Bean,所以我們在配置TransactionProxyFactoryBean時,需要指定目標Bean。每個TransactionProxyFactoryBean為一個目標Bean生成事務代理,事務代理的方法改寫了目標Bean的方法,就是在目標Bean的方法執行之前加入開始事務,在目標Bean的方法正常結束之前提交事務,如果遇到特定異常則回滾事務。TransactionProxyFactoryBean創建事務代理時,需要了解當前事務所處的環境,該環境屬性通過PlatformTransactionManager實例傳入,而相關事務傳入規則在TransactionProxyFactoryBean的定義中給出。
下面該方法的配置方式:
關于以上配置文件的幾個事務傳播規則可以查閱相應的API
程序面向UserServiceImpl類所實現的接口編程,事務處理由Spring為UserServiceImpl類所實現的接口IUserService生成的代理bean來完成。(Spring不僅支持對接口的代理,Spring結合CGLIB還可以為具體類生成代理,在此不做討論)
對于第二種:采用bean繼承的事務代理
仔細觀察第一種配置方式,我們可以發現,如果配置文件中有多個這樣的事務代理Bean,配置文件將變得非常臃腫。所以可以使用Bean繼承來簡化事務代理的配置。考慮到所有事務代理Bean中,事務代理Bean所使用的事務管理器和事務傳播規則大致是相同的,所以我們可以定義一個事務代理bean的模板。
即:
接下來讓真正的事務代理Bean繼承上面的事務模板Bean
我們知道,繼承中子類可以復寫父類的方法,這里也一樣,子Bean重新定義事務屬性將覆蓋事務代理模板里的事務屬性定義:
即:
可見,采用Bean繼承方式定義事務代理的方式,可以很好地簡化事務代理的配置,可以避免配置事務代理Bean時的冗余配置。
對于第三種:使用BeanNameAutoProxyCreator
使用BeanNameAutoProxyCreator來創建代理時,并不一定是創建事務代理,關鍵在于傳入的攔截器,如果傳入事務攔截器,將可自動生成事務代理。
下面是使用BeanNameAutoProxyCreator自動生成事務代理的配置方式:
如果配置文件中僅有兩個目標Bean,可能不能很清楚地看出這種自動創建代理配置方式的優勢,但如果有更多目標Bean需要自動創建事務代理,則可以很好地體會到這種配置方式的優勢:配置文件只需要簡單地配置目標Bean,然后在BeanNameAutoProxyCreator配置中增加一行即可。
對于第四種:DefaultAdvisorAutoProxyCreator:
這種配置方式與BeanNameAutoProxyCreator自動創建代理的方式非常相似,都是使用bean后處理器為目標bean生成事務代理,區別是前者使用事務攔截器創建代理,后者需要使用Advisor創建事務代理。事實上,采用DefaultAdvisorAutoProxyCreator的事務代理配置方式更加簡潔,這個代理生成器自動搜索Spring容器中的Advisor,并為容器中所有的bean創建代理。相對前一種方式,這種方式的可讀性不如前一種直觀。
使用DefaultAdvisorAutoProxyCreator的配置方式:
<?xml version="1.0" encoding="utf-8"?><!-- 指定Spring配置文件的根元素,以及相應的Schema信息 --><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定義數據源Bean,使用C3P0數據源實現 --> <bean id="dataSource" class="com.mchange.v2.c3p0. ComboPooledDataSource" destroy-method="close"> <!-- 指定連接數據庫的驅動 --> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <!-- 指定連接數據庫的URL --> <property name="jdbcUrl" value="jdbc:mysql:3306/127.0.0.1/ssh"/> <!-- 指定連接數據庫的用戶名 --> <property name="user" value="root"/> <!-- 指定連接數據庫的密碼 --> <property name="password" value="123"/> <!-- 指定連接數據庫連接池的最大連接數 --> <property name="maxPoolSize" value="40"/> <!-- 指定連接數據庫連接池的最小連接數 --> <property name="minPoolSize" value="1"/> <!-- 指定連接數據庫連接池的初始化連接數 --> <property name="initialPoolSize" value="1"/> <!-- 指定連接數據庫連接池的連接最大空閑時間 --> <property name="maxIdleTime" value="20"/> </bean> <!--定義一個hibernate的SessionFactory--><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 定義SessionFactory必須注入DataSource--> <property name="dataSource"><ref local="dataSource"/></property> <property name="mappingResources"> <list> <!--列出所有的PO映射文件--> <value>org/hnylj/vo/User.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props><!--定義hibernate的SessionFactory的屬性--> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> </props> </property> </bean> <!-- 定義hibernate的局部事務管理器--><bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <!-- 注入SessionFactory bean的引用--> <property name="sessionFactory"><ref local="sessionFactory"/></property></bean> <!-- 配置事務攔截器--><bean id="transactionInterceptor"class="org.springframework.transaction.interceptor.TransactionInterceptor"> <!-- 事務攔截器bean需要依賴注入一個事務管理器 --> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <!-- 下面定義事務傳播屬性--> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property></bean> <!-- 定義事務Advisor--><bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <!-- 定義advisor時,必須傳入Interceptor--> <property name="transactionInterceptor" ref="transactionInterceptor"/> </bean> <!-- DefaultAdvisorAutoProxyCreator搜索容器中的 advisor,并為每個bean創建代理 --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/><!--定義DAO Bean ,由BeanNameAutoProxyCreator自動生成事務代理--> <bean id="userService" class="org.hnylj.service.impl.UserServiceImpl"> <property name="userDAO"><ref local="userDAO"/></property></bean></beans> 新聞熱點
疑難解答