<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    gembin

    OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

    HBase, Hadoop, ZooKeeper, Cassandra

    Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

    There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

    About Me

     

    設計模式之事務處理

    設計模式之事務處理
     

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

        首先是業務接口,針對接口,而不是針對類編程:
    public interface BookStoreManager{
              public boolean buyBook(String bookId,int quantity)throws SystemException;
              .其他業務方法
    }

        接下來就是業務接口的實現類——業務對象:
       public class BookStoreManagerImpl implements BookStoreManager{
             public boolean buyBook(String bookId)throws SystemException{
                  Connection conn=ConnectionManager.getConnection();//獲取數據庫連接
                  boolean b=false;
                  
                  try{
                      conn.setAutoCommit(false);  //取消自動提交
                      BookDAO bookDAO=DAOFactory.getBookDAO();
                      CustomerDAO customerDAO=DAOFactory.getCustomerDAO();
                        //嘗試從庫存中取書 
                      if(BookDAO.reduceInventory(conn,bookId,quantity)){
                           BigDecimal price=BookDAO.getPrice(bookId);  //取價格
                           //從客戶帳戶中扣除price*quantity的費用
                           b=
                           CustomerDAO.reduceAccount(conn,price.multiply(new BigDecimal(quantity));
                           .
                           其他業務方法,如通知管理員,生成定單等.
                            
                           conn.commit();   //提交事務
                           conn.setAutoCommit(true);
                      }
                   }catch(SQLException e){
                      conn.rollback();   //出現異常,回滾事務
                      con.setAutoCommit(true);
                      e.printStackTrace();
                      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外部對象包裝(或者說代理)的業務對象。此代理對象將請求發送給原始業務代表對象,但是對其中的業務方法進行事務控制。那么,我們如何實現此效果呢?答案是JDK1.3引進的動態代理技術。動態代理技術只能代理接口,這也是為什么我們需要業務接口BookStoreManager的原因。
        首先,我們引入這個Transaction Context外部對象,通過ThreadLocal來保證Connection在統一線程內是唯一的,它的代碼其實很簡單,如果不了解動態代理技術的請先閱讀其他資料。
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    import java.sql.Connection;

    import com.strutslet.demo.service.SystemException;

    public final class TransactionWrapper {

        /** *//**
         * 裝飾原始的業務代表對象,返回一個與業務代表對象有相同接口的代理對象 
         */
        public static Object decorate(Object delegate) {
            return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
                    delegate.getClass().getInterfaces(), new XAWrapperHandler(
                            delegate));
        }
        
        //動態代理技術
        static final class XAWrapperHandler implements InvocationHandler {
            private final Object delegate;

            XAWrapperHandler(Object delegate) {
               this.delegate = delegate;
            }
            
            //簡單起見,包裝業務代表對象所有的業務方法
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                Object result = null;
                Connection con = ConnectionManager.getConnection();
                try { 
                    //開始一個事務
                    con.setAutoCommit(false);
                    //調用原始業務對象的業務方法
                    result = method.invoke(delegate, args);
                    con.commit();   //提交事務
                    con.setAutoCommit(true);
                } catch (Throwable t) {
                    //回滾
                    con.rollback();
                    con.setAutoCommit(true);
                    throw new SystemException(t);
                }

                return result;
            }
        }
    }

        正如我們所見,此對象只不過把業務對象需要事務控制的業務方法中的事務控制部分抽取出來而已。請注意,業務代表對象內部調用自身的方法將不會開始新的事務,因為這些調用不會傳給代理對象。如此,我們去除了代表重復的味道。此時,我們的業務代表對象修改成:
    public class BookStoreManagerImpl implements BookStoreManager {
        public boolean buyBook(String bookId)throws SystemException{
              Connection conn=ConnectionManager.getConnection();// 獲取數據庫連接
              boolean b=false;
              try{
                  BookDAO bookDAO=DAOFactory.getBookDAO();
                  CustomerDAO customerDAO=DAOFactory.getCustomerDAO();
                  // 嘗試從庫存中取書
                  if(BookDAO.reduceInventory(conn,bookId,quantity)){
                      BigDecimal price=BookDAO.getPrice(bookId);  // 取價格
                      // 從客戶帳戶中扣除price*quantity的費用
                      b=
                      CustomerDAO.reduceAccount(conn,price.multiply(new BigDecimal(quantity));
                      .
                      其他業務方法,如通知管理員,生成定單等.
                      
                  }
              }catch(SQLException e){
                 throws new SystemException(e);
              }
              return b;
        }
        . 
    }

        可以看到,此時的業務代表對象專注于實現業務邏輯,它不再關心事務控制細節,把它們全部委托給了外部對象。業務代表工廠也修改一下,讓它返回兩種類型的業務代表對象:
        public final class ManagerFactory {
          //返回一個被包裝的對象,有事務控制能力
          public static BookStoreManager getBookStoreManagerTrans() {
              return (BookStoreManager) TransactionWrapper
                      .decorate(new BookStoreManagerImpl());
          }
          //原始版本
          public static BookStoreManager getBookStoreManager() {
             return new BookStoreManagerImpl();
          }
          
       }
       
       我們在業務代表工廠上提供了兩種不同的對象生成方法:一個用于創建被包裝的對象,它會為每次方法調用創建一個新的事務;另外一個用于創建未被包裝的版本,它用于加入到已有的事務(比如其他業務代表對象的業務方法),解決了嵌套業務代表對象的問題。 
       我們的設計還不夠優雅,比如我們默認所有的業務代表對象的方法調用都將被包裝在一個Transaction Context。可事實是很多方法也許并不需要與數據庫打交道,如果我們能配置哪些方法需要事務聲明,哪些不需要事務管理就更完美了。解決辦法也很簡單,一個XML配置文件來配置這些,調用時判斷即可。說到這里,了解spring的大概都會意識到這不正是聲明式事務控制嗎?正是如此,事務控制就是AOP的一種服務,spring的聲明式事務管理是通過AOP實現的。AOP的實現方式包括:動態代理技術,字節碼生成技術(如CGLIB庫),java代碼生成(早期EJB采用),修改類裝載器以及源代碼級別的代碼混合織入(aspectj)等。我們這里就是利用了動態代理技術,只能對接口代理;對類的動態代理可以使用cglib庫。

    posted on 2007-09-21 10:57 gembin 閱讀(765) 評論(1)  編輯  收藏

    評論

    # re: 設計模式之事務處理 2007-09-22 00:15 千里冰封

    EJB3現在事務處理也不錯啊  回復  更多評論   


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


    網站導航:
     

    導航

    統計

    常用鏈接

    留言簿(6)

    隨筆分類(440)

    隨筆檔案(378)

    文章檔案(6)

    新聞檔案(1)

    相冊

    收藏夾(9)

    Adobe

    Android

    AS3

    Blog-Links

    Build

    Design Pattern

    Eclipse

    Favorite Links

    Flickr

    Game Dev

    HBase

    Identity Management

    IT resources

    JEE

    Language

    OpenID

    OSGi

    SOA

    Version Control

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    free counters
    主站蜘蛛池模板: 国产亚洲sss在线播放| 免费看又黄又爽又猛的视频软件 | a在线观看免费网址大全| 国产亚洲精品无码成人| 亚欧日韩毛片在线看免费网站| 亚洲国产精品人久久电影| 成年女人毛片免费观看97| 亚洲精品av无码喷奶水糖心| 国产免费AV片无码永久免费| 久久国产乱子伦精品免费强| 亚洲最新在线视频| 国产最新凸凹视频免费| 两个人看的www免费视频中文| 亚洲精品美女在线观看播放| 国产三级免费电影| 大地资源在线资源免费观看| 亚洲AV无码成人专区| 亚洲Av无码国产情品久久| 亚洲精品在线免费观看视频| 一级看片免费视频| 亚洲中文字幕无码中文字| 亚洲第一福利网站| 亚洲va中文字幕无码| 免费做爰猛烈吃奶摸视频在线观看| 手机看片国产免费永久| 日韩色视频一区二区三区亚洲| 亚洲白嫩在线观看| 亚洲日韩精品一区二区三区| 国产麻豆剧传媒精品国产免费 | 国产男女性潮高清免费网站| 亚洲电影免费观看| 久久精品免费观看| 久久国产福利免费| 日本视频免费观看| 亚洲a∨国产av综合av下载| 亚洲国产日韩在线人成下载| 亚洲AV无码第一区二区三区| 亚洲男人的天堂在线va拉文 | 亚洲首页国产精品丝袜| 亚洲国产精品lv| 亚洲午夜久久久久久久久久|