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

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

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

    Dict.CN 在線詞典, 英語學習, 在線翻譯

    都市淘沙者

    荔枝FM Everyone can be host

    統計

    留言簿(23)

    積分與排名

    優秀學習網站

    友情連接

    閱讀排行榜

    評論排行榜

    使用Spring的JdbcTemplate實現DAO(zhuan)

    直接使用JDBC操作數據庫來實現DAO,相對于使用持久層框架(Hibernate等) ,可以減少映射等帶來的性能損失。
    一般而言,使用JDBC來操作數據庫,無非是以下幾個步驟:
        獲取數據源
        取得數據庫連接
        執行SQL語句
        處理執行結果和異常
        釋放數據庫連接
    這些步驟是每次進行數據庫操作都必須進行的。很顯然,可以使用模板模式來簡化設計,將執行SQL語句的部分抽象出來,其它的步驟由模板自動完成。
    雖然設計這樣的模板并不算復雜,但是現在我們完全無需自己來實現,應為Spring已經為我們提供了一個非常實用的模板--JdbcTemplate。它位于Spring包org.springframework.jdbc.core下,是Spring的jdbc工具包的核心類之一。使用JdbcTemplate的前提是必須為其提供數據源(DataSource),并通過實用類DataSourceUtils來安全地獲取和釋放數據庫連接(Connection對象)。可以說已經是一個完美的實現,因此我們只要放心地使用就可以了。

    總體思路
        (1)數據源通過Spring的容器來提供;
        (2)DAO通過靜態方式從Spring容器中獲取;
        (3)針對接口編程;
        (4)提供數據操作父類,簡化具體DAO實現。

    一、DAO地實現
        遵循Spring的良好編程風格,針對接口編程。同時,為了簡化對接口的實現,還提供了一個所有實現類的父類,提供了具體的數據庫操作方法,這些方法當然就是使用JdbcTemplate來實現的了。

    1、Dao父類
        主要目的是獲取數據源,為子類提供具體的數據庫操作方法:

    public class Dao {
        
        
    /**
         * 日志
         
    */

        
    protected Log log = LogFactory.getLog(this.getClass().getName());
        
        
    /**
         * 執行查詢SQL文
         *  
         * 
    @param strSql
         
    */

        
    protected void doQuery(String strSql) {

            JdbcTemplate jt 
    new JdbcTemplate(getDataSource());    //使用
    JdbcTemplate
            
            
    try {
                List result 
    = jt.queryForList(strSql);
                
    this.resultList = result;
                
                
    this.resultCount = result.size();
                
                log.debug(logHeader 
    + strSql);
                
            }
     catch (DataAccessException de) {
                
                log.error(logHeader 
    + de);
            }

            
        }
        
        
        
    /**
         * 執行更新SQL文
         * 
         * 
    @param strSql
         
    */

        
    protected boolean doUpdate(String strSql) {
            
            JdbcTemplate jt 
    = new JdbcTemplate(getDataSource());
            
            
    try {
                
    this.affectedRows = jt.update(strSql);
                
                log.debug(logHeader 
    + strSql);
                
                
    return true;
                
            }
     catch (DataAccessException de) {
                
                log.error(logHeader 
    + de);
                
                
    return false;
            }

        }


        
    /**
         * 獲取執行結果的一行
         * 
         * 
    @return 一行結果用Map保存
         
    */

        
    protected Object getResult() {
            
    if (this.resultList == null || this.resultList.size() == 0{
                
    return null;
            }
     else {
                
    return this.resultList.get(0);
            }

        }

        
        
    /**
         * 獲取查詢結果
         * 
         * 
    @return 查詢結果以List保存
         
    */

        
    protected List getResultList() {
            
    return this.resultList;
        }

        
        
    /**
         * 獲取更新所影響的行記錄數
         * 
         * 
    @return 整數
         
    */

        
    protected int getAffectedRows() {
            
    return this.affectedRows;
        }

            
        
    /**
         * 獲取查詢結果總行數
         * 
         * 
    @return 整數
         
    */

        
    protected long getResultCount() {
            
    return this.resultCount;
        }
        

        
    /** 日志頭部 */
        
    protected String logHeader = LogUtil.getLogHeader();
        
        
    /**
         * 
    @return dataSource
         
    */

        
    public DataSource getDataSource() {
            
    return dataSource;
        }


        
    /**
         * 
    @param dataSource 設置 dataSource
         
    */

        
    public void setDataSource(DataSource dataSource) {
            
    this.dataSource = dataSource;   //獲取數據源
        }
        
        
        
    //-------------------------------------------------------------------------

        
    private List resultList = null;
        
    private long resultCount = 0;
        
    private int affectedRows = 0;    
        
    private DataSource dataSource = null;
    }

    此處為dataSource提供了get/set方法,可以從使用Spring的Ioc中獲益,即可以使用配置的方法為之選擇數據源(本文的實現方式);同時,也可以通過代碼手工提供數據源。

    2、UserDao接口定義:

    public interface UserDao {
        
        
    /**
         * 根據用戶ID,獲取User對象
         * 
         * 
    @param 用戶ID
         * 
    @return User対象
         
    */

        
    public User getUserByLoginId(String loginId);

        
    }

    就一個方法,僅僅是示例而已 ^_^

    3、UserDaoImpl實現:

    public class UserDaoImpl extends Dao implements UserDao {

        
    /*
         * (non-Javadoc)
         * @see my.test.dao.UserDao#getUserByLoginId(java.lang.String)
         
    */

        
    public User getUserByLoginId(String loginId) {
            
            User user 
    = null;
            
            doQuery(Sql.S_M_MEMBER_01(loginId));
            
    if (getResultCount() > 0{            
                user 
    = new User();
                
                Map result 
    = (Map) getResult();
                user.setMemberId(String.valueOf(result.get(
    "MEMBER_ID")));
               
    //以下省略
            }

            
            
    return user;
        }


    }

    這里只是簡單地實現了平面(二維的數據庫)和立體(對象)的轉換,并沒有涉及到對關系數據庫中的關系的轉化,這些都要靠自己去實現,還是有些不方便。自己實現的麻煩之處就是要手工編寫所有的SQL語句...但一切都在自己的掌控制中,也沒什么不好,呵呵。
    現在看看紅色的部分用起來是不是簡便了很多了。

    羅羅嗦嗦地一堆代碼,還不如看圖來得清爽:


    二、DAO的使用
        既然使用了JdbcTemplate,為什么不再多使用一點Spring的功能呢?比如通過配置為DAO提供數據源等。但問題是,整個應用系統如果沒有使用Spring的容器來管理,如何才能使用Ioc功能呢?還好,可以將Spring的應用上下文(ApplicationContext)單獨地使用。我們可以將DAO作為單獨的bean分別定義,然后從ApplicationContext中取得這些bean的實例。Spring會根據定義為我們自動生成所需的DAO的實例。只要在定義的時候,為DAO提供Datasoure即可實現數據源的自動配置了。
    1、daoBeans.xml

    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

    <beans>
        
        
    <bean id="dataSource" 
            class
    ="org.springframework.jdbc.datasource.DriverManagerDataSource"
            destroy-method
    ="close">
            
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
            
    <property name="url" value="jdbc:oracle:thin:@192.168.***.***:1521:***"/>
            
    <property name="username" value="username"/>
            
    <property name="password" value="password"/>
            
    <property name="validationQuery" value="SELECT 1 FROM DUAL"/>
        
    </bean>

        
    <bean id="userDao" class="my.test.dao.impl.UserDaoImpl">
            
    <property name="dataSource">      <--為UserDao設置數據源
                
    <ref bean="dataSource"/>     
            
    </property>
        
    </bean>

    </beans>

    使用了Spring的數據源管理功能,通過定義的方式為UserDao提供了數據源(在生成UserDao實例的時候,setDataSource方法就會被調用從而將dataSource載入)。

    2、DAO獲取工具的實現
        編寫了一個工具類,提供根據DAO名(daoBeans.xml中定義的名字)獲取DAO對象的靜態方法。

    public class DaoBeanFactory {
        
        
    private static Log log = LogFactory.getLog(DaoBeanFactory.class.getName());
        
        
    private static final String DAO_BEANS= "/daoBeans.xml";
        
    private static ApplicationContext ctx = null;
        
        
    static {
            ctx 
    = new ClassPathXmlApplicationContext(DAO_BEANS);
            log.debug(DAO_BEANS 
    + "被成功載入。");
        }

        
        
    public static Object getDao(String daoName){        
            
    return ctx.getBean(daoName);
        }

    }

    這里首先通過讀取daoBeans.xml初始化應用上下文(ApplicationContext )。由于是靜態方法,只會在第一次被使用時執行一次;然后就可從上下文中獲取所需要的指名DAO對象了:

    private UserDao userDao = (UserDao) DaoBeanFactory.getDao("userDao");


    到此為止,可以說從實現到使用都已經大功告成了,happy一下。

    三、進一步改進
        并不是說一切都是完美的。比如,第一次執行DaoBeanFactory.getDao方法時,會進行應用上下文的初始化,耗時較多;想改善數據源的管理,比如使用連接池;更進一步,如果大部分的工作都是進行查詢,想提高系統的查詢效率,該如何呢?
        時間不夠,請等待下回分解。


    1、對ApplicationContex初始化的改進
        DAO的獲取工具類DaoBeanFactory首次被使用的時候會花上幾秒鐘執行ApplicationContex的初始化工作。如果用戶在進行登錄的時候,輸入了用戶名和密碼之后要等上幾秒鐘后才被告知可以進入了,這樣的系統給人的第一印象就是--怎么這么慢啊!為了盡量避免這種情況出現,既然是初始化而且還耗時,我們就應該盡量將這種初始化工作放到系統啟動的時候去做。
        實現的方法很多,我就簡單寫了一個初始化Servlet,在Servlet的init中調用一次DaoBeanFactory即可觸發ApplicationContex的初始化:

    public class AppInitServlet extends HttpServlet {

        
    /**
         * 
         
    */

        
    private static final long serialVersionUID = 2987034642754889458L;
        
        
    public void init() {
            log.info(
    "應用系統啟動開始…");
            
            
    if (DaoBeanFactory.getDao("dataSource"!= null{
                log.info(
    "應用系統啟動正常終了。");
            
            }
     else {        
                log.info(
    "應用系統啟動異常終了。");
            }

        }

        
        
    private Log log = LogFactory.getLog(AppInitServlet.class.getName());

    }

    然后在web.xml中設置為啟動執行就可以了:

       <servlet>
            
    <servlet-name>AppInit</servlet-name>
            
    <servlet-class>my.test.common.AppInitServlet</servlet-class>
            
    <load-on-startup>1</load-on-startup>
        
    </servlet>

    重新啟動時,就可以看到Log打印出的啟動信息。再次登錄,快多了吧!

    2、更換數據源管理
        dataSource使用的是Spring的DriverManagerDataSource。一般情況下,這已經足夠了。但它沒有提供連接池功能,對系統的整體性能有所影響。于是,更換具有連接池功能的吧。我用的是開源的DBCP連接池,配置也很簡便:

        <bean id="dataSource"
            class
    ="org.apache.commons.dbcp.BasicDataSource"
            destroy-method
    ="close">
            
    <property name="driverClassName">
                
    <value>oracle.jdbc.driver.OracleDriver</value>
            
    </property>
            
    <property name="url">
                
    <value>jdbc:oracle:thin:@192.168.4.***:1521:***</value>
            
    </property>
            
    <property name="username">
                
    <value>username</value>
            
    </property>
            
    <property name="password">
                
    <value>password</value>
            
    </property>
            
    <property name="validationQuery">            
                
    <value>SELECT 1 FROM DUAL</value>
            
    </property>                                                       
            
    <property name="testOnBorrow">               
                
    <value>true</value>                                   
            
    </property>                                                       
        
    </bean>

    這里也有要注意的地方。當數據庫服務器重新啟動或者出現故障后,連接池中的連接是要被清空的。但是DBCP似乎沒有去自動檢測連接是否還有效。為了安全起見,最好在使用前測試其有效性。灰色背景部分的配置就是這個目的。

    3、增加查詢緩存
        在使用Hibernate的時候,可以很容易地獲得緩存帶來的系統性能優化。這里,我了達到相似的效果,也增加了緩存。其實Spring已經提供了使用各種緩存的接口,它位于org.springframework.cache.ehcache包下。
        如何實現緩存功能呢?當每個DAO執行查詢方法的時候,就先到緩存中查找歷史緩存數據,存在則返回,不存在才去訪問數據庫。勢必要為每一個這樣的查詢方法都做一個if判斷。若是日后想取消或撤換緩存的時候,這就成了一個艱巨的修改任務。這就和事務管理類似,我可以使用也可以不使用。很自然地,就想到了使用Spring的AOP功能,對每個查詢方法作橫切處理,增加對緩存的判斷。
        很幸運,這個世界上有很多很勤快的人,讓我們可以變得越來越懶。Pieter Coucke已經實現了一個非常實用的AOP Cache。根據他提供的例子,很容易就實現了一個基于AOP的DAO緩存。首先下載Spring AOP Cache的jar文件以及EHCache的jar文件(我使用的是EHCache,當然也可以使用其它的),加入到系統工程中。剩下的任務就是寫配置文件:

        <!-- Cache Configuration -->    
        
    <bean id="cacheInterceptor" class="org.springframework.aop.interceptor.cache.EHCacheInterceptor">
            
    <property name="refreshPeriods">
                
    <props>
                    
    <prop key="my.test.dao.UserDao@getUserByLoginId">900</prop>
                
    </props>
            
    </property>

            
    <property name="identifiers">
                
    <props>
                    
    <prop key="java.lang.String">toString</prop>
                
    </props>
            
    </property>
        
    </bean>
        
        
    <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            
    <property name="advice">
                
    <ref bean="cacheInterceptor"/>
            
    </property>
            
    <property name="patterns">
                
    <list>
                    
    <value>.*get.*</value>         <!-- 這里就是匹配查詢方法了 -->
                
    </list>
            
    </property>
        
    </bean>
        
    <bean id="cacheProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            
    <property name="beanNames">
                
    <value>*Dao</value>
            
    </property>
            
    <property name="interceptorNames">
                
    <list>
                    
    <value>advisor</value>
                
    </list>
            
    </property>
        
    </bean>

    重新啟動后,登錄完成后再登錄一次試試看?

    cache.CacheInterceptor (CacheInterceptor.java:229)     - Returning cached data for key [efdd56@java.lang.String#fn] in cache [my.test.dao.UserDao@getUserByLoginId]

    看到上面的Log信息代替了原有的訪問數據庫的部分,高興了吧!

    好了,拍拍手,收工 ^_^!

    posted on 2009-01-17 09:30 都市淘沙者 閱讀(3204) 評論(0)  編輯  收藏


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


    網站導航:
     
    主站蜘蛛池模板: 在线视频免费观看爽爽爽| 久久亚洲AV无码精品色午夜麻豆| 亚洲精品在线免费观看| 免费人成网站永久| 中文字幕在线观看亚洲日韩| 久久国产亚洲观看| 亚洲中文字幕无码爆乳av中文| 成人毛片手机版免费看| 巨波霸乳在线永久免费视频| 日韩电影免费在线观看网站| 曰批全过程免费视频免费看 | 亚洲色av性色在线观无码| 综合亚洲伊人午夜网 | 亚洲人成7777影视在线观看| 亚洲av丰满熟妇在线播放| 毛茸茸bbw亚洲人| 免费人成视频在线观看视频| 日韩免费视频一区| 无码视频免费一区二三区| 91嫩草免费国产永久入口| 久久国产精品免费专区| 中文精品人人永久免费| 久久99精品免费一区二区| 少妇太爽了在线观看免费视频| 免费一级做a爰片久久毛片潮| 国产精品亚洲专区无码唯爱网| 91丁香亚洲综合社区| 亚洲国产成人久久99精品| 亚洲白嫩在线观看| 亚洲妇女水蜜桃av网网站| 亚洲成a人片在线网站| 亚洲综合无码一区二区| 精品亚洲成a人片在线观看少妇| 久久久无码精品亚洲日韩蜜桃 | 美女扒开尿口给男人爽免费视频| 亚洲成AV人片高潮喷水| 亚洲成a∨人片在无码2023| 亚洲av无码日韩av无码网站冲| 亚洲成AV人片在线观看WWW| 狠狠久久永久免费观看| 最新免费jlzzjlzz在线播放|