天天看點

面向應用的持久層

1.1

持久化:通過持久化過程,将記憶體中的資料儲存到資料庫(或)其他媒介)以備日後隻用,是為持久化。

持久層:專注于資料持久化的一個相對獨立的領域。

所謂持久層,我們不妨從回答下面幾個問題來嘗試了解:

1.如果表示層發生變化,需要從JSP遷移到Java WebStartClient,我們的資料持久層代碼是否需要重新編譯。

2.如果業務邏輯層發生變化,那麼資料化持久話代碼是否需要重新編譯。

3.如果底層資料持久化機制發生了改變,比如更換資料庫,那麼,系統的非持久化部分代碼,包括表示層,業務邏輯層是否重新編譯。

1.2

耦合:事物之間的互相關系。

解耦合:采用一些手段降低關聯的緊密程度。

解耦合設計:應用層解耦合—應用邏輯和資料邏輯分離;資源層解耦合—邏輯結構和實體結構的相分離。

解耦思想的自然演進和持久層的解耦合:以網上商店購物結算的處理過程為例。

<此處讀者以人類曆史的發展過程來整理作者的演繹過程,并對其示例代碼略作整合,并忽略了異常處理>

原始社會—原始個體獨立生産自己所需:

業務邏輯和資料通路代碼混雜,一個過程負責完成所有工作。

public BigDecimal calcAmount(String customerID, BigDecimal amount) throws Exception {

      connection conn = null;

      Statement statement = null;

       class.forName("Oracle.jdbc.driver.OracleDriver");

       conn = DriverManager.getConnection(

                                                 "JDBC:oracle:thin:@dbserver:1521:forum",

                                                   "MyUserName", "MyPasswor");

       PreparedStatement stmt_customer = conn.prepareStatement("select level from customer where id = ?");

       stmt_customer.setString(1, customerID);

       ResultSet rset_customer = stmt_customer.executeQuery();

       if(rset_customer.next())

       {

             int customerLevel = rset_customer.getInt(1);

             PreparedStatement stmt_promotion = conn.prepareStatement(

                                              "select ration from promotion where cust_level = ?");

             stmt_promotion.setInt(1, customerLevel);

             ResultSet rset_promotion = stmt_promotion.executeQuery();

             Double ratio = 1;

             if(rset_promotion.next())

             { 

                 ratio = rset_promotion.getDouble(1);

              }

              amount = amount.multi(new BigDecimal(ratio));

              PreparedStatement stmt_updateCustomer = conn.prepareStatement(

                           "update custiomer set sum_amount = sum_amount + ? where id = ?");

              stmt_updateCustomer.setDouble(1, amount.doubleValue());

              stmt_updateCustomer.setString(2, customerID);

              stmt_updateCustomer.executeUpdate();

              stmt_updateCustomer.close();

              rset_promotion.close():

              stmt_promotion.close():

      }

       rset_customer.close();

       stmt_customer.cloase();

       return amount;

  }

奴隸社會—個體專注自己的生産,并用産出與他人交換,簡單的獨立和合作:

将一些變化的,和影響性能的操作進行簡單的封裝,比如将使用者資訊通過配置檔案實作,用一個對象負責資料庫連接配接池的管理,以提高性能。

從配置檔案讀取資料庫連接配接的配置片段:

……

Class.forname(config.getValue(“JDBC_DRIVER”);

Conn = DriverManager.getConnection(config.getValue(“DB_URL”), config.getValue(“DB_USER”), config.getValue(“DB_PASSWORD”));

……

連接配接池管理類:

Public class DBHelper{

  Public static Connection getConnection() {

  //從連接配接池擷取資料庫連接配接

  }

Public static releaseConnection(Connection conn) {

   //将使用完的連接配接傳回到連接配接池

}

}

Public class MyDBPersistence {

   ……

   Connection conn = null;

try {

   conn = DBHelper.getConnection();

……

) finally  {

    DBHelper.releaseConnection(conn);

}

……

}

封建社會—專業作坊的出現使得生産力大大提高:

引入DAO(Data Access Object)模式(DAO實際上是Data Accessor模式和Active Domain Object模式的組合),實作

業務邏輯層的分離

資料通路底層實作的分離

資源管理和排程的分離(資料通路層的分離,使得資源的管理和緩存機制可以更好的得以應用,進而提高性能)

資料抽象(對底層資料封裝-對象Bean 使得業務邏輯可以通路更有意義的屬性名稱,而不是資料表的字段)。

業務邏輯層代碼:

public BigDecimal calcAmount(String customerID, BigDecimal amount) {

          //根據客戶ID獲得客戶記錄

         Customer customer = CustomerDAO.getCustomer(customerID);

          //根據客戶等級獲得打折規則

          Promotion promotion = PromotionDAO.getPromotion(customer.getLevel());

          //累計客戶總消費額,并儲存結果

          customer.setSumAmount(customer.getSumAmount().add(amount));

          customerDAO.save(customer);

           return amount.getmultiply(promotion.getRation());

}

實體對象<Active Domain Object>:

普通的實體bean(代碼省略)。

資料通路層代碼<Data Accessor>:

public class customerDAO {

public static Customer getCustomer(String ID) {

Connection conn;

ResultSet rset_customer = null;

PreparedStatement stmt_customer = null;

conn = DBHelper.getConnection();

……

……

……

Customer customer = new Customer():

Customer.setID(rset_customer.getInt(1);

……

DBHelper.releaseConnection(conn);

return customer

}

Public static void save(Customer customer) {

//同上

}

}

資本主義社會—面對複雜的環境,更加規模化和專業化:

對于一個産品而言,面臨着複雜多變的應用環境,如采用不同的資料庫,我們引進Factory模式和Proxy模式來實作對不同資料庫的通路機制,以更好的展現開閉原則—對擴充開放,對變化封裝。

public interface CustomerDAO {

       public Customer getCustomer(String custID);

public void save (Customer customer);

}

public class CustomerDAOImp_MySQL implements CustomerDAO {

}

public class CustomerDAOImp_Oracle implement CustomerDAO {

}

public class DAOFactory {

       private static HashMap daomap = null;

       public static Object getDAO(Class daoInterface) ;

              Initial();

              Object dao = daoMap.get(interface);

              if( null == dao)

              {

                      //報錯

               }

               return dao;

         }

          public static synchronized void initial() {

                   if(null == daomap) {

                          daoMap = DAOConfig.load(); //根據配置檔案加載DAO實作

           }

}

public BigDecimal calcAmount(String customerID, BigDecimal amount) {

           CustomerDAO customerDAO = (Customer)DAOFactory.getDAO(CustomerDAO.calss);

          //根據客戶ID獲得客戶記錄

         Customer customer = CustomerDAO.getCustomer(customerID);

          //根據客戶等級獲得打折規則

          Promotion promotion = PromotionDAO.getPromotion(customer.getLevel());

          //累計客戶總消費額,并儲存結果

          customer.setSumAmount(customer.getSumAmount().add(amount));

          customerDAO.save(customer);

           return amount.getmultiply(promotion.getRation());

}

calcAmount中似乎又夾雜了一點資料庫操作的代碼,當然事情不可能十全十美,總歸是要有所取舍。不過我們繼續用proxy模式對其進行重構優化。

public class CustomerProxy {

        public static Customer getCustomer(String customerID) {

              CustomerDAO custDAO = (CustomerDAO)DAOFactory.getDAO(CustomerDAO.class);

              return custDAO.getCustomer(customerID);

        }

        public static void save(Customer customer) {

               ……

        }

}

PromotionProxy類此。

再看看我們calcAmount:

public BigDecimal calcAmount(String customerID, BigDecimal amount) {

          //根據客戶ID獲得客戶記錄

         Customer customer = CustomerProxy.getCustomer(customerID);

          //根據客戶等級獲得打折規則

          Promotion promotion = PromotionProxy.getPromotion(customer.getLevel());

          //累計客戶總消費額,并儲存結果

          customer.setSumAmount(customer.getSumAmount().add(amount));

          customerDAO.save(customer);

           return amount.getmultiply(promotion.getRation());

}

一個簡單的例子,讓我們了解到了資料持久層的概念和重要性,同時也體會到了一些重要的思想和技術方法的應用--分層設計,解耦合,開閉原則,設計模式。