DAO 设计模式 事务界定

 

前面说过, DAO 不负责处理事务、会话或连接,而把这交给一个工具类,封装所有关于数据库的操作。把Session的获取,语句的关闭等放在这个类更好。通常的设计把数据 库的代码放到DAO的实现类中,这样如果某个DAO实现类设计不良,要改动就必须牵涉到很多地方,不利于维护。在这里的工具类代码如清单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的管理进行了优化,提供了内建的Session管理方式,所以上面也可以不用 ThreadLocal类型的实例对象来保存。书中提到一点,现在绝大多数的应用都是基于Web来实现的,这里通过Web所提供的Filter机制实现持 久化操作的进一步的封装,将一个用户请求中所做的所有持久化操作看成一个事务,当然,如果某个业务确实需要将这个请求分解成多个事务,那么也可以在业务实 现的方法中自行地进行事务的提交或者回流操作,完成的Hibernate如清单7

 

清单7

public class HibernateFilter implements Filter
{
    private static Log log = LogFactory.getLog(HibernateFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Servlet filter init, now opening/closing a Session for each request.");
    }

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException
    {
        // There is actually no explicit "opening" of a Session, the
        // first call to HibernateUtil.beginTransaction() in control
        // logic (e.g. use case controller/event handler, or even a
        // DAO factory) will get a fresh Session.
        try
        {
        HibernateUtil.beginTransaction();
       
        request.setCharacterEncoding( "gb2312" );
       
            chain.doFilter(request, response);
            // Commit any pending database transaction.
            HibernateUtil.commitTransaction();

        }
        catch (ServletException ex)
        {
            log.debug("Rolling back the database transaction.");
            HibernateUtil.rollbackTransaction(); // Also closes the Session
            // Just rollback and let others handle the exception, e.g. for display
            throw ex;
        }
        catch (IOException ex)
        {
            log.debug("Rolling back the database transaction.");
            HibernateUtil.rollbackTransaction(); // Also closes the Session
            // Just rollback and let others handle the exception, e.g. for display
            throw ex;
        }
        finally
        {
            // No matter what happens, close the Session.
            HibernateUtil.closeSession();
        }
    }

    public void destroy() {}

}

 经过学习上面的数据库操作封装,事务界定,在对于如何在数据访问对象上应用DAO模式以及有了更深入的理解了~

 除了上面的内容,这本书里的例子的处理方法还学到了两点:DAO异常的处理方法,以及DIP的使用,见下一个笔记了~~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值