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

JAVA設計模式之事務處理[1]

2013-11-23 19:58:44  來源: Java高級技術 
    事務處理是企業應用需要解決的最主要的問題之一JEE通過JTA提供了完整的事務管理能力包括多個事務性資源的管理能力但是大部分應用都是運行在單一的事務性資源之上(一個數據庫)他們並不需要全局性的事務服務本地事務服務已然足夠(比如JDBC事務管理)
    本文並不討論應該采用何種事務處理方式主要目的是討論如何更為優雅地設計事務服務僅以JDBC事務處理為例涉及到的DAOFactoryProxyDecorator等模式概念請閱讀相關資料
    也許你聽說過事務處理應該做在service層也許你也正這樣做但是否知道為什麼這樣做?為什麼不放在DAO層做事務處理顯而易見的原因是業務層接口的每一個方法有時候都是一個業務用例(User Case)它需要調用不同的DAO對象來完成一個業務方法比如簡單地以網上書店購書最後的確定定單為例業務方法首先是調用BookDAO對象(一般是通過DAO工廠產生)BookDAO判斷是否還有庫存余量取得該書的價格信息等然後調用CustomerDAO從帳戶扣除相應的費用以及記錄信息然後是其他服務(通知管理員等)簡化業務流程大概如此:
    注意我們的例子忽略了連接的處理只要保證同一個線程內取的是相同的連接即可(可用ThreadLocal實現)

    首先是業務接口針對接口而不是針對類編程


public interface BookStoreManager{
          public boolean buyBook(String bookIdint quantity)throws SystemException;
          其他業務方法
    }

    接下來就是業務接口的實現類??業務對象


public class BookStoreManagerImpl implements BookStoreManager{
         public boolean buyBook(String bookId)throws SystemException{
              Connection conn=ConnectionManagergetConnection();//獲取數據庫連接
              boolean b=false;
             
              try{
                  connsetAutoCommit(false);  //取消自動提交
                  BookDAO bookDAO=DAOFactorygetBookDAO();
                  CustomerDAO customerDAO=DAOFactorygetCustomerDAO();
                    //嘗試從庫存中取書
                  if(BookDAOreduceInventory(connbookIdquantity)){
                       BigDecimal price=BookDAOgetPrice(bookId);  //取價格
                       //從客戶帳戶中扣除price*quantity的費用
                       b=
                       CustomerDAOreduceAccount(connpricemultiply(new BigDecimal(quantity));
                      
                       其他業務方法如通知管理員生成定單等
                       
                       conncommit();   //提交事務
                       connsetAutoCommit(true);
                  }
               }catch(SQLException e){
                  connrollback();   //出現異常回滾事務
                  consetAutoCommit(true);
                  eprintStackTrace();
                  throws new SystemException(e);  
               }
               return b;
         }
    }


    然後是業務代表工廠 


  public final class ManagerFactory {
      public static BookStoreManager getBookStoreManager() {
         return new BookStoreManagerImpl();
      }
   }

    這樣的設計非常適合於DAO中的簡單活動我們項目中的一個小系統也是采用這樣的設計方案但是它不適合於更大規模的應用首先你有沒有聞到代碼重復的 bad smell?每次都要設置AutoCommit為false然後提交出現異常回滾包裝異常拋到上層寫多了不煩才怪那能不能消除呢?其次業務代表對象現在知道它內部事務管理的所有的細節這與我們設計業務代表對象的初衷不符對於業務代表對象來說了解一個與事務有關的業務約束是相當恰當的但是讓它負責來實現它們就不太恰當了再次你是否想過嵌套業務對象的場景?業務代表對象之間的互相調用層層嵌套此時你又如何處理呢?你要知道按我們現在的方式每個業務方法都處於各自獨立的事務上下文當中(Transaction Context)互相調用形成了嵌套事務此時你又該如何處理?也許辦法就是重新寫一遍把不同的業務方法集中成一個巨無霸包裝在一個事務上下文中

    我們有更為優雅的設計來解決這類問題如果我們把Transaction Context的控制交給一個被業務代表對象DAO和其他Component所共知的外部對象當業務代表對象的某個方法需要事務管理時它提示此外部對象它希望開始一個事務外部對象獲取一個連接並且開始數據庫事務也就是將事務控制從service層抽離當web層調用service層的某個業務代表對象時返回的是一個經過Transaction Context外部對象包裝(或者說代理)的業務對象此代理對象將請求發送給原始業務代表對象但是對其中的業務方法進行事務控制那麼我們如何實現此效果呢?答案是JDK引進的動態代理技術動態代理技術只能代理接口這也是為什麼我們需要業務接口BookStoreManager的原因
    首先我們引入這個Transaction Context外部對象它的代碼其實很簡單如果不了解動態代理技術的請先閱讀其他資料


[]  []  


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27765.html
  • 上一篇文章:

  • 下一篇文章:
  • Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.