??? 在使用Hibernate的應用中, Spring的對DAO對象通常的事務管理特別應該引起關注。它的目的就是分離數(shù)據(jù)訪問和事務處理,使事務性業(yè)務對象不與任何特殊的數(shù)據(jù)訪問或者事務策略綁在一起,從而不影響業(yè)務對象的可復用性。這種劃分既可以經(jīng)由事務模板(TransactionTemplate)用編程的方式實現(xiàn),也可以經(jīng)由面向方面(AOP)事務攔截器(TransactionTemplate)用聲明的方式實現(xiàn)。無論是本地的Hibernate / JDBC事務,還是JTA事務都支持對象外的事務策略,這對于本地的無狀態(tài)會話Bean(Stateless Session Beans)是一個非常有用的選擇。
??? Spring的HibernateTemplate類提供了一個簡單的方式實現(xiàn)了Hibernate-based DAO對象而不必關心如何獲得Hibernate的Session實例,也不必關心多方參與的事務處理。無需使用try-catch塊,也無需進行事務檢查。一個簡單的Hibernate訪問方法就完全解決了些麻煩! 無論是在多個DAO接口還是在多方事務的情況下,Spring使得多種DAO對象無縫地協(xié)同工作。例如:某些DAO對象可能是基于plain JDBC的實現(xiàn),更適合于經(jīng)由Spring的JdbcTemplate來避免手動的異常處理。
????? 你可以單獨地使用許多Spring特性,因為Spring的所有對象都是設計成可復用的JavaBean對象的集合。也不要因為Spring可以提供一個完整的應該框架而氣餒!使用其他的Spring特性時,應用配置概念是一個附加的特性,并不是一個必須的特性。無論如何,當你要決定去構(gòu)建一個象Spring這樣的內(nèi)在的基礎架構(gòu)的時候,在使用Spring的路途上沒有什么范圍上的限制。
1. 介紹: 資源管理
?????? 典型的業(yè)務應用系統(tǒng)常常由于重復的資源管理代碼而導致混亂。許多項目試著用自己的方法來解決這個問題,有時要為此付出失敗的代價,Spring針對適當?shù)馁Y源管理提倡了一種引人注目的簡單方法:即經(jīng)由模板來倒置控制(Inversion of control),例如:基礎類使用回調(diào)接口,或者應用AOP攔截器。其基礎核心是適當?shù)馁Y源處理和將特殊的API異常轉(zhuǎn)換為一個unchecked的基礎異常。
?????? Spring引入了一個DAO異常層適用于任何數(shù)據(jù)訪問策略。對于直接的JDBC,JdbcTemplate類關注于連接處理,并且關注于對SQLException轉(zhuǎn)換為適當?shù)腄ataAccessException,包括對特殊的數(shù)據(jù)庫SQL錯誤轉(zhuǎn)換為有意義的異常。 經(jīng)由不同的事務管理對象,Spring支持JTA和JDBC事務。Spring 也提供對Hibernate和JDO的支持,它的這種支持由與JdbcTemplate類的作用相類似的HibernateTemplate類和JdoTemplate類, 以及HibernateInterceptor類、JdoInterceptor類,還有Hibernate、JDO 事務管理類組成。
?????? 最主要的目的是要使應用的層次分明,為此將數(shù)據(jù)訪問和事務處理同應用對象分離開來。所有的業(yè)務對象都不再依賴數(shù)據(jù)訪問或者事務策略。不再有硬編碼的資源查找代碼,不再有難以替換的單例對象,也不再需要定制服務注冊。
????? 所有的單獨的數(shù)據(jù)訪問特性均無需依賴于Spring,可以單獨使用,無需讓Spring知道,同時也可以通過Spring的應用配置(提供基于XML的配置和對普通JavaBean實例的交叉引用)來進行裝配。在一個典型的Spring應用中,大部分重要的對象都是普通的JavaBean:數(shù)據(jù)訪問模板對象(data access templates)、數(shù)據(jù)訪問對象(使用數(shù)據(jù)訪問模板對象的對象)、事務管理對象及業(yè)務對象(使用數(shù)據(jù)訪問對象和事務對象的對象),web表示分解對象、web控制對象(使用業(yè)務對象的對象)等等。
2. 應用配置中的資源定義
??? 為了避免應用對象將資源查找的代碼硬編碼,Spring允許在應用配置中將一個如JDBC DataSource或者Hibernate SessionFactory定義為一個Bean。應用對象如果需要訪問資源只需要通過Bean引用(DAO定義在下一部分說明)接受先前定義的實例的引用。以下的內(nèi)容引用自一個應用配置定義,顯示了如何建立一個JDBC DataSource和一個Hibernate的SessionFactory:
?<beans> .JndiObjectFactoryBean"> .LocalSessionFactoryBean"> .MySQLDialect</prop> |
??? ? 注意選擇是用JNDI來定位數(shù)據(jù)源還是從一個象Jakarta Commons DBCP BasicDataSource這樣的本地定義取得一個數(shù)據(jù)源,只是一個改變配置的事:
<bean id="myDataSource" .dbcp.BasicDataSource" destroy-method="close"> |
???? ? 你也可以使用一個JNDI查找SessionFactory,但是通常對于EJB環(huán)境之外的應用來說并不是需要的(參考"container resources vs local resources"部分的討論)。
3. 倒置控制(Inversion of Control): 模板和回調(diào)
??? 模板的基本編程模式就象你將在下面看到那樣,至于方法就如同任何定制的數(shù)據(jù)訪問對象或者業(yè)務的對象的方法一樣。除了需要向其提供一個Hibernate的SessionFactory之外,再沒有對周圍執(zhí)行對象的信賴的限制。雖然最好是從一個Spring的應用配置中經(jīng)由一個簡單setSessionFactory bean的屬性設置使用Bean引用來獲得它,但隨后你可以從任何地方獲得它。隨后的引用片段包括一段在Spring應用配置中對DAO定義的配置,其中引用了在其前面定義的SessionFactory,和一段DAO方法的實現(xiàn)的例子。
<beans> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> ... </beans> |
public class ProductDaoImpl implements ProductDao { private SessionFactory sessionFactory; public void setSessionFactory(SessionFactorysessionFactory) { this.sessionFactory = sessionFactory; } public List loadProductsByCategory(final Stringcategory) { HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory); return (List) hibernateTemplate.execute( new HibernateCallback() { public Object doInHibernate(Session session) throwsHibernateException { List result = session.find( "from test.Product product where product.category=?", category, Hibernate.STRING); // do some further stuff with the result list return result; } } ); } } |
?????? 一個回調(diào)的實現(xiàn)可以被有效地用在任何Hibernate數(shù)據(jù)訪問中。在任何情況下都由HibernateTemplate來管理Session的開閉和自動的多方事務。模板實例是線程安全和可重用的,因此它們可以做為其他類的變量。
?????? 對于簡單的單步的動作,象find, load, saveOrUpdate或者delete的調(diào)用,HibernateTemplate提供更為便利的選擇以代替象一行的回調(diào)的執(zhí)行。此外,Spring提供了一個方便的基本類,就是HibernateDaoSupport類,它提供了setSessionFactory方法來接受一個SessionFactory,同時提供了getSessionFactory和getHibernateTemplate方法供其繼承類使用。將這些結(jié)合起來,允許對于典型的需求給出了非常簡單的DAO實現(xiàn):
public class ProductDaoImpl extends HibernateDaoSupport implementsProductDao { public List loadProductsByCategory(String category) { return getHibernateTemplate().find( "from test.Product product where product.category=?", category, Hibernate.STRING); } } |
4. 應用一個AOP攔截器代替一個模板
?? 除使用HibernateTemplate之外的另一個選擇就是使用Spring的AOP HibernateInterceptor。用直接在一個委托的try/catch塊中編寫Hibernate代碼,配合相應的在應用配置中分別的攔截器配置來代替執(zhí)行回調(diào)。下面的片段顯示了一個Spring應用配置中的DAO, interceptor和proxy的各自的定義,同時給出了一個DAO方法實現(xiàn)的例子:
<beans> ... <bean id="myHibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductDaoTarget" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductDao" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>product.ProductDao</value> </property> <property name="interceptorNames"> <list> <value>myHibernateInterceptor</value> <value>myProductDaoTarget</value> </list> </property> </bean> ... </beans> |
?public class ProductDaoImpl extends HibernateDaoSupportimplements ProductDao { public List loadProductsByCategory(final String category)throws MyException { Session session = SessionFactoryUtils.getSession(getSessionFactory(), false); try { List result = session.find( "from test.Product product where product.category=?", category, Hibernate.STRING); if (result == null) { throw new MyException("invalid search result"); } return result; } catch (HibernateException ex) { throw SessionFactoryUtils.convertHibernateAccessException(ex); } } } |
??????? 這個方法將只在有一個與它配合的HibernateInterceptor時才能正常工作,HibernateInterceptor為它負責在方法調(diào)用前線程綁定Session的開啟和方法調(diào)用后的關閉。getSession方法調(diào)用中的"false"標志是要確認Session必須是已經(jīng)存在的,如果沒有發(fā)現(xiàn)任何一個Session,SessionFactoryUtils將會為其創(chuàng)建一個。如果已經(jīng)有一個Session句柄綁定在本線程上,比如是由一個HibernateTransactionManager事務綁定的,在任何情況下SessionFactoryUtils會自動接入這個Session。HibernateTemplate在底層也使用SessionFactoryUtils,與以上說的方式基本是一樣的。
?????? HibernateInterceptor的主要益處是它允許在數(shù)據(jù)訪問代碼中拋出checked application exception,而HibernateTemplate由于受限于回調(diào)只能在其中拋出unchecked exceptions。注意到這點我們可以推遲各自的檢驗,同時在回調(diào)后拋出應用異常。攔截方式的主要缺點是它需要在配置中進行特殊的配置。HibernateTemplate在大多數(shù)情況下都是一種簡單好用的方法。
5. 程序事務劃分
?? 在這種底層的數(shù)據(jù)訪問服務之上,事務處理可以在更高的應用層被劃分 ,形成一些操作。這里除了需要一個Spring的PlatformTransactionManager對象外,對于周圍運行的業(yè)務對象也沒有任何限制。同樣的,其后你可以從任何地方獲得它們,但是經(jīng)由Bean引用的方式通過setTransactionManage方法獲得更為適合,象productDAO要經(jīng)由一個setProductDao方法獲得一樣。下面的引用片段顯示了在一個Spring應用配置中的事務管理對象和業(yè)務對象的定義,并且還提供了一個業(yè)務方法實現(xiàn)的例子:
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductService" class="product.ProductServiceImpl"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> </beans> |
?public class ProductServiceImpl implements ProductService { private PlatformTransactionManager transactionManager; private ProductDao productDao; public void setTransactionManager(PlatformTransactionManagertransactionManager) { this.transactionManager = transactionManager; } public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final Stringcategory) { TransactionTemplate transactionTemplate = new TransactionTemplate(this.transactionManager); transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); transactionTemplate.execute( new TransactionCallbackWithoutResult() { public void doInTransactionWithoutResult(TransactionStatusstatus) { List productsToChange = productDAO.loadProductsByCategory(category); ... } } ); } } |
6. 聲明性事務劃分
?????? 我們還可以選擇使用Spring的AOP TransactionInterceptor通過在應用配置中定義攔截器配置來代替事務劃分代碼的事務處理方式。這允許我們保持業(yè)務對象獨立于每個業(yè)務對象中重復的事務劃分代碼。此外,事務行為和隔離層次的變化可以通過一個配置文件來改變而不需要對業(yè)務對象的實現(xiàn)造成影響。
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myTransactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="transactionAttributeSource"> <value> product.ProductService.increasePrice*=PROPAGATION_REQUIRED product.ProductService.someOtherBusinessMethod=PROPAGATION_MANDATORY </value> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>product.ProductService</value> </property> <property name="interceptorNames"> <list> <value>myTransactionInterceptor</value> <value>myProductServiceTarget</value> </list> </property> </bean> </beans> |
?public class ProductServiceImpl implements ProductService { private ProductDao productDao; public void setProductDao(ProductDao productDao) { this.productDao = productDao; } public void increasePriceOfAllProductsInCategory(final Stringcategory) { List productsToChange = this.productDAO.loadProductsByCategory(category); ... } } |
???? ?如同使用HibernateInterceptor一樣,TransactionInterceptor允許任何checked application exception從回調(diào)代碼中拋出,而TransactionTemplate受回調(diào)限制在其內(nèi)部拋出unchecked exceptions,在出現(xiàn)一個unchecked application exception的情況時,TransactionTemplate將引發(fā)一個回滾或者這個事務由應用(通過事務狀態(tài))標記為回滾。TransactionInterceptor默認情況也是同樣的行為,但是允許為每一個方法制定回滾策略。
????? ?建立聲明性事務的一個便利的方式是使用TransactionProxyFactoryBean,特別是如果沒有其他AOP攔截器的話,TransactionProxyFactoryBean將聯(lián)合定義為代理的自身與一個特殊的目標Bean的事務配置。這將減少一個代理Bean對應一個目標Bean的配置情況。此外,你不必指定哪個接口或者哪個類必須定義事務方法。
<beans> ... <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager"> <property name="sessionFactory"> <ref bean="mySessionFactory"/> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="target"> <ref bean="myProductServiceTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="increasePrice*">PROPAGATION_REQUIRED</prop> <prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop> </props> </property> </bean> </beans> |
7. 事務管理策略
????????? 對于Hibernate應用來說,無論是TransactionTemplate還是TransactionInterceptor都是委托驗實際的事務處理給PlatformTransactionManager實例,可以是一個HibernateTransactionManager(由一個單一的Hibernate的SessionFactory,使用一個ThreadLocal Session)或者可以是一個JtaTransactionManager(代理容器的JTA子系統(tǒng))。甚至你可以使用一個自定義的PlatformTransactionManager實現(xiàn)。
????? ?如果選擇從本地Hibernate事務管理轉(zhuǎn)為由JTA來進行事務管理,例如:當你的應用的部署面對分布的事務需求時,也僅僅是改變一下配置的事。只要簡單地將Hibernate的事務管理換為JTA事務實現(xiàn)即可。所有的事務劃分和數(shù)據(jù)訪問無需做任何變動仍可以繼續(xù)工作,因為他們使用的都是普通的事務管理API。
?????? 對于分布式的事務會跨越多個Hibernate的session factories,僅僅是聯(lián)合JtaTransactionManager與多個LocalSessionFactoryBean定義作為事務策略。你的每一個DAO將通過它們各自的Bean屬性得到一個特殊的SessionFactory的引用。如果這一切都是在下面的JDBC數(shù)據(jù)源是事務容器,一個業(yè)務對象可以劃分事務跨越很多DAO和很多session factories而無需做特別的處理,對于使用JtaTransactionManager做為事務策略也是一樣的。
?<beans> <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jdbc/myds1</value> </property> </bean> <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>jdbc/myds2</value> </property> </bean> <bean id="mySessionFactory1" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>product.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop> </props> </property> <property name="dataSource"> <ref bean="myDataSource1"/> </property> </bean> <bean id="mySessionFactory2" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>inventory.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop> </props> </property> <property name="dataSource"> <ref bean="myDataSource2"/> </property> </bean> <bean id="myTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> <bean id="myProductDao" class="product.ProductDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory1"/> </property> </bean> <bean id="myInventoryDao" class="product.InventoryDaoImpl"> <property name="sessionFactory"> <ref bean="mySessionFactory2"/> </property> </bean> <bean id="myProductServiceTarget" class="product.ProductServiceImpl"> <property name="productDao"> <ref bean="myProductDao"/> </property> <property name="inventoryDao"> <ref bean="myInventoryDao"/> </property> </bean> <bean id="myProductService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref bean="myTransactionManager"/> </property> <property name="target"> <ref bean="myProductServiceTarget"/> </property> <property name="transactionAttributes"> <props> <prop key="increasePrice*">PROPAGATION_REQUIRED</prop> <prop key="someOtherBusinessMethod">PROPAGATION_MANDATORY</prop> </props> </property> </bean> </beans> |
????? ?無論是HibernateTransactionManager還是JtaTransactionManager允許適當?shù)膶ibernate的在JVM層次的緩存處理-不需要容器-提供特殊的事務查找或者JCA連接器(只要不使用EJB發(fā)起事務)。另外,HibernateTransactionManager能輸出JDBC連接供通常的JDBC訪問代碼使用。這樣就允許在高層次上的事務劃分是混合了Hibernate與JDBC而不要JTA的,只要只是訪問一個數(shù)據(jù)庫就可以!
8. 使用Spring管理應用的Bean
??????? 一個Spring應用配置定義可以被多種配置實現(xiàn)所加載,從FileSystemXmlApplicationContext和ClassPathXmlApplicationContext到XmlWebApplicationContext。這就允許在各種環(huán)境下重用Spring管理的數(shù)據(jù)訪問和業(yè)務對象。默認情況下,一個Web應用將有它自己的定義在“WEB-INF/applicationContext.xml”中的根配置。
?????? 在任何一個Spring應用中,一個應用配置定義在一個XML格式的文件中用來對應用的所有有關的Bean進行裝配,從Hibernate的session factory到自定義的數(shù)據(jù)訪問和業(yè)務對象(象上面所有的Bean那樣)。他們中的大多數(shù)不需要Spring容器知道他們,甚至即使是與其他Bean合作時也一樣,因為他們只是簡單的JavaBean之間的協(xié)作。下面的Bean定義可能是一個Spring Web 的MVC配置中用來訪問業(yè)務對象的配置的一部分。
?<bean id="myProductList" class="product.ProductListController"> <property name="productService"> <ref bean="myProductService"/> </property> </bean> |
????? Spring的Web控制器經(jīng)由Bean引用擁有它們需要的所有的業(yè)務和數(shù)據(jù)訪問對象,因此它們無需在應用配置中做任何手工的Bean查找。但是當使用Spring管理的Beans用于Struts或者是在EJB實現(xiàn),或者一個applet中時常常是需要必須手工查找一個Bean的。因此Spring的Bean可以被用在任何地方。也許只是需要是一應用配置的引用,或者經(jīng)由一個web容器的Servlet配置屬性,或者從一個文件中或者類路徑的資源中創(chuàng)建它。
ApplicationContext context =WebApplicationContextUtils.getWebApplicationContext(servletContext); ProductService productService = (ProductService) context.getBean("myProductService"); |
?ApplicationContext context = new FileSystemXmlApplicationContext("C:/myContext.xml"); ProductService productService = (ProductService) context.getBean("myProductService"); |
?ApplicationContext context = new ClassPathXmlApplicationContext("myContext.xml"); ProductService productService = (ProductService) context.getBean("myProductService"); |
9. 容器資源VS本地資源
?????? Spring的資源管理允許簡單地在一個JNDI SessionFactory和一個本地SessionFactory間做選擇,同樣允許在一個JNDI DataSource與本地DataSource間做選擇,而無需改變應用的一行代碼。在容器中保存資源定義還是在應用本地保存,主要是一個事務策略方面的事。比較一個Spring定義的本地SessionFactory與一個手工注冊的JNDI SessionFactory沒有任何益處。如果經(jīng)由Hibernate的JCA連接器注冊,才會有加入JTA事務的明顯益處,特別是對EJB。
?????? 一個重要的Spring事務提供的好處是它不與任何容器綁定。定義包括JTA在內(nèi)的策略,它都可以獨立工作或者在一個試驗環(huán)境中工作。特別是對典型的一個數(shù)據(jù)庫的事務來說,對于JTA這是一個非常輕量的和強大的選擇。當使用本地EJB SLSB的事務時,你將同時依賴EJB容器和JTA-即使你只是訪問一個數(shù)據(jù)庫,即使只是使用SLSBs經(jīng)由CMT來聲明事務。選擇使用 JTA編程也需要一個J2EE環(huán)境。
?????? 就JTA自身和JNDI數(shù)據(jù)源來說JTA不只是包括容器依賴。對于不使用Spring的JTA驅(qū)動的Hibernate事務,你必須使用HibernateJCA連接器或者在合適的JVM緩沖層專門寫Hibernate的事務代碼配置JTA事務。在只訪問一個數(shù)據(jù)庫的情況下,Spring驅(qū)動的事務可以與一個本地定義的Hibernate的SessionFactory配合良好,就如同與一個本地JDBC數(shù)據(jù)源相配合一樣。因此當面對分布的事務需求時,你只需要轉(zhuǎn)換為Spring的JTA事務策略即可。
????? ?要注意一個JCA連接器需要特別的容器的部署步驟,并且顯然首先得支持JCA。這比使用本地資源定義和Spring驅(qū)動事務來部署一個簡單的Web應用有更多的爭議。而且你常常需要企業(yè)版本的容器支持,象WebLogic Express就不提供JCA。一個只用一個數(shù)據(jù)庫的使用本地資源和事務的Spring應用可以在任何J2EE的Web容器中工作,Web容器不必支持JTA, JCA和EJB,如:Tomcat, Resin甚至最小的Jetty。另外,這樣一個中間層就可以很容易地在桌面應用或者在測試套件中被重用。
?????? 所有考慮過的事情包括:如果你不使用EJB,堅持使用本地SessionFactory,使用SpringHibernateTransactionManager或者JtaTransactionManager,你將獲得包括適當處理的JVM層的緩存和分布事務的所有益處,而無需引起任何關于容器部署的爭論。經(jīng)由JCA連接器的一個Hibernate的SessionFactory的JNDI注冊只是在使用EJB的情況中才會有明顯的附加值。
10. Skeletons和例子
????? 配置使用Spring和HIbernate的一個J2EE的Web應用的注釋和細節(jié)最好去看看在Spring Framework的例子中的“典型的Web應用”Skeletons,它給出了適合于JDBC 和 Hibernate應用的多種數(shù)據(jù)源及事務管理的配置項,仔細看一下事務攔截器的配置,它也同樣向你展示了如何配置AOP攔截器。
????? 在Spring的1.0 M2版中,例子Petclinic提供了JDBC和Hibernate的DAO實現(xiàn)和應用配置的選擇。Petclinic
可以作為一個可工作的簡單應用說明如何在一個Spring web 應用中使用Hibernate,同樣也包括根據(jù)不同的事務策略來聲明事務劃分。