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

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

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

    Feng.Li's Java See

    抓緊時間,大步向前。
    隨筆 - 95, 文章 - 4, 評論 - 58, 引用 - 0
    數(shù)據(jù)加載中……

    DAO模式

      一 .有關(guān)DAO模式的介紹

              業(yè)務(wù)對象只應(yīng)該關(guān)注業(yè)務(wù)邏輯,不應(yīng)該關(guān)心數(shù)據(jù)存取的細(xì)節(jié)。數(shù)據(jù)訪問對象必須實(shí)現(xiàn)特定的持久化策略(如,基于JDBC或Hibernate的持久化邏輯), 這樣就抽出來了DAO層,作為數(shù)據(jù)源層,而之上的Domain Model層與之通訊而已,如果將那些實(shí)現(xiàn)了數(shù)據(jù)訪問操作的所有細(xì)節(jié)都放入高層Domain model(領(lǐng)域模型)的話,系統(tǒng)的結(jié)構(gòu)一定層次上來說就變得有些混亂。低級別的數(shù)據(jù)訪問邏輯與高級別的業(yè)務(wù)邏輯分離,用一個DAO接口隱藏持久化操作的 細(xì)節(jié),這樣使用的最終目的就是讓業(yè)務(wù)對象無需知道底層的持久化技術(shù)知識,這是標(biāo)準(zhǔn) j2ee 設(shè)計模式之一。一個典型的的DAO組成:DAO工廠類,DAO接口,實(shí)現(xiàn)DAO接口的具體類(每個 DAO 實(shí)例負(fù)責(zé)一個主要域?qū)ο蠡驅(qū)嶓w),VO(Value Object)。如果一個DAO 工廠只為一個數(shù)據(jù)庫的實(shí)現(xiàn)(現(xiàn)在只考慮這種情況)而創(chuàng)建很多的DAO的時候,實(shí)現(xiàn)該策略時,我們考慮采用工廠方法設(shè)計模 式.

             二.設(shè)計DAO要注意的問題
             在采用這種工廠方法設(shè)計模式來實(shí)現(xiàn)時我們其實(shí)要注意很多問題,哪個對象負(fù)責(zé)開始事務(wù),哪個負(fù)責(zé)事務(wù)結(jié)束?DAO 是否要負(fù)責(zé)事務(wù)的開始和結(jié)束? 應(yīng)用程序是否需要通過多少個DAO訪問數(shù)據(jù)?事務(wù)涉及一個DAO還是多個DAO?一個DAO是否調(diào)用另一個DAO的方法?了解上述問題的答案將有助于我們 選擇最適合的 DAO 的事務(wù)界定策略。在 DAO 中有兩種主要的界定事務(wù)的策略。一種方式是讓 DAO 負(fù)責(zé)界定事務(wù),另一種將事務(wù)界定交給調(diào)用這個 DAO 方法的對象處理。如果選擇了前一種方式,那么就將事務(wù)代碼嵌入到 DAO 中。如果選擇后一種方式,那么事務(wù)界定代碼就是在 DAO 類外面,在這里我將用<<Hibernate項目開發(fā)寶典>>中留言版的小例子來理解后一種工作方式是如何工作的,以及如何自己 實(shí)現(xiàn)一個類似Spring的IOC輕量級容器中Bean工廠的功能(當(dāng)然是沒有使用Spring應(yīng)用程序框架的情況下,對于這個簡單的例子來說更有助于我 們理解Spring的DI模式)。這個小實(shí)例所要實(shí)現(xiàn)的業(yè)務(wù)功能包括創(chuàng)建用戶,用戶登錄,發(fā)表文章,瀏覽文章,修改文章和刪除文章,所以有兩個對應(yīng)的實(shí)體 對象User,Message。本文不涉及到業(yè)務(wù)邏輯,以及顯示層部分。

      三.DAO的實(shí)現(xiàn)

      DAO 模式對開發(fā)J2EE應(yīng)用的人員來說都應(yīng)該很熟悉的,但是模式的實(shí)現(xiàn)各不相同,在這里我將按下面的思路來實(shí)現(xiàn):

      1.系統(tǒng)中的所有數(shù)據(jù)庫訪問都通過 DAO 進(jìn)行以實(shí)現(xiàn)封裝。

             2. 每個 DAO 實(shí)例負(fù)責(zé)一個主要域?qū)ο蠡驅(qū)嶓w。

             3.DAO 負(fù)責(zé)域?qū)ο蟮膭?chuàng)建、讀取(按主鍵)、更新和刪除(CRUD)。

      4. DAO 可允許基于除主鍵之外的標(biāo)準(zhǔn)進(jìn)行查詢,返回值通常是DAO 負(fù)責(zé)的域?qū)ο蠹稀?/p>

      5.像上面說的,DAO 不負(fù)責(zé)處理事務(wù)、會話或連接,而把這交給一個工具類,這樣做是為了實(shí)現(xiàn)靈活性。

         (一)泛型 DAO 接口

      泛型 DAO 的基礎(chǔ)是其 CRUD 操作。下面的接口定義泛型 DAO 的方法:

          

      提供數(shù)據(jù)庫操作接口給業(yè)務(wù)層使用

           清單1

      public interface IMessageDAO
    { //對應(yīng)留言信息Message這個實(shí)體對象的操作
    public void saveMessage( Message message );
    public void updateMessage( Message message );
    public List getMessages( );
    public void deleteMessage( String id, String userId );
    public Message getMessage( String id );
    }

             清單2

      public interface IUserDAO
           {
           public void saveUser( User user );
           public User getUser( String username );
          public User getUserById( String id );
          }

        (二)泛型DAO的實(shí)現(xiàn)

     第一個泛型 DAO 的實(shí)現(xiàn)
    DAO 的實(shí)現(xiàn)類,封裝數(shù)據(jù)庫邏輯,按<<Hibernate項目開發(fā)寶典>>書上所說的將那些持久化操作封裝到一個DAO基礎(chǔ)類,也相 當(dāng)于是一個工具類,通過繼承這個基礎(chǔ)類,DAO的實(shí)現(xiàn)類可以在很大程度上簡化持久化操作的步驟,減少代碼的重復(fù)量。這個基礎(chǔ)類命名為 HibernateDAO,具體的方法實(shí)現(xiàn)如清單2

    清單 3.

    /**
    * 使用Hibernate實(shí)現(xiàn)DAO的基礎(chǔ)類
    * 包括了持久化操作的一些基礎(chǔ)方法
    */
    public class HibernateDAO
    {
    /**
    * 保存對象信息到數(shù)據(jù)庫
    * @param obj 需要進(jìn)行持久化操作的對象
    */
    public void saveObject(Object obj)
    {
       HibernateUtil.getCurrentSession().save(obj);
    }

    /**
    * 更新持久化對象
    * @param obj 需要更新的對象
    */
    public void updateObject(Object obj)
    {
       HibernateUtil.getCurrentSession().update(obj);
    }

    /**
    * 使用HQL語句進(jìn)行查詢
    * @param hsql 查詢語句
    * @return 符合條件的對象集合
    */
    public List getObjects(String hsql)
    {
       List result = HibernateUtil.getCurrentSession().createQuery(hsql).list();
       return result;
    }

    /**
    * 使用HQL語句進(jìn)行對象的查詢
    * @param hsql 查詢語句
    * @return 符合條件的對象
    */
    public Object getObject(String hsql)
    {
       Object result = HibernateUtil.getCurrentSession().createQuery(hsql).uniqueResult();
       return result;
    }

    /**
    * 根據(jù)ID值得到持久化的對象
    * @param cls 對象的類型
    * @param id ID值
    * @return 指定ID的對象
    */
    public Object getObject(Class cls, String id)
    {
       Object result = HibernateUtil.getCurrentSession().get(cls, id);
       return result;
    }

    /**
    * 刪除對象信息
    * @param obj 被刪除的對象
    */
    public void deleteObject(Object obj)
    {
       HibernateUtil.getCurrentSession().delete(obj);
    }
    }

    清單 4. IMessageDAO接口的實(shí)現(xiàn)類

    /**
    * IMessageDAO接口的Hibernate實(shí)現(xiàn)
    */
    public class MessageDAO extends HibernateDAO implements IMessageDAO
    {

    /**
    * 保存留言信息
    *
    * @param message
    *            被保存的留言對象
    */
    public void saveMessage(Message message)
    {
       super.saveObject(message);
    }

    /**
    * 得到所有的留言信息
    *
    * @return 返回所有的留言信息
    */
    public List getMessages()
    {
       String hsql = "from Message";
       return super.getObjects(hsql);
    }

    /**
    * 刪除留言信息
    *
    * @param id
    *            要刪除的留言信息的ID值
    * @param userId
    *            執(zhí)行刪除操作的用戶ID
    */
    public void deleteMessage(String id, String userId)
    {
       Message msg = getMessage(id);
       if (msg == null)
       {
        throw new MessageDAOException("找不到你所要刪除的留言!");
       }

       if (!msg.getUser().getId().equals(userId))
       {
        throw new MessageDAOException("你不能刪除別人的留言!");
       }

        deleteObject(msg);
    }

    /**
    * 得到留言信息
    *
    * @param id
    *            留言的ID值
    * @return 指定ID值得留言對象
    */
    public Message getMessage(String id)
    {
       return (Message) getObject(Message.class, id);
    }

    /**
    * 更新留言信息
    *
    * @param message
    *            欲更新的留言對象
    */
    public void updateMessage(Message message)
    {
       updateObject(message);
    }

    } 
    清單 5. IUserDAO接口的實(shí)現(xiàn)類

    /**
    * IUserDAO接口的Hibernate實(shí)現(xiàn)
    */
    public class UserDAO extends HibernateDAO implements IUserDAO
    {

    /**
    * 保存用戶信息到數(shù)據(jù)庫
    * @param user 被保存的用戶對象
    */
    public void saveUser(User user)
    {
       if (user == null)
        return;

       User u = getUser(user.getName());
       if (u != null)
        throw new MessageDAOException("用戶名已經(jīng)存在,請使用其它用戶名!");

     saveObject(user);
    }

    /**
    * 得到用戶對象
    * @param username 用戶的登錄名
    * @return 指定登錄名的用戶對象
    */
    public User getUser(String username)
    {
       User u = (User) getObject("from User u where u.name = '" + username
         + "'");
       return u;
    }

    /**
    * 得到用戶對象的信息
    * @param id 用戶的ID值
    * @return 指定的用戶信息
    */
    public User getUserById(String id)
    {
       return (User) getObject(User.class, id);
    }

    }

    四.事務(wù)界定

         前面說過, DAO 不負(fù)責(zé)處理事務(wù)、會話或連接,而把這交給一個工具類,封裝所有關(guān)于數(shù)據(jù)庫的操作。把Session的獲取,語句的關(guān)閉等放在這個類更好。通常的設(shè)計把數(shù)據(jù) 庫的代碼放到DAO的實(shí)現(xiàn)類中,這樣如果某個DAO實(shí)現(xiàn)類設(shè)計不良,要改動就必須牽涉到很多地方,不利于維護(hù)。在這里的工具類代碼如清單6。

     清單 6.

     public class HibernateUtil
    {

        private static Log log = LogFactory.getLog(HibernateUtil.class);

        private static final String INTERCEPTOR_CLASS = "hibernate.util.interceptor_class";

        private static Configuration configuration;
        private static SessionFactory sessionFactory;
        private static ThreadLocal threadSession = new ThreadLocal();
        private static ThreadLocal threadTransaction = new ThreadLocal();

        private static boolean useThreadLocal = true;

        static {
            // Create the initial SessionFactory from the default configuration files
            try {

                // Replace with Configuration() if you don't use annotations or JDK 5.0
                //configuration = new AnnotationConfiguration();
                configuration = new Configuration();

                // Read not only hibernate.properties, but also hibernate.cfg.xml
                configuration.configure();

                // Assign a global, user-defined interceptor with no-arg constructor
                String interceptorName = configuration.getProperty(INTERCEPTOR_CLASS);
                if (interceptorName != null) {
                    Class interceptorClass =
                            HibernateUtil.class.getClassLoader().loadClass(interceptorName);
                    Interceptor interceptor = (Interceptor)interceptorClass.newInstance();
                    configuration.setInterceptor(interceptor);
                }

                // Disable ThreadLocal Session/Transaction handling if CMT is used
                if (org.hibernate.transaction.CMTTransactionFactory.class.getName()
                     .equals( configuration.getProperty(Environment.TRANSACTION_STRATEGY) ) )
                    useThreadLocal = false;

                if (configuration.getProperty(Environment.SESSION_FACTORY_NAME) != null) {
                    // Let Hibernate bind it to JNDI
                    configuration.buildSessionFactory();
                } else {
                    // or use static variable handling
                    sessionFactory = configuration.buildSessionFactory();
                }

            } catch (Throwable ex) {
                // We have to catch Throwable, otherwise we will miss
                // NoClassDefFoundError and other subclasses of Error
                log.error("Building SessionFactory failed.", ex);
                throw new ExceptionInInitializerError(ex);
            }
        }

        /**
         * Returns the original Hibernate configuration.
         *
         * @return Configuration
         */
        public static Configuration getConfiguration() {
            return configuration;
        }

        /**
         * Returns the global SessionFactory.
         *
         * @return SessionFactory
         */
        public static SessionFactory getSessionFactory() {
            SessionFactory sf = null;
            String sfName = configuration.getProperty(Environment.SESSION_FACTORY_NAME);
            if ( sfName != null) {
                log.debug("Looking up SessionFactory in JNDI.");
                try {
                    sf = (SessionFactory) new InitialContext().lookup(sfName);
                } catch (NamingException ex) {
                    throw new RuntimeException(ex);
                }
            } else {
                sf = sessionFactory;
            }
            if (sf == null)
                throw new IllegalStateException("SessionFactory not available.");
            return sf;
        }

        /**
         * Closes the current SessionFactory and releases all resources.
         * <p>
         * The only other method that can be called on HibernateUtil
         * after this one is rebuildSessionFactory(Configuration).
         */
        public static void shutdown() {
            log.debug("Shutting down Hibernate.");
            // Close caches and connection pools
            getSessionFactory().close();

            // Clear static variables
            configuration = null;
            sessionFactory = null;

            // Clear ThreadLocal variables
            threadSession.set(null);
            threadTransaction.set(null);
        }


        /**
         * Rebuild the SessionFactory with the static Configuration.
         * <p>
         * This method also closes the old SessionFactory before, if still open.
         * Note that this method should only be used with static SessionFactory
         * management, not with JNDI or any other external registry.
         */
         public static void rebuildSessionFactory() {
            log.debug("Using current Configuration for rebuild.");
            rebuildSessionFactory(configuration);
         }

        /**
         * Rebuild the SessionFactory with the given Hibernate Configuration.
         * <p>
         * HibernateUtil does not configure() the given Configuration object,
         * it directly calls buildSessionFactory(). This method also closes
         * the old SessionFactory before, if still open.
         *
         * @param cfg
         */
         public static void rebuildSessionFactory(Configuration cfg) {
            log.debug("Rebuilding the SessionFactory from given Configuration.");
            synchronized(sessionFactory) {
                if (sessionFactory != null && !sessionFactory.isClosed())
                    sessionFactory.close();
                if (cfg.getProperty(Environment.SESSION_FACTORY_NAME) != null)
                    cfg.buildSessionFactory();
                else
                    sessionFactory = cfg.buildSessionFactory();
                configuration = cfg;
            }
         }

        /**
         * Retrieves the current Session local to the thread.
         * <p/>
         * If no Session is open, opens a new Session for the running thread.
         * If CMT is used, returns the Session bound to the current JTA
         * container transaction. Most other operations on this class will
         * then be no-ops or not supported, the container handles Session
         * and Transaction boundaries, ThreadLocals are not used.
         *
         * @return Session
         */
        public static Session getCurrentSession() {
            if (useThreadLocal) {
                Session s = (Session) threadSession.get();
                if (s == null) {
                    log.debug("Opening new Session for this thread.");
                    s = getSessionFactory().openSession();
                    threadSession.set(s);
                }
                return s;
            } else {
                return getSessionFactory().getCurrentSession();
            }
        }

        /**
         * Closes the Session local to the thread.
         * <p>
         * Is a no-op (with warning) if called in a CMT environment. Should be
         * used in non-managed environments with resource local transactions, or
         * with EJBs and bean-managed transactions.
         */
        public static void closeSession() {
            if (useThreadLocal) {
                Session s = (Session) threadSession.get();
                threadSession.set(null);
                Transaction tx = (Transaction) threadTransaction.get();
                if (tx != null && (!tx.wasCommitted() || !tx.wasRolledBack()) )
                    throw new IllegalStateException("Closing Session but Transaction still open!");
                if (s != null && s.isOpen()) {
                    log.debug("Closing Session of this thread.");
                    s.close();
                }
            } else {
                log.warn("Using CMT/JTA, intercepted superfluous close call.");
            }
        }

        /**
         * Start a new database transaction.
         * <p>
         * Is a no-op (with warning) if called in a CMT environment. Should be
         * used in non-managed environments with resource local transactions, or
         * with EJBs and bean-managed transactions. In both cases, it will either
         * start a new transaction or join the existing ThreadLocal or JTA
         * transaction.
         */
        public static void beginTransaction() {
            if (useThreadLocal) {
                Transaction tx = (Transaction) threadTransaction.get();
                if (tx == null) {
                    log.debug("Starting new database transaction in this thread.");
                    tx = getCurrentSession().beginTransaction();
                    threadTransaction.set(tx);
                }
            } else {
                log.warn("Using CMT/JTA, intercepted superfluous tx begin call.");
            }
        }

        /**
         * Commit the database transaction.
         * <p>
         * Is a no-op (with warning) if called in a CMT environment. Should be
         * used in non-managed environments with resource local transactions, or
         * with EJBs and bean-managed transactions. It will commit the
         * ThreadLocal or BMT/JTA transaction.
         */
        public static void commitTransaction() {
            if (useThreadLocal) {
                Transaction tx = (Transaction) threadTransaction.get();
                try {
                    if ( tx != null && !tx.wasCommitted()
                                    && !tx.wasRolledBack() ) {
                        log.debug("Committing database transaction of this thread.");
                        tx.commit();
                    }
                    threadTransaction.set(null);
                } catch (RuntimeException ex) {
                    log.error(ex);
                    rollbackTransaction();
                    throw ex;
                }
            } else {
                log.warn("Using CMT/JTA, intercepted superfluous tx commit call.");
            }
        }

        /**
         * Rollback the database transaction.
         * <p>
         * Is a no-op (with warning) if called in a CMT environment. Should be
         * used in non-managed environments with resource local transactions, or
         * with EJBs and bean-managed transactions. It will rollback the
         * resource local or BMT/JTA transaction.
         */
        public static void rollbackTransaction() {
            if (useThreadLocal) {
                Transaction tx = (Transaction) threadTransaction.get();
                try {
                    threadTransaction.set(null);
                    if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {
                        log.debug("Tyring to rollback database transaction of this thread.");
                        tx.rollback();
                        log.debug("Database transaction rolled back.");
                    }
                } catch (RuntimeException ex) {
                    throw new RuntimeException("Might swallow original cause, check ERROR log!", ex);
                } finally {
                    closeSession();
                }
            } else {
                log.warn("Using CMT/JTA, intercepted superfluous tx rollback call.");
            }
        }

        /**
         * Reconnects a Hibernate Session to the current Thread.
         * <p>
         * Unsupported in a CMT environment.
         *
         * @param session The Hibernate Session to be reconnected.
         */
        public static void reconnect(Session session) {
            if (useThreadLocal) {
                log.debug("Reconnecting Session to this thread.");
                session.reconnect();
                threadSession.set(session);
            } else {
                log.error("Using CMT/JTA, intercepted not supported reconnect call.");
            }
        }

        /**
         * Disconnect and return Session from current Thread.
         *
         * @return Session the disconnected Session
         */
        public static Session disconnectSession() {
            if (useThreadLocal) {
                Transaction tx = (Transaction) threadTransaction.get();
                if (tx != null && (!tx.wasCommitted() || !tx.wasRolledBack()) )
                    throw new IllegalStateException("Disconnecting Session but Transaction still open!");
                Session session = getCurrentSession();
                threadSession.set(null);
                if (session.isConnected() && session.isOpen()) {
                    log.debug("Disconnecting Session from this thread.");
                    session.disconnect();
                }
                return session;
            } else {
                log.error("Using CMT/JTA, intercepted not supported disconnect call.");
                return null;
            }
        }

        /**
         * Register a Hibernate interceptor with the current SessionFactory.
         * <p>
         * Every Session opened is opened with this interceptor after
         * registration. Has no effect if the current Session of the
         * thread is already open, effective on next close()/getCurrentSession().
         * <p>
         * Attention: This method effectively restarts Hibernate. If you
         * need an interceptor active on static startup of HibernateUtil, set
         * the <tt>hibernateutil.interceptor</tt> system property to its
         * fully qualified class name.
         */
        public static void registerInterceptorAndRebuild(Interceptor interceptor) {
            log.debug("Setting new global Hibernate interceptor and restarting.");
            configuration.setInterceptor(interceptor);
            rebuildSessionFactory();
        }

        public static Interceptor getInterceptor() {
            return configuration.getInterceptor();
        }
    }
    上 面的代碼中,如果是使用Hibernate3.1以上版本對Session的管理進(jìn)行了優(yōu)化,提供了內(nèi)建的Session管理方式,所以上面也可以不用 ThreadLocal類型的實(shí)例對象來保存。書中提到一點(diǎn),現(xiàn)在絕大多數(shù)的應(yīng)用都是基于Web來實(shí)現(xiàn)的,這里通過Web所提供的Filter機(jī)制實(shí)現(xiàn)持 久化操作的進(jìn)一步的封裝,將一個用戶請求中所做的所有持久化操作看成一個事務(wù),當(dāng)然,如果某個業(yè)務(wù)確實(shí)需要將這個請求分解成多個事務(wù),那么也可以在業(yè)務(wù)實(shí) 現(xiàn)的方法中自行地進(jìn)行事務(wù)的提交或者回流操作,完成的Hibernate如清單7

    posted on 2008-03-10 14:54 小鋒 閱讀(1726) 評論(0)  編輯  收藏


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 女人与禽交视频免费看| 在线日韩日本国产亚洲| 日韩色视频一区二区三区亚洲 | 国产成人精品日本亚洲18图| 黄瓜视频高清在线看免费下载| 国产成人亚洲精品播放器下载| 亚洲中文字幕久久精品无码APP | 亚洲综合av一区二区三区| 免费在线观看亚洲| 无码人妻久久一区二区三区免费| 久久亚洲国产成人影院| 中文字幕亚洲图片| 精品久久久久成人码免费动漫| 四虎国产精品成人免费久久| 久久亚洲私人国产精品| 无码欧精品亚洲日韩一区夜夜嗨 | 亚洲国产精品ⅴa在线观看| 亚洲啪啪AV无码片| 在线视频免费观看www动漫| 最近免费字幕中文大全| 亚洲熟妇无码AV| 亚洲成AV人片一区二区密柚| 日韩中文字幕免费| 182tv免费视视频线路一二三 | aa毛片免费全部播放完整| 久久夜色精品国产噜噜亚洲AV| 亚洲国产成人精品无码久久久久久综合| 99久久免费观看| 国产无限免费观看黄网站| 亚洲乱码国产乱码精华| 99人中文字幕亚洲区| 亚洲精品国产福利一二区| 成人黄页网站免费观看大全| 最新国产乱人伦偷精品免费网站| 亚洲aⅴ无码专区在线观看| 亚洲乱人伦精品图片| 亚洲AV日韩AV高潮无码专区| 亚洲最大av无码网址| 国产成人高清精品免费鸭子| 4虎永免费最新永久免费地址| 免费a级毛片无码a∨免费软件|