熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java開源技術 >> 正文

Spring的事務

2013-11-23 20:14:00  來源: Java開源技術 

  今天對 spring 的 AOP 事務有了一個新的認識所以趕緊把今天的學習記下來希望在今後的學習中能夠起到一些作用也能對今天的認識做一次總結

  spring 分享

  先看一段代碼

  Connection conn = ConngetConnection();

  connsetAutoCommit(false);

  ……

  ……

  connrollback();

  mit();

  數據庫的事務是針對 Connection 的

  接著再看一段代碼( spring 中事務的一段學習代碼這段代碼是把 spring 和 hibernate 結合在一起的增加了理解上的難度因為我的出發點一開始不要 hibernate 就光用 jdbc 來進行數據庫事務但是沒有其他好的代碼就這樣吧)

  public Long addLineItem(Long orderId LineItem lineItem){

  log(OrderListDAOHibernateaddLineItem : Start);

  OrderList orderList = (OrderList) getHibernateTemplate()load(OrderListclass orderId);

  lineItemsetOrderList(orderList);

  getHibernateTemplate()saveOrUpdate(lineItem);

  getHibernateTemplate()saveOrUpdate(orderList);

  log(OrderListDAOHibernateaddLineItem : Ending);

  return lineItemgetId();

  }

  在這個代碼的配置文件中把 addLineItem 做為一個切入點進行事務也就是說在 addLineItem 的外面再包上一層事務的外殼

  但是這個時候問題出來了事務是針對 Connection 的而上面的兩個連續的 HibernateTemplate 執行的 saveOrUpdate 中的 Connection 必須是一致才能用事務 spring 怎麼做到這一點的呢?(這個問題也就是在找 spring 的事務例子前我想的 spring 中用 jdbc 來進行事務怎麼樣讓 Connection 保持一致呢?但是沒有 jdbc 的例子只有整合 hibernate 或者 ibatis 的例子但是我想原理是一樣的吧

  解決問題的思路 HibernateTemplate 中的 Connection 必定一致那麼就從 HibernateTemplate 入手

  看 spring 的源代碼既然是 Hibernate 那麼就沒有 Connection 給你看只有 Session 由 Session 來管理 Connection 那麼用事務來控制的話這個 Session 必定在所有該事務中是一致的於是在 HibernateTemplate 中找到

  protected Session getSession() {

  if (isAlwaysUseNewSession()) {

  return SessionFactoryUtilsgetNewSession(getSessionFactory() getEntityInterceptor());

  }

  else if (!isAllowCreate()) {

  return SessionFactoryUtilsgetSession(getSessionFactory() false);

  }

  else {

  return SessionFactoryUtilsgetSession(

  getSessionFactory() getEntityInterceptor() getJdbcExceptionTranslator());

  }

  }

  看來在 SessionFactoryUtils 裡面接著在 SessionFactoryUtilsgetSession 中找

  這個方法太長了太復雜了從簡發現了非常關鍵的一點

  SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManagergetResource(sessionFactory);

  假如 sessionHolder 不等於空說明在事務中有這樣一個還沒有 commit 的 session 那麼就返回這個 session 假如等於空新建一個 session 並且在事務裡加入這個 session 這段代碼的意思大概是這樣太繁雜了只能猜也肯定是如此

  再看 getHibernateTemplate() 方法來自繼承 HibernateDaoSupport 看了電子書《 springreference 》的第九章 Dao 支持 Dao 的支持類可以有好多 JdbcDaoSupport HibernateDaoSupport JdoDaoSupport 等等

  既然前面一開始就是從 jdbc 的 spring 事務控制引起的那麼看到了同樣的 HibernateDaoSupportJdbcDaoSupport 那麼 JdbcDaoSupport 也應該有 getJdbcTemplate() 這個方法並且返回 JdbcTemplate 這個類

  果然如此

  於是剖析 JdbcTemplate 是不是和 HibernateTemplate 一樣果然一樣

  注意到

  Connection con = DataSourceUtilsgetConnection(getDataSource());

  Connection 是從 DataSourceUtilsgetConnection() 來的繼續跟蹤 DataSourceUtilsgetConnection()

  找到

  ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManagergetResource(dataSource);

  和 Hibernate 中的一模一樣因為沒有了 session 的封裝條理在 jdbc 中更加清晰了

  至此 spring 的事務控制 已經全部搞定

  Spring 事務管理的配置

  看了上面同事學習 spring 的筆記後自己也覺得有新的理解從什麼地方說起呢?就從 spring 的事務配置說起吧那麼我們看看 contextConfigxml 吧

  <bean id=sessionFactory class=orgspringframeworkormhibernateLocalSessionFactoryBean>

  <property name=dataSource>

  <ref bean=dataSource />

  </property>

  <property name=mappingResources>

  <list>

  <value>mf/org/user/Userhbmxml</value>

  </list>

  </property>

  </bean>

  <bean id=transactionManager class=orgspringframeworkormhibernateHibernateTransactionManager>

  <property name=sessionFactory>

  <ref local=sessionFactory />

  </property>

  </bean>

  <bean id=txProxyTemplate abstract=true class=orgspringframeworktransactioninterceptorTransactionProxyFactoryBean>

  <property name=transactionManager>

  <ref bean=transactionManager />

  </property>

  <property name=transactionAttributes>

  <props>

  <prop key=save*>PROPAGATION_REQUIREDException</prop>

  <prop key=remove*>PROPAGATION_REQUIREDException </prop>

  <prop key=update*>PROPAGATION_REQUIREDException </prop>

  <prop key=incress*>PROPAGATION_REQUIREDException </prop>

  <prop key=*>PROPAGATION_REQUIREDreadOnly</prop>

  </props>

  </property>

  </bean>

  <bean id=userManager parent=txProxyTemplate>

  <property name=target ref=userManagerTarget />

  </bean>

  <bean id=userManagerTarget

  class= hbuserserviceimplUserManagerImpl>

  <property name=userDAO ref=userDAO />

  </bean>

  <bean id=userDAO class=hbuserdaohibernateUserDAOHibernate>

  <property name=sessionFactory ref=sessionFactory />

  </bean>

  以上就是一個完整的 spring 配置是不是很熟悉呢這裡是用的 Appfuse 的框架呵呵有那麼點味道吧

  首先我們看看

  <bean id=transactionManager class=orgspringframeworkormhibernateHibernateTransactionManager>

  <property name=sessionFactory>

  <ref local=sessionFactory />

  </property>

  </bean>

  這一個 bean 讓 spring 為我們注入了什麼呢?事務對!我們把 hibernate 的事務注入到了 spring 的 IOC 容器之中了然後我們再看看

  <bean id=txProxyTemplate abstract=true class=orgspringframeworktransactioninterceptorTransactionProxyFactoryBean>

  <property name=transactionManager>

  <ref bean=transactionManager />

  </property>

  <property name=transactionAttributes>

  <props>

  <prop key=save*>PROPAGATION_REQUIREDException</prop>

  <prop key=remove*>PROPAGATION_REQUIREDException </prop>

  <prop key=update*>PROPAGATION_REQUIREDException </prop>

  <prop key=incress*>PROPAGATION_REQUIREDException </prop>

  <prop key=*>PROPAGATION_REQUIREDreadOnly</prop>

  </props>

  </property>

  </bean>

  這個 bean 又是讓 spring 為我們注入了了什麼呢?事務代理對了!我們把事務的代理交給一個 txProxyTemplate 的去做了這樣的好處我待會再說現在我們看看下面的一些配置信息

  <prop key=save*>PROPAGATION_REQUIREDException</prop>

  <prop key=remove*>PROPAGATION_REQUIREDException </prop>

  <prop key=update*>PROPAGATION_REQUIREDException </prop>

  <prop key=incress*>PROPAGATION_REQUIREDException </prop>

  <prop key=*>PROPAGATION_REQUIREDreadOnly</prop>

  這裡就是事務處理時如果遇到異常信息或者其他的原因時我們要求 spring 把當前的事務回滾了這樣才能不至於在數據庫中產生垃圾啊我們規定所有的 saveremoveupdateincress 這樣的方法開頭的在出現一些問題後把事務給回滾了看看我們寫的 PROPAGATION_REQUIREDException

  有人就會說 PROPAGATION_REQUIRED 就可以回滾事務啊為什麼加上 Exception 呢?其實我以前也時這樣想的但這是不完全正確的當然我們在處理一個事務時只要有一個 PROPAGATION_REQUIRED 就可以了但是當我們的業務邏輯中要求我們在一個事務代理中開啟兩個事務這兩個事務表面上沒有聯系但是實際中又有很多聯系的比如我們上傳附件和提交文檔這樣兩個操作我們可以分開因為他們不是往一個表裡插入數據我們又不希望這兩個操作寫在一個 service 裡這樣我們要是有一個業務只要上傳附件呢?那樣我們是不是又要再寫一個方法啊!所以在開啟兩個事務時如果有一個拋出異常了我們就要把上一個提交的事務回滾了這樣做我們就要用的 Exception 了這樣就完全滿足我們的要求了我也試過如果我寫的是 PROPAGATION_REQUIREDSQLException 時這樣我們只會在出現 SQLException 時事務回顧出現其他的異常事務就不回滾了好在 spring 可以讓我們寫如異常的基類就可以做到捕獲任何異常這樣我們就寫 Exception 好了特殊情況在特殊處理吧通用情況下我們還是這樣的

  我們再看看

  <bean id=userManager parent=txProxyTemplate>

  <property name=target ref=userManagerTarget />

  </bean>

  <bean id=userManagerTarget

  class=hbuserserviceimplUserManagerImpl>

  <property name=userDAO ref=userDAO />

  </bean>

  <bean id=userDAO class=hbuserdaohibernateUserDAOHibernate>

  <property name=sessionFactory ref=sessionFactory />

  </bean>

  當然我們也可以寫成

  <bean id=userManager parent=txProxyTemplate>

  <property name=target>

  <bean class=hbuserserviceimplUserManagerImpl>

  <property name=userDAO>

  <ref bean=userDao/>

  </property>

  </bean>

  </property>

  </bean>

  <bean id=userDAO class=hbuserdaohibernateUserDAOHibernate>

  <property name=sessionFactory ref=sessionFactory />

  </bean>

  這下我們解除以前的疑惑 parent=txProxyTemplate 知道我們為什麼在上面先寫了 txProxyTemplate 的 bean 了吧這樣我們就沒有必要再寫一編了是不是很方便? spring 的這些技巧還不只這些呢這樣我們就可以輕松利用以上這三個注入的類去做我們的邏輯了

  Spring 就是要我們注入實現類然後使用接口操作這樣耦合性就不是那麼強了這也體現了 Spring 的工廠模式而 AOP 的 manager 又象我們熟知的代理模式吧 !

  注意要點

  在寫配置的時候注意各個 Manager 和 DAO 之間的關系以及 <ref= > 之間的關系清晰裡面的關系才能更好的配置


From:http://tw.wingwit.com/Article/program/Java/ky/201311/28161.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.