cmd

          Spring讓Hibernate使用者受益良多

          Spring的輕量級的bean容器為業務對象(business objects)、DAO對象和資源(如:JDBC數據源或者Hibernate SessionFactorie等)對象提供了IoC類型的裝配能力。Spring使用一個xml格式的應用配置文件為開發者提供了一種通過解析定制的屬性文件來手動管理單實例對象或者工廠對象的選擇性。由于Spring將非入侵性做為一個重要的目標,因此可以由Spring配置管理的bean對象均不需要依賴Spring自有的接口和類就可以通過它們的bean屬性完成配置。這個概念可以被應用到任何環境中,無論你開發的是一個J2EE的web應用還是一個桌面應用甚至只是一個applet都可以。

          ??? 在使用Hibernate的應用中, Spring的對DAO對象通常的事務管理特別應該引起關注。它的目的就是分離數據訪問和事務處理,使事務性業務對象不與任何特殊的數據訪問或者事務策略綁在一起,從而不影響業務對象的可復用性。這種劃分既可以經由事務模板(TransactionTemplate)用編程的方式實現,也可以經由面向方面(AOP)事務攔截器(TransactionTemplate)用聲明的方式實現。無論是本地的Hibernate / JDBC事務,還是JTA事務都支持對象外的事務策略,這對于本地的無狀態會話Bean(Stateless Session Beans)是一個非常有用的選擇。

          ??? Spring的HibernateTemplate類提供了一個簡單的方式實現了Hibernate-based DAO對象而不必關心如何獲得Hibernate的Session實例,也不必關心多方參與的事務處理。無需使用try-catch塊,也無需進行事務檢查。一個簡單的Hibernate訪問方法就完全解決了些麻煩! 無論是在多個DAO接口還是在多方事務的情況下,Spring使得多種DAO對象無縫地協同工作。例如:某些DAO對象可能是基于plain JDBC的實現,更適合于經由Spring的JdbcTemplate來避免手動的異常處理。

          ????? 你可以單獨地使用許多Spring特性,因為Spring的所有對象都是設計成可復用的JavaBean對象的集合。也不要因為Spring可以提供一個完整的應該框架而氣餒!使用其他的Spring特性時,應用配置概念是一個附加的特性,并不是一個必須的特性。無論如何,當你要決定去構建一個象Spring這樣的內在的基礎架構的時候,在使用Spring的路途上沒有什么范圍上的限制。

          1. 介紹: 資源管理

          ?????? 典型的業務應用系統常常由于重復的資源管理代碼而導致混亂。許多項目試著用自己的方法來解決這個問題,有時要為此付出失敗的代價,Spring針對適當的資源管理提倡了一種引人注目的簡單方法:即經由模板來倒置控制(Inversion of control),例如:基礎類使用回調接口,或者應用AOP攔截器。其基礎核心是適當的資源處理和將特殊的API異常轉換為一個unchecked的基礎異常。

          ?????? Spring引入了一個DAO異常層適用于任何數據訪問策略。對于直接的JDBC,JdbcTemplate類關注于連接處理,并且關注于對SQLException轉換為適當的DataAccessException,包括對特殊的數據庫SQL錯誤轉換為有意義的異常。 經由不同的事務管理對象,Spring支持JTA和JDBC事務。Spring 也提供對Hibernate和JDO的支持,它的這種支持由與JdbcTemplate類的作用相類似的HibernateTemplate類和JdoTemplate類, 以及HibernateInterceptor類、JdoInterceptor類,還有Hibernate、JDO 事務管理類組成。

          ?????? 最主要的目的是要使應用的層次分明,為此將數據訪問和事務處理同應用對象分離開來。所有的業務對象都不再依賴數據訪問或者事務策略。不再有硬編碼的資源查找代碼,不再有難以替換的單例對象,也不再需要定制服務注冊。

          ????? 所有的單獨的數據訪問特性均無需依賴于Spring,可以單獨使用,無需讓Spring知道,同時也可以通過Spring的應用配置(提供基于XML的配置和對普通JavaBean實例的交叉引用)來進行裝配。在一個典型的Spring應用中,大部分重要的對象都是普通的JavaBean:數據訪問模板對象(data access templates)、數據訪問對象(使用數據訪問模板對象的對象)、事務管理對象及業務對象(使用數據訪問對象和事務對象的對象),web表示分解對象、web控制對象(使用業務對象的對象)等等。

          2. 應用配置中的資源定義

          ??? 為了避免應用對象將資源查找的代碼硬編碼,Spring允許在應用配置中將一個如JDBC DataSource或者Hibernate SessionFactory定義為一個Bean。應用對象如果需要訪問資源只需要通過Bean引用(DAO定義在下一部分說明)接受先前定義的實例的引用。以下的內容引用自一個應用配置定義,顯示了如何建立一個JDBC DataSource和一個Hibernate的SessionFactory:

          ?<beans>

          <bean id="myDataSource" class="org.springframework.jndi

          .JndiObjectFactoryBean">
          <property name="jndiName">
          <value>jdbc/myds</value>
          </property>
          </bean>

          <bean id="mySessionFactory" 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="myDataSource"/>
          </property>
          </bean>

          ...

          </beans>

          ??? ? 注意選擇是用JNDI來定位數據源還是從一個象Jakarta Commons DBCP BasicDataSource這樣的本地定義取得一個數據源,只是一個改變配置的事:

          <bean id="myDataSource"
          ????? class="org.apache.commons

          .dbcp.BasicDataSource" destroy-method="close">
          <property name="driverClassName">
          <value>org.hsqldb.jdbcDriver</value>
          </property>
          <property name="url">
          <value>jdbc:hsqldb:hsql://localhost:9001</value>
          </property>
          <property name="username">
          <value>sa</value>
          </property>
          <property name="password">
          <value></value>
          </property>
          </bean>

          ???? ? 你也可以使用一個JNDI查找SessionFactory,但是通常對于EJB環境之外的應用來說并不是需要的(參考"container resources vs local resources"部分的討論)。

          3. 倒置控制(Inversion of Control): 模板和回調

          ??? 模板的基本編程模式就象你將在下面看到那樣,至于方法就如同任何定制的數據訪問對象或者業務的對象的方法一樣。除了需要向其提供一個Hibernate的SessionFactory之外,再沒有對周圍執行對象的信賴的限制。雖然最好是從一個Spring的應用配置中經由一個簡單setSessionFactory bean的屬性設置使用Bean引用來獲得它,但隨后你可以從任何地方獲得它。隨后的引用片段包括一段在Spring應用配置中對DAO定義的配置,其中引用了在其前面定義的SessionFactory,和一段DAO方法的實現的例子。

          												<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(SessionFactory 
          												
          														   sessionFactory) {
          this.sessionFactory = sessionFactory;
          }
          
          public List loadProductsByCategory(final String 
          												
          														  category) {
          HibernateTemplate hibernateTemplate =
          new HibernateTemplate(this.sessionFactory);
          
          return (List) hibernateTemplate.execute(
          new HibernateCallback() {
          public Object doInHibernate(Session session) throws
          												
          														 HibernateException {
          List result = session.find(
          "from test.Product product where product.category=?",
          category, Hibernate.STRING);
          // do some further stuff with the result list
          return result;
          }
          }
          );
          }
          }
          												

          ?????? 一個回調的實現可以被有效地用在任何Hibernate數據訪問中。在任何情況下都由HibernateTemplate來管理Session的開閉和自動的多方事務。模板實例是線程安全和可重用的,因此它們可以做為其他類的變量。


          ?????? 對于簡單的單步的動作,象find, load, saveOrUpdate或者delete的調用,HibernateTemplate提供更為便利的選擇以代替象一行的回調的執行。此外,Spring提供了一個方便的基本類,就是HibernateDaoSupport類,它提供了setSessionFactory方法來接受一個SessionFactory,同時提供了getSessionFactory和getHibernateTemplate方法供其繼承類使用。將這些結合起來,允許對于典型的需求給出了非常簡單的DAO實現:

          												
          														
          																public class ProductDaoImpl extends HibernateDaoSupport implements
          														
          																 ProductDao {
          
          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代碼,配合相應的在應用配置中分別的攔截器配置來代替執行回調。下面的片段顯示了一個Spring應用配置中的DAO, interceptor和proxy的各自的定義,同時給出了一個DAO方法實現的例子:

          												
          														
          																
          																		<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 HibernateDaoSupport 
          																
          																		   implements 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為它負責在方法調用前線程綁定Session的開啟和方法調用后的關閉。getSession方法調用中的"false"標志是要確認Session必須是已經存在的,如果沒有發現任何一個Session,SessionFactoryUtils將會為其創建一個。如果已經有一個Session句柄綁定在本線程上,比如是由一個HibernateTransactionManager事務綁定的,在任何情況下SessionFactoryUtils會自動接入這個Session。HibernateTemplate在底層也使用SessionFactoryUtils,與以上說的方式基本是一樣的。

          ?????? HibernateInterceptor的主要益處是它允許在數據訪問代碼中拋出checked application exception,而HibernateTemplate由于受限于回調只能在其中拋出unchecked exceptions。注意到這點我們可以推遲各自的檢驗,同時在回調后拋出應用異常。攔截方式的主要缺點是它需要在配置中進行特殊的配置。HibernateTemplate在大多數情況下都是一種簡單好用的方法。

          5. 程序事務劃分

          ?? 在這種底層的數據訪問服務之上,事務處理可以在更高的應用層被劃分 ,形成一些操作。這里除了需要一個Spring的PlatformTransactionManager對象外,對于周圍運行的業務對象也沒有任何限制。同樣的,其后你可以從任何地方獲得它們,但是經由Bean引用的方式通過setTransactionManage方法獲得更為適合,象productDAO要經由一個setProductDao方法獲得一樣。下面的引用片段顯示了在一個Spring應用配置中的事務管理對象和業務對象的定義,并且還提供了一個業務方法實現的例子:

          												
          														
          																
          																		<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(PlatformTransactionManager 
          																
          																		  transactionManager) {
          this.transactionManager = transactionManager;
          }
          
          public void setProductDao(ProductDao productDao) {
          this.productDao = productDao;
          }
          
          public void increasePriceOfAllProductsInCategory(final String 
          																
          																		  category) {
          TransactionTemplate transactionTemplate =
          new TransactionTemplate(this.transactionManager);
          transactionTemplate.setPropagationBehavior(TransactionDefinition
          																
          																		    .PROPAGATION_REQUIRED);
          transactionTemplate.execute(
          new TransactionCallbackWithoutResult() {
          public void doInTransactionWithoutResult(TransactionStatus 
          																
          																		  status) {
          List productsToChange = productDAO.loadProductsByCategory(category);
          ...
          }
          }
          );
          }
          }
          																

          6. 聲明性事務劃分

          ?????? 我們還可以選擇使用Spring的AOP TransactionInterceptor通過在應用配置中定義攔截器配置來代替事務劃分代碼的事務處理方式。這允許我們保持業務對象獨立于每個業務對象中重復的事務劃分代碼。此外,事務行為和隔離層次的變化可以通過一個配置文件來改變而不需要對業務對象的實現造成影響。

          												
          														<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 String
          												
          														 category) {
          List productsToChange = this.productDAO
          												
          														.loadProductsByCategory(category);
          ...
          }
          }
          												

          ???? ?如同使用HibernateInterceptor一樣,TransactionInterceptor允許任何checked application exception從回調代碼中拋出,而TransactionTemplate受回調限制在其內部拋出unchecked exceptions,在出現一個unchecked application exception的情況時,TransactionTemplate將引發一個回滾或者這個事務由應用(通過事務狀態)標記為回滾。TransactionInterceptor默認情況也是同樣的行為,但是允許為每一個方法制定回滾策略。
          ????? ?建立聲明性事務的一個便利的方式是使用TransactionProxyFactoryBean,特別是如果沒有其他AOP攔截器的話,TransactionProxyFactoryBean將聯合定義為代理的自身與一個特殊的目標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子系統)。甚至你可以使用一個自定義的PlatformTransactionManager實現。
          ????? ?如果選擇從本地Hibernate事務管理轉為由JTA來進行事務管理,例如:當你的應用的部署面對分布的事務需求時,也僅僅是改變一下配置的事。只要簡單地將Hibernate的事務管理換為JTA事務實現即可。所有的事務劃分和數據訪問無需做任何變動仍可以繼續工作,因為他們使用的都是普通的事務管理API。
          ?????? 對于分布式的事務會跨越多個Hibernate的session factories,僅僅是聯合JtaTransactionManager與多個LocalSessionFactoryBean定義作為事務策略。你的每一個DAO將通過它們各自的Bean屬性得到一個特殊的SessionFactory的引用。如果這一切都是在下面的JDBC數據源是事務容器,一個業務對象可以劃分事務跨越很多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允許適當的對Hibernate的在JVM層次的緩存處理-不需要容器-提供特殊的事務查找或者JCA連接器(只要不使用EJB發起事務)。另外,HibernateTransactionManager能輸出JDBC連接供通常的JDBC訪問代碼使用。這樣就允許在高層次上的事務劃分是混合了Hibernate與JDBC而不要JTA的,只要只是訪問一個數據庫就可以!

          8. 使用Spring管理應用的Bean

          ??????? 一個Spring應用配置定義可以被多種配置實現所加載,從FileSystemXmlApplicationContext和ClassPathXmlApplicationContext到XmlWebApplicationContext。這就允許在各種環境下重用Spring管理的數據訪問和業務對象。默認情況下,一個Web應用將有它自己的定義在“WEB-INF/applicationContext.xml”中的根配置。
          ?????? 在任何一個Spring應用中,一個應用配置定義在一個XML格式的文件中用來對應用的所有有關的Bean進行裝配,從Hibernate的session factory到自定義的數據訪問和業務對象(象上面所有的Bean那樣)。他們中的大多數不需要Spring容器知道他們,甚至即使是與其他Bean合作時也一樣,因為他們只是簡單的JavaBean之間的協作。下面的Bean定義可能是一個Spring Web 的MVC配置中用來訪問業務對象的配置的一部分。

          												?
          												
          														
          																<bean id="myProductList" class="product.ProductListController">
          <property name="productService">
          <ref bean="myProductService"/>
          </property>
          </bean>
          														

          ????? Spring的Web控制器經由Bean引用擁有它們需要的所有的業務和數據訪問對象,因此它們無需在應用配置中做任何手工的Bean查找。但是當使用Spring管理的Beans用于Struts或者是在EJB實現,或者一個applet中時常常是需要必須手工查找一個Bean的。因此Spring的Bean可以被用在任何地方。也許只是需要是一應用配置的引用,或者經由一個web容器的Servlet配置屬性,或者從一個文件中或者類路徑的資源中創建它。

          												
          														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沒有任何益處。如果經由Hibernate的JCA連接器注冊,才會有加入JTA事務的明顯益處,特別是對EJB。

          ?????? 一個重要的Spring事務提供的好處是它不與任何容器綁定。定義包括JTA在內的策略,它都可以獨立工作或者在一個試驗環境中工作。特別是對典型的一個數據庫的事務來說,對于JTA這是一個非常輕量的和強大的選擇。當使用本地EJB SLSB的事務時,你將同時依賴EJB容器和JTA-即使你只是訪問一個數據庫,即使只是使用SLSBs經由CMT來聲明事務。選擇使用 JTA編程也需要一個J2EE環境。

          ?????? 就JTA自身和JNDI數據源來說JTA不只是包括容器依賴。對于不使用Spring的JTA驅動的Hibernate事務,你必須使用HibernateJCA連接器或者在合適的JVM緩沖層專門寫Hibernate的事務代碼配置JTA事務。在只訪問一個數據庫的情況下,Spring驅動的事務可以與一個本地定義的Hibernate的SessionFactory配合良好,就如同與一個本地JDBC數據源相配合一樣。因此當面對分布的事務需求時,你只需要轉換為Spring的JTA事務策略即可。

          ????? ?要注意一個JCA連接器需要特別的容器的部署步驟,并且顯然首先得支持JCA。這比使用本地資源定義和Spring驅動事務來部署一個簡單的Web應用有更多的爭議。而且你常常需要企業版本的容器支持,象WebLogic Express就不提供JCA。一個只用一個數據庫的使用本地資源和事務的Spring應用可以在任何J2EE的Web容器中工作,Web容器不必支持JTA, JCA和EJB,如:Tomcat, Resin甚至最小的Jetty。另外,這樣一個中間層就可以很容易地在桌面應用或者在測試套件中被重用。

          ?????? 所有考慮過的事情包括:如果你不使用EJB,堅持使用本地SessionFactory,使用SpringHibernateTransactionManager或者JtaTransactionManager,你將獲得包括適當處理的JVM層的緩存和分布事務的所有益處,而無需引起任何關于容器部署的爭論。經由JCA連接器的一個Hibernate的SessionFactory的JNDI注冊只是在使用EJB的情況中才會有明顯的附加值。


          10. Skeletons和例子

          ????? 配置使用Spring和HIbernate的一個J2EE的Web應用的注釋和細節最好去看看在Spring Framework的例子中的“典型的Web應用”Skeletons,它給出了適合于JDBC 和 Hibernate應用的多種數據源及事務管理的配置項,仔細看一下事務攔截器的配置,它也同樣向你展示了如何配置AOP攔截器。

          ????? 在Spring的1.0 M2版中,例子Petclinic提供了JDBC和Hibernate的DAO實現和應用配置的選擇。Petclinic
          可以作為一個可工作的簡單應用說明如何在一個Spring web 應用中使用Hibernate,同樣也包括根據不同的事務策略來聲明事務劃分。

          Links

          Spring Framework website

          Spring Framework documentation

          posted on 2006-06-21 17:17 靜夜思 閱讀(282) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 寿宁县| 连城县| 通海县| 德清县| 潮州市| 石台县| 东安县| 北宁市| 临海市| 桐柏县| 克东县| 许昌市| 洛隆县| 黄平县| 隆安县| 周口市| 宿迁市| 阿鲁科尔沁旗| 菏泽市| 柘城县| 宝坻区| 措美县| 通河县| 施秉县| 东丰县| 灵寿县| 中方县| 会宁县| 江油市| 西丰县| 自治县| 宁晋县| 宣汉县| 类乌齐县| 宣恩县| 桓仁| 锡林浩特市| 恩施市| 南召县| 邵阳县| 泸定县|