posts - 193,  comments - 520,  trackbacks - 0
          問(wèn)題背景:我們是一家工作流公司,客戶(hù)采購(gòu)我們的產(chǎn)品后,將其嵌入其項(xiàng)目中。我們的工作流采用的是   spring+hibernate的方式,客戶(hù)項(xiàng)目則是jdbc直接進(jìn)行數(shù)據(jù)庫(kù)操作。
          問(wèn)題:客戶(hù)在其數(shù)據(jù)庫(kù)操作過(guò)程中需要調(diào)用我們的工作流接口,這樣就需要將我們的工作流操作與他們的業(yè)  務(wù)操作置于同一個(gè)事務(wù)中。我們的服務(wù)采用的都是spring的聲明式事務(wù),而客戶(hù)采用的是對(duì)         connection進(jìn)行事務(wù)處理。如何保證事務(wù)的一致性?
          想到的解決方案一:使用jta事務(wù),用tomcat+jotm提供事務(wù)管理器。為什么一開(kāi)始就想到要使用jta事務(wù)??實(shí)際上我們和客戶(hù)都是使用的同一個(gè)數(shù)據(jù)庫(kù),為了方便,各自使用了不同的數(shù)據(jù)庫(kù)連接方式,使用jta的話(huà)確實(shí)有bt的意思在里面。但是事實(shí)上是我們的第一反應(yīng)都是jta。最后沒(méi)有采用該方法的原因也很簡(jiǎn)單:我沒(méi)有將jotm配置成功!汗一個(gè)。
          想到的解決方案二:將客戶(hù)的這些特定代碼用spring管理起來(lái)。因?yàn)橐薷目蛻?hù)部分代碼,這個(gè)方案遭到了客戶(hù)的強(qiáng)烈反對(duì)。于是放棄。
          想到的解決方案三:客戶(hù)數(shù)據(jù)庫(kù)操作與我們的服務(wù)使用同一個(gè)數(shù)據(jù)庫(kù)連接。然后編程處理事務(wù)。存在兩種方式:一種是把客戶(hù)的連接傳給我們,另一種則是把我們的連接傳給客戶(hù)。第一種方式對(duì)我們的影響太大,所以最后決定采用后一種方式:從hibernate session中獲取connection然后傳遞給客戶(hù)。接下來(lái)查看一下HibernateTemplate的execute()方法,思路就很簡(jiǎn)單了:獲取定義的sessionFactory-->創(chuàng)建一個(gè)新的session并打開(kāi)-->將session與當(dāng)前線(xiàn)程綁定-->給客戶(hù)代碼返回connection-->打開(kāi)事務(wù)-->客戶(hù)使用我們傳遞的connection進(jìn)行數(shù)據(jù)庫(kù)操作-->我們不帶聲明事務(wù)的服務(wù)操作-->提交事務(wù)-->解除綁定。
          實(shí)際要注意的地方是:1、將session與當(dāng)前線(xiàn)程綁定使用的TransactionSynchronizationManager.bindResource()方法,這樣在HibernateTemplate里才能找到session;
                              2、我們的服務(wù)一定要把聲明式事務(wù)徹底干掉,否則會(huì)有commit;
                              3、我們服務(wù)調(diào)用完畢后一定要flush session,否則客戶(hù)代碼不會(huì)感知數(shù)據(jù)庫(kù)里的數(shù)據(jù)變化。
          最終解決:使用了spring里常用的模板和回調(diào)。代碼如下:
          public class TransactionTemplate {

              
          protected final Log logger = LogFactory.getLog(TransactionTemplate.class);

              
          private FlushMode flushMode = FlushMode.ALWAYS;

              
          public Object execute(TransactionCallback callback) {
                  
          //首先獲取sessionFactory
                  SessionFactory sessionFactory = (SessionFactory) Framework.getEngine()
                          .getContainer().getComponent(
          "sessionFactory");
                  
          //創(chuàng)建一個(gè)新的session并打開(kāi)
                  logger.debug("Opening single Hibernate Session in TransactionTemplate");
                  Session session 
          = getSession(sessionFactory);
                  
          //將session與當(dāng)前線(xiàn)程綁定
                  TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
                  
          //獲取數(shù)據(jù)庫(kù)連接
                  Connection conn = session.connection();
                  Object result 
          = null;
                  Transaction transaction 
          = null;
                  
          try {
                      
          //開(kāi)始處理事務(wù)
                      transaction = session.beginTransaction();
                      
          try {
                          result 
          = callback.doInTransaction(conn);
                      }
                      
          catch (RuntimeException ex) {
                          doRollback(session, transaction);
                          
          throw ex;
                      }
                      
          catch (Error err) {
                          doRollback(session, transaction);
                          
          throw err;
                      }
                      
          //如果數(shù)據(jù)庫(kù)操作過(guò)程中沒(méi)有發(fā)生異常則提交事務(wù)
                      transaction.commit();
                  } 
          catch (WorkflowException e) {
                      logger.error(
          "數(shù)據(jù)庫(kù)操作失敗,事務(wù)回滾也失敗!");
                      
          throw e;
                  } 
          catch (RuntimeException ex) {
                      logger.error(
          "數(shù)據(jù)庫(kù)操作失敗,事務(wù)被回滾!");
                      
          throw ex;
                  } 
          catch (Error err) {
                      logger.error(
          "數(shù)據(jù)庫(kù)操作失敗,事務(wù)被回滾!");
                      
          throw err;
                  } 
          finally {
                      
          // 將session與當(dāng)前線(xiàn)程解除綁定
                      TransactionSynchronizationManager.unbindResource(sessionFactory);
                      doClose(session);
                  }
                  
          return result;
              }

              
          protected Session getSession(SessionFactory sessionFactory) {
                  Session session 
          = SessionFactoryUtils.getSession(sessionFactory, true);
                  FlushMode flushMode 
          = getFlushMode();
                  
          if (flushMode != null) {
                      session.setFlushMode(flushMode);
                  }
                  
          return session;
              }

              
          private void doRollback(Session session, Transaction transaction) {
                  logger.debug(
          "數(shù)據(jù)庫(kù)操作異常,開(kāi)始回滾事務(wù)");
                  
          try {
                      transaction.rollback();
                      logger.debug(
          "回滾事務(wù)成功!");
                  }
                  
          catch (Exception e) {
                      logger.error(
          "回滾事務(wù)失敗!");
                      
          throw new WorkflowException("回滾事務(wù)失敗!");
                  } 
          finally {
                      session.clear();
                  }
              }

              
          private void doClose(Session session) {
                  logger.debug(
          "開(kāi)始關(guān)閉連接");
                  
          try {
                      session.close();
                  }
                  
          catch (Exception e) {
                      logger.error(
          "關(guān)閉連接失敗!");
                      
          throw new WorkflowException("關(guān)閉連接失敗!");
                  }
              }

              
          public FlushMode getFlushMode() {
                  
          return flushMode;
              }

              
          public void setFlushMode(FlushMode flushMode) {
                  
          this.flushMode = flushMode;
              }
          }

          public interface TransactionCallback {

              Object doInTransaction(Connection conn);
          }
          調(diào)用偽代碼:
              public void methodA(){
                  TransactionTemplate transactionTemplate
          =new TransactionTemplate();
                  transactionTemplate.execute(
          new TransactionCallback(){
                      
          public Object doInTransaction(Connection conn) {
                          
          //客戶(hù)代碼
                          client.method1("1");
                          
          //我們代碼 直接使用
                          our.method2();
                          
          //客戶(hù)代碼
                          client.method3("l");
                          
          return null;  
                      }
                  });
              }




          http://www.aygfsteel.com/ronghao 榮浩原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處:)
          posted on 2007-10-09 15:11 ronghao 閱讀(7749) 評(píng)論(5)  編輯  收藏 所屬分類(lèi): 工作日志

          FeedBack:
          # re: 結(jié)合spring+hibernate與jdbc的事務(wù)
          2007-10-09 18:40 | BeanSoft
          感謝分享!  回復(fù)  更多評(píng)論
            
          # re: 結(jié)合spring+hibernate與jdbc的事務(wù)
          2007-10-09 18:57 | 快樂(lè)的豬豬
          不錯(cuò)  回復(fù)  更多評(píng)論
            
          # re: 結(jié)合spring+hibernate與jdbc的事務(wù)
          2007-10-11 08:07 | ce
          不錯(cuò)。。。  回復(fù)  更多評(píng)論
            
          # re: 結(jié)合spring+hibernate與jdbc的事務(wù)[未登錄](méi)
          2007-10-12 07:49 | leo
          看的有點(diǎn)不懂。。。  回復(fù)  更多評(píng)論
            
          # re: 結(jié)合spring+hibernate與jdbc的事務(wù)
          2008-08-01 14:10 | asd
          不錯(cuò)。  回復(fù)  更多評(píng)論
            
          <2007年10月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          關(guān)注工作流和企業(yè)業(yè)務(wù)流程改進(jìn)。現(xiàn)就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          常去的網(wǎng)站

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 东乡县| 邵阳县| 桐城市| 南阳市| 土默特左旗| 柳州市| 扎兰屯市| 平武县| 徐水县| 桦甸市| 晋江市| 长垣县| 连州市| 诸城市| 桐柏县| 安图县| 铜鼓县| 霸州市| 左贡县| 井冈山市| 溧阳市| 墨竹工卡县| 临夏市| 德格县| 马鞍山市| 南和县| 耒阳市| 同仁县| 济阳县| 合水县| 淮安市| 丰都县| 肃宁县| 泸州市| 夏河县| 石嘴山市| 松原市| 阳信县| 郴州市| 六盘水市| 达日县|