少年阿賓那些青春的歲月 |
摘要: Struts2攔截器(Interceptor)
&... 閱讀全文
MYSQL中 ENUM 類型的詳細解釋
ENUM 類型
在下列某些情況下,值也可以是空串(
每個枚舉值均有一個索引值:
例如,指定為
換個枚舉最大可以有 65535 個成員值。 從 MySQL 3.23.51 開始,當表被創建時, 當為一個 如果在一個數字語境中檢索一個 mysql> SELECT enum_col+0 FROM tbl_name; 如果將一個數字存儲到一個
如果希望得到一個 package com.abin.inter.service; public interface UserService { package com.abin.inter.serviceImpl; import com.abin.inter.service.UserService; public class UserServiceImpl implements UserService{ @Override @Override package com.abin.inter.test; import com.abin.inter.service.UserService; import junit.framework.TestCase; public class TestUser extends TestCase{ 運行結果: Enum Info:Initialize Of User UserInfo:UserAge UserSum=27 Enum Info:UserInitialize UserInfo:UserName Welcome=歡迎abin 緩存是介于應用程序和物理數據源之間,其作用是為了降低應用程序對物理數據源訪問的頻次,從而提高了應用的運行性能。緩存內的數據是對物理數據源中的數據的復制,應用程序在運行時從緩存讀寫數據,在特定的時刻或事件會同步緩存和物理數據源的數據。 緩存的介質一般是內存,所以讀寫速度很快。但如果緩存中存放的數據量非常大時,也會用硬盤作為緩存介質。緩存的實現不僅僅要考慮存儲的介質,還要考慮到管理緩存的并發訪問和緩存數據的生命周期。 Hibernate的緩存包括Session的緩存和SessionFactory的緩存,其中SessionFactory的緩存又可以分為兩類:內置緩存和外置緩存。Session的緩存是內置的,不能被卸載,也被稱為Hibernate的第一級緩存。SessionFactory的內置緩存和Session的緩存在實現方式上比較相似,前者是SessionFactory對象的一些集合屬性包含的數據,后者是指Session的一些集合屬性包含的數據。SessionFactory的內置緩存中存放了映射元數據和預定義SQL語句,映射元數據是映射文件中數據的拷貝,而預定義SQL語句是在Hibernate初始化階段根據映射元數據推導出來,SessionFactory的內置緩存是只讀的,應用程序不能修改緩存中的映射元數據和預定義SQL語句,因此SessionFactory不需要進行內置緩存與映射文件的同步。SessionFactory的外置緩存是一個可配置的插件。在默認情況下,SessionFactory不會啟用這個插件。外置緩存的數據是數據庫數據的拷貝,外置緩存的介質可以是內存或者硬盤。SessionFactory的外置緩存也被稱為Hibernate的第二級緩存。 Hibernate的這兩級緩存都位于持久化層,存放的都是數據庫數據的拷貝,那么它們之間的區別是什么呢?為了理解二者的區別,需要深入理解持久化層的緩存的兩個特性:緩存的范圍和緩存的并發訪問策略。 持久化層的緩存的范圍 緩存的范圍決定了緩存的生命周期以及可以被誰訪問。緩存的范圍分為三類。 1 事務范圍:緩存只能被當前事務訪問。緩存的生命周期依賴于事務的生命周期,當事務結束時,緩存也就結束生命周期。在此范圍下,緩存的介質是內存。事務可以是數據庫事務或者應用事務,每個事務都有獨自的緩存,緩存內的數據通常采用相互關聯的的對象形式。 2 進程范圍:緩存被進程內的所有事務共享。這些事務有可能是并發訪問緩存,因此必須對緩存采取必要的事務隔離機制。緩存的生命周期依賴于進程的生命周期,進程結束時,緩存也就結束了生命周期。進程范圍的緩存可能會存放大量的數據,所以存放的介質可以是內存或硬盤。緩存內的數據既可以是相互關聯的對象形式也可以是對象的松散數據形式。松散的對象數據形式有點類似于對象的序列化數據,但是對象分解為松散的算法比對象序列化的算法要求更快。 3 集群范圍:在集群環境中,緩存被一個機器或者多個機器的進程共享。緩存中的數據被復制到集群環境中的每個進程節點,進程間通過遠程通信來保證緩存中的數據的一致性,緩存中的數據通常采用對象的松散數據形式。 對大多數應用來說,應該慎重地考慮是否需要使用集群范圍的緩存,因為訪問的速度不一定會比直接訪問數據庫數據的速度快多少。 持久化層可以提供多種范圍的緩存。如果在事務范圍的緩存中沒有查到相應的數據,還可以到進程范圍或集群范圍的緩存內查詢,如果還是沒有查到,那么只有到數據庫中查詢。事務范圍的緩存是持久化層的第一級緩存,通常它是必需的;進程范圍或集群范圍的緩存是持久化層的第二級緩存,通常是可選的。 持久化層的緩存的并發訪問策略 當多個并發的事務同時訪問持久化層的緩存的相同數據時,會引起并發問題,必須采用必要的事務隔離措施。 在進程范圍或集群范圍的緩存,即第二級緩存,會出現并發問題。因此可以設定以下四種類型的并發訪問策略,每一種策略對應一種事務隔離級別。 事務型:僅僅在受管理環境中適用。它提供了Repeatable Read事務隔離級別。對于經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止臟讀和不可重復讀這類的并發問題。 讀寫型:提供了Read Committed事務隔離級別。僅僅在非集群的環境中適用。對于經常被讀但很少修改的數據,可以采用這種隔離類型,因為它可以防止臟讀這類的并發問題。 非嚴格讀寫型:不保證緩存與數據庫中數據的一致性。如果存在兩個事務同時訪問緩存中相同數據的可能,必須為該數據配置一個很短的數據過期時間,從而盡量避免臟讀。對于極少被修改,并且允許偶爾臟讀的數據,可以采用這種并發訪問策略。 只讀型:對于從來不會修改的數據,如參考數據,可以使用這種并發訪問策略。 事務型并發訪問策略是事務隔離級別最高,只讀型的隔離級別最低。事務隔離級別越高,并發性能就越低。 什么樣的數據適合存放到第二級緩存中? 1、很少被修改的數據 2、不是很重要的數據,允許出現偶爾并發的數據 3、不會被并發訪問的數據 4、參考數據 不適合存放到第二級緩存的數據? 1、經常被修改的數據 2、財務數據,絕對不允許出現并發 3、與其他應用共享的數據。 Hibernate的二級緩存 如前所述,Hibernate提供了兩級緩存,第一級是Session的緩存。由于Session對象的生命周期通常對應一個數據庫事務或者一個應用事務,因此它的緩存是事務范圍的緩存。第一級緩存是必需的,不允許而且事實上也無法比卸除。在第一級緩存中,持久化類的每個實例都具有唯一的OID。 第二級緩存是一個可插拔的的緩存插件,它是由SessionFactory負責管理。由于SessionFactory對象的生命周期和應用程序的整個過程對應,因此第二級緩存是進程范圍或者集群范圍的緩存。這個緩存中存放的對象的松散數據。第二級對象有可能出現并發問題,因此需要采用適當的并發訪問策略,該策略為被緩存的數據提供了事務隔離級別。緩存適配器用于把具體的緩存實現軟件與Hibernate集成。第二級緩存是可選的,可以在每個類或每個集合的粒度上配置第二級緩存。 Hibernate的二級緩存策略的一般過程如下: 1) 條件查詢的時候,總是發出一條select * from table_name where …. (選擇所有字段)這樣的SQL語句查詢數據庫,一次獲得所有的數據對象。 2) 把獲得的所有數據對象根據ID放入到第二級緩存中。 3) 當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;查不到,如果配置了二級緩存,那么從二級緩存中查;查不到,再查詢數據庫,把結果按照ID放入到緩存。 4) 刪除、更新、增加數據的時候,同時更新緩存。 Hibernate的二級緩存策略,是針對于ID查詢的緩存策略,對于條件查詢則毫無作用。為此,Hibernate提供了針對條件查詢的Query緩存。 Hibernate的Query緩存策略的過程如下: 1) Hibernate首先根據這些信息組成一個Query Key,Query Key包括條件查詢的請求一般信息:SQL, SQL需要的參數,記錄范圍(起始位置rowStart,最大記錄個數maxRows),等。 2) Hibernate根據這個Query Key到Query緩存中查找對應的結果列表。如果存在,那么返回這個結果列表;如果不存在,查詢數據庫,獲取結果列表,把整個結果列表根據Query Key放入到Query緩存中。 3) Query Key中的SQL涉及到一些表名,如果這些表的任何數據發生修改、刪除、增加等操作,這些相關的Query Key都要從緩存中清空。
來源:http://www.tianxiaboke.com/u/lyeerwy
級聯保存和更新 在運行上面的程序時,如果hibernate的"show-sql"設置為true時,就會看到Hibernate會生成很多sql語句,其實很多sql語句都是重復的 為了解決這個問題,我們可以利用在<set>標簽中加上inverse屬性。術語:inverse是指反轉的意思,在 Hibernate中,表示關聯關系中的方向關聯關系中,inverse="false"的主控方,由主動方負責維護對象關系我們 在customer對象的對象配置文件中加上 <set name="orders" cascade="save-update" inverse="true"> 聲明在Customer和Order的雙向關聯關系中,Customer端的關聯只是Order端關聯的鏡象(即Order端是主空端,負責維護 Customer和order對象之間的關聯關系),當hibernate探測到持久化對象Customer或Order的狀態發生變化時(主要是關聯關系的改變),僅按照Order對象的狀態的變化來同步更新數據庫。 映射一對多雙向關聯關系 具體實現<br> customer.getOrders().add(order);
5個最常問的幾個Hibernate面試問題,不一定你都能回答:
1.實體對象在Hibernate中如何進行狀態遷移? 2.何謂Hibernate的N+1問題,如何解決? 3.Hibernate延遲加載的機制是什么,如何工作? 4.Hibernate級聯保存要如何做? 5.Hibernate的二級緩存和一級緩存有什么區別? 延遲加載: 延遲加載機制是為了避免一些無謂的性能開銷而提出來的,所謂延遲加載就是當在真正需要數據的時候,才真正執行數據加載操作。在Hibernate中提供了對實體對象的延遲加載以及對集合的延遲加載,另外在Hibernate3中還提供了對屬性的延遲加載。下面我們就分別介紹這些種類的延遲加載的細節。 A、實體對象的延遲加載: 如果想對實體對象使用延遲加載,必須要在實體的映射配置文件中進行相應的配置,如下所示: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user” lazy=”true”> …… </class> </hibernate-mapping> 通過將class的lazy屬性設置為true,來開啟實體的延遲加載特性。如果我們運行下面的代碼: User user=(User)session.load(User.class,”1”);(1) System.out.println(user.getName());(2) 當運行到(1)處時,Hibernate并沒有發起對數據的查詢,如果我們此時通過一些調試工具(比如JBuilder2005的Debug工具),觀察此時user對象的內存快照,我們會驚奇的發現,此時返回的可能是User$EnhancerByCGLIB$$bede8986類型的對象,而且其屬性為 null,這是怎么回事?還記得前面我曾講過session.load()方法,會返回實體對象的代理類對象,這里所返回的對象類型就是User對象的代理類對象。在Hibernate中通過使用CGLIB,來實現動態構造一個目標對象的代理類對象,并且在代理類對象中包含目標對象的所有屬性和方法,而且所有屬性均被賦值為null。通過調試器顯示的內存快照,我們可以看出此時真正的User對象,是包含在代理對象的 CGLIB$CALBACK_0.target屬性中,當代碼運行到(2)處時,此時調用user.getName()方法,這時通過CGLIB賦予的回調機制,實際上調用CGLIB$CALBACK_0.getName()方法,當調用該方法時,Hibernate會首先檢查 CGLIB$CALBACK_0.target屬性是否為null,如果不為空,則調用目標對象的getName方法,如果為空,則會發起數據庫查詢,生成類似這樣的SQL語句:select * from user where id=’1’;來查詢數據,并構造目標對象,并且將它賦值到CGLIB$CALBACK_0.target屬性中。 這樣,通過一個中間代理對象,Hibernate實現了實體的延遲加載,只有當用戶真正發起獲得實體對象屬性的動作時,才真正會發起數據庫查詢操作。所以實體的延遲加載是用通過中間代理類完成的,所以只有session.load()方法才會利用實體延遲加載,因為只有session.load()方法才會返回實體類的代理類對象。 B、 集合類型的延遲加載: 在Hibernate的延遲加載機制中,針對集合類型的應用,意義是最為重大的,因為這有可能使性能得到大幅度的提高,為此Hibernate進行了大量的努力,其中包括對JDK Collection的獨立實現,我們在一對多關聯中,定義的用來容納關聯對象的Set集合,并不是java.util.Set類型或其子類型,而是 net.sf.hibernate.collection.Set類型,通過使用自定義集合類的實現,Hibernate實現了集合類型的延遲加載。為了對集合類型使用延遲加載,我們必須如下配置我們的實體類的關于關聯的部分: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set> </class> </hibernate-mapping> 通過將<set>元素的lazy屬性設置為true來開啟集合類型的延遲加載特性。我們看下面的代碼: User user=(User)session.load(User.class,”1”); Collection addset=user.getAddresses(); (1) Iterator it=addset.iterator(); (2) while(it.hasNext()){ Address address=(Address)it.next(); System.out.println(address.getAddress()); } 當程序執行到(1)處時,這時并不會發起對關聯數據的查詢來加載關聯數據,只有運行到(2)處時,真正的數據讀取操作才會開始,這時Hibernate會根據緩存中符合條件的數據索引,來查找符合條件的實體對象。 這里我們引入了一個全新的概念——數據索引,下面我們首先將接一下什么是數據索引。在Hibernate中對集合類型進行緩存時,是分兩部分進行緩存的,首先緩存集合中所有實體的id列表,然后緩存實體對象,這些實體對象的id列表,就是所謂的數據索引。當查找數據索引時,如果沒有找到對應的數據索引,這時就會一條select SQL的執行,獲得符合條件的數據,并構造實體對象集合和數據索引,然后返回實體對象的集合,并且將實體對象和數據索引納入Hibernate的緩存之中。另一方面,如果找到對應的數據索引,則從數據索引中取出id列表,然后根據id在緩存中查找對應的實體,如果找到就從緩存中返回,如果沒有找到,在發起select SQL查詢。在這里我們看出了另外一個問題,這個問題可能會對性能產生影響,這就是集合類型的緩存策略。如果我們如下配置集合類型: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <cache usage=”read-only”/> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set> </class> </hibernate-mapping> 這里我們應用了<cache usage=”read-only”/>配置,如果采用這種策略來配置集合類型,Hibernate將只會對數據索引進行緩存,而不會對集合中的實體對象進行緩存。如上配置我們運行下面的代碼: User user=(User)session.load(User.class,”1”); Collection addset=user.getAddresses(); Iterator it=addset.iterator(); while(it.hasNext()){ Address address=(Address)it.next(); System.out.println(address.getAddress()); } System.out.println(“Second query……”); User user2=(User)session.load(User.class,”1”); Collection it2=user2.getAddresses(); while(it2.hasNext()){ Address address2=(Address)it2.next(); System.out.println(address2.getAddress()); } 運行這段代碼,會得到類似下面的輸出: Select * from user where id=’1’; Select * from address where user_id=’1’; Tianjin Dalian Second query…… Select * from address where id=’1’; Select * from address where id=’2’; Tianjin Dalian 我們看到,當第二次執行查詢時,執行了兩條對address表的查詢操作,為什么會這樣?這是因為當第一次加載實體后,根據集合類型緩存策略的配置,只對集合數據索引進行了緩存,而并沒有對集合中的實體對象進行緩存,所以在第二次再次加載實體時,Hibernate找到了對應實體的數據索引,但是根據數據索引,卻無法在緩存中找到對應的實體,所以Hibernate根據找到的數據索引發起了兩條select SQL的查詢操作,這里造成了對性能的浪費,怎樣才能避免這種情況呢?我們必須對集合類型中的實體也指定緩存策略,所以我們要如下對集合類型進行配置: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user”> ….. <set name=”addresses” table=”address” lazy=”true” inverse=”true”> <cache usage=”read-write”/> <key column=”user_id”/> <one-to-many class=”com.neusoft.entity.Arrderss”/> </set> </class> </hibernate-mapping> 此時Hibernate會對集合類型中的實體也進行緩存,如果根據這個配置再次運行上面的代碼,將會得到類似如下的輸出: Select * from user where id=’1’; Select * from address where user_id=’1’; Tianjin Dalian Second query…… Tianjin Dalian 這時將不會再有根據數據索引進行查詢的SQL語句,因為此時可以直接從緩存中獲得集合類型中存放的實體對象。 C、 屬性延遲加載: 在Hibernate3中,引入了一種新的特性——屬性的延遲加載,這個機制又為獲取高性能查詢提供了有力的工具。在前面我們講大數據對象讀取時,在 User對象中有一個resume字段,該字段是一個java.sql.Clob類型,包含了用戶的簡歷信息,當我們加載該對象時,我們不得不每一次都要加載這個字段,而不論我們是否真的需要它,而且這種大數據對象的讀取本身會帶來很大的性能開銷。在Hibernate2中,我們只有通過我們前面講過的面性能的粒度細分,來分解User類,來解決這個問題(請參照那一節的論述),但是在Hibernate3中,我們可以通過屬性延遲加載機制,來使我們獲得只有當我們真正需要操作這個字段時,才去讀取這個字段數據的能力,為此我們必須如下配置我們的實體類: <hibernate-mapping> <class name=”com.neusoft.entity.User” table=”user”> …… <property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/> </class> </hibernate-mapping> 通過對<property>元素的lazy屬性設置true來開啟屬性的延遲加載,在Hibernate3中為了實現屬性的延遲加載,使用了類增強器來對實體類的Class文件進行強化處理,通過增強器的增強,將CGLIB的回調機制邏輯,加入實體類,這里我們可以看出屬性的延遲加載,還是通過 CGLIB來實現的。CGLIB是Apache的一個開源工程,這個類庫可以操縱java類的字節碼,根據字節碼來動態構造符合要求的類對象。根據上面的配置我們運行下面的代碼: String sql=”from User user where user.name=’zx’ ”; Query query=session.createQuery(sql); (1) List list=query.list(); for(int i=0;i<list.size();i++){ User user=(User)list.get(i); System.out.println(user.getName()); System.out.println(user.getResume()); (2) } 當執行到(1)處時,會生成類似如下的SQL語句: Select id,age,name from user where name=’zx’; 這時Hibernate會檢索User實體中所有非延遲加載屬性對應的字段數據,當執行到(2)處時,會生成類似如下的SQL語句: Select resume from user where id=’1’; 這時會發起對resume字段數據真正的讀取操作。 讓Spring架構減化事務配置
注:原創文章,本文曾發表于it168 Spring顛覆了以前的編程模式,引入了IOC等全新的概念,廣受大家的喜愛。目前大多數j2ee項目都已經采用Spring框架。Spring最大的問題是太多的配置文件,使得你不僅需要維護程序代碼,還需要額外去維護相關的配置文件。最典型的就是事務配置(注:這里的“事務配置”都指“聲明式事務配置”),在Spring中進行事務配置除了定義對象自身的bean外,還需要定義一個進行事務代理的bean.如果你有n個類需要引入事務,那么你就必須定義2n個bean。維護這些bean的代價是十分昂貴的,所以必須要對事務配置進行減化。如果你是基于Spring進行架構設計,那么作為一個好的架構設計師,應該把一些公共的方面進行簡化,讓項目的開發人員只關心項目的業務邏輯,而不要花費太多的精力去關心業務邏輯之外的太多東西。所以作為一個好的架構就應該把事務管理進行簡化,讓程序員花在編程之外的工作最小化。 1. Spring聲明式事務配置的幾種方法 在Spring中進行事務控制首先要選擇適當的事務管理器,其次為程序選擇劃分事務的策略。如果只有單個事務性資源,可以從“單一資源”的PlatformTransactionManger實現當中選擇一個,這些實現有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根據你所采用的數據庫持久化技術選擇。如果你的項目運行于支持JTA的服務器,那么將選擇JtaTransactionManger,將會支持多資源事務。 下表將為你選擇適當的事務管理器提供參考。 技術 事務管理器 內建的事務支持 JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有類 IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate JMS JmsTransactionManager JmsTemplate 在劃分事務時,我們需要進行事務定義,也就是配置事務的屬性。事務的屬性有傳播行業,隔離級別,超時值及只讀標志。TransactionAttribute接口指定哪些異常將導致一個回滾,哪些應該一次性提交。 (1) 使用ProxyFactoryBean 和TransactionInterceptor <!--定義本地數據源--> <bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- !定義單個jdbc數據源的事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!—定義攔截器--> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定義業務對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定義業務對象的事務代理對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean"> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target"> </property> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> </bean> 通過ProxyFacgtoryBean和TransactionInterceptor組合使用,可以對事務進行更多的控制。所有需要事務控制的對象可以共享一個transactionInterceptor的事務屬性。 (2) 使用TransactionProxyFactoryBean <!—定義業務對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定義業務對象的事務代理對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target" /> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> 使用TransactionProxyFactoryBean需要為每一個代理對象都去定義自己的事務屬性。 (3) 使用TransactionProxyFactoryBean及abstract屬性來簡化配置 這種方工也是目前使用得最多的一種聲明式事務配置方法 <!--事務控制代理抽象定義 --> <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定義業務對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定義業務對象的事務代理對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy"> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target"> </property> </bean> 使用abstract屬性,可以讓代理對象可以共享一個定義好的事務屬性,使配置簡化。 (4)使用BeanNameAutoProxyCreator <!—定義攔截器--> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定義bean別名自動代理創建器--> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> <property name="beanNames"> <list> <idref local="com.prs.application.ehld.sample.biz.service.sampleService"/> </list> </property> </bean> <!—定義業務對象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> 使用BeanNameAutoProxyCreator可以由框架來提供適當的代理,由一個transactionInterceptor統一定義事務屬性,只需要把需要事務控制的bean加到beannames的列表。 對于需要大量聲明式事務的bean,BeanNameAutoProxyCreator是十分方便的。減少了代理bean的定義,還可以靈活的決定一個bean是否進行事務控制。 上面四種方法是在Spring中常見的聲明式事務配置方法,其中使用TransactionProxyFactoryBean及abstract屬性進行配置是最常見的簡化方法。 http://www.iteye.com/topic/72435 一.
使用TransactionProxyFactoryBean創建事務代理(通常事務代理以Service層為目標bean) <bean id="personService" class="com.lin.personServiceImpl"> <property name="personDao" ref="personDao"/> </bean> //配置hibernate的事務管理器,使用HibernateTransactionManager類,該類實現了PlatformTransactionManager接口,針對hibernate 持久化連接的特定實現 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> //配置personService bean的事務代理 <bean id="personServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> //指定事務管理器 <property name="transactionManager" ref="transactionManager"/> //指定需要生成代理的日標bean <property name="persionService" ref="persionService"/> //指定事務屬性 <property name="transactionAttributes" <props> <prop key="insert*">PROPAGATION_REQUIRED,-MyCheckedException</prop> <prop key="update*>PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> </props> </property> 二.使用自動創建代理簡化事務配置 使用BeanNameAutoProxyCreator 和DefaultAdvisorAutoProxyCreator創建代理時,并不一定是創建事務代理,關鍵在于傳入的攔截器,如果傳入事務攔截器,將可自動生成事務代理. //使用jdbc局部事務策略 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> //配置目標bean1,該目標bean將由Bean后處理器自動生成代理 <bean id="testbean1" class="com.lin.Testbean1Impl"> <property name="dataSource" ref="dataSource"/> </bean //配置目標bean2,該目標bean將由Bean后處理器自動生成代理 <bean id="testbean2" class="com.lin.Testbean2Impl"> <property name="dataSource" ref="dataSource"/> </bean //配置事務攔截器bean <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> //事務攔截器需要注入一個事務管理器 <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> //定義BeanNameAutoProxyCreator的Bean后處理器 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>testbean1</value> <value>testbean2</value> </list> //此處可以增加其他需要創建事務代理的bean </property> //定義BeanNameAutoProxyCreator所需要的攔截器 <property name="interceptorNames"> <list> <value>transactionInterceptor</value> //此處可以增加其他新的Interceptor </list> </property> </bean> |