论坛首页 Java企业应用论坛

讨论:在DAO中对Hibernate的封装

浏览 89133 次
该帖已经被评为精华帖
作者 正文
   发表时间:2003-09-15  
DAO
我在现在的项目中在DAO层中对Hiberante做了如下封装:
用一个HibernateDAO封装一些共同的操作:
package org.skyinn.commons.dao;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;

/**
 * <p>HibernateDAO.</p>
 * 
 * <b>Description:</b>
 * 封装Hibernate的会话、事务的通用操作,以简化相应DAO中的相关操作。
 *
 * 具体实现DAO的示例代码如下:
 * <code><pre>
 * public Account register(final Account account); throws DAOException {
 *     try {
 *         //事务开始
 *         beginTransaction();;
 *         //具体操作
 *         //注册帐号
 *         //getSession();.save(account);;
 *         //结束事务
 *         endTransaction(true);;
 *     } catch (HibernateException he); {
 *         //但发生异常时事务回滚
 *         rollback();;
 *         log.error(he);;
 *         //向调用者抛出异常
 *         throw new DAOException(he);;
 *     } finally {
 *         //结束会话
 *         closeSession();;
 *     } //end try...catch...finally....
 *     return account;
 * } //end register();
 * </pre></code>
 *
 * @author HanQing
 * @version $Revision: 1.3 $ $Date: 2003/08/08 11:44:31 $
 */
public abstract class HibernateDAO implements DAO {

    protected Session session = null;
    protected Transaction transaction = null;
    
    /**
     * Returns the session.
     * @return Session
     */
    public Session getSession(); {
        return session;
    }

    /**
     * Returns the transaction.
     * @return Transaction
     */
    public Transaction getTransaction(); {
        return transaction;
    }

    /**
     * 开始事务。
     *
     * @throws HibernateException 创建事务时的异常
     */
    public void beginTransaction(); throws HibernateException {
        //创建对话
        session = HibernateSessionFactory.openSession();;
        //事务开始
        transaction = session.beginTransaction();;
    }//end beginTransaction();

    /**
     * 结束事务。
     *
     * @param commit 是否提交,但只是读取操作时不需要事务提交,故设为false以提高相应速度
     * @throws HibernateException  结束事务时的Hibernate异常
     * @throws DAOException 结束会话时的DAO异常
     */
    public void endTransaction(boolean commit);
        throws HibernateException,DAOException {
            
        if (commit); {
            transaction.commit();;
        } else {
            // Don't commit the transaction, can be faster for read-only operations
            transaction.rollback();;
        }
        closeSession();;
    }//end endTransaction();

    /**
     * 事务回滚,但事务出错时回滚当前操作。
     *
     * @throws DAOException 回滚中出现的异常
     */
    public void rollback(); throws DAOException{
        if(null != transaction);{
            try {
				transaction.rollback();;
			} catch (HibernateException e); {
                throw new DAOException(e);;
			}
        }
    }//end rollback();

    /**
     * 结束会话。
     *
     * @throws DAOException 结束会话时出现的异常
     */
    public void closeSession(); throws DAOException{
        try {
			session.close();;
		} catch (HibernateException e); {
            throw new DAOException(e);;
		}
    }//end closeSession();
}//EOC HibernateDAO


在具体的DAO中,用有个DAO接口来定义方法(如AccountDAO),
从HiberanteDAO继承并实现AccountDAO,做具体的持久层操作:
package org.skyinn.test.user.dao;

import org.skyinn.commons.dao.DAOException;
import org.skyinn.commons.dao.HibernateDAO;
import org.skyinn.commons.test.user.bean.Account;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Iterator;

/**
 * <p>AccountDAO的Hibernate实现。</p>
 *
 * @version $Revision: 1.6 $ $Date: 2003/08/09 09:41:33 $
 * @author $Author: hanqing $
 */
public final class AccountDAOHibImpl
	extends HibernateDAO
	implements AccountDAO {

	/**日志。*/
	private static Log log = LogFactory.getLog(AccountDAOHibImpl.class);;

	//~ Methods ================================================================

	public Account findAccount(String accountName); throws DAOException{
		Account account = null;
		final String queryString =
			"select account from Account as account "
				+ " where account.accountName = :accountName";
		try {
			//验证帐号
			beginTransaction();;
			final Query query = getSession();.createQuery(queryString);;
			//设置参数
			query.setString("accountName", accountName);;
			//Execute Query...
			final Iterator it = query.iterate();;
			if (it.hasNext();); {
				account = (Account); it.next();;
			}
			//结束事务,false表示不提交
			endTransaction(false);;
		} catch (HibernateException he); {
			//但发生异常时事务回滚
			rollback();;
			log.error(he);;
			throw new DAOException(he);;
		} finally {
			//结束会话
			closeSession();;
		} //end try...catch...finally....
		return account;
	}//end findAccount();

	public Account findAccount(long accountId); {
		return null;
	}

	/**
	 * @see AccountDAO#register
	 */
	public Account register(final Account account); throws DAOException {
		try {
			//事务开始
			beginTransaction();;
			//创建帐号
			session.save(account);;
			//结束事务
			endTransaction(true);;
		} catch (HibernateException he); {
			//但发生异常时事务回滚
			rollback();;
			log.error(he);;
			throw new DAOException(he);;
		} finally {
			//结束会话
			closeSession();;
		} //end try...catch...finally....
		return account;
	} //end register();

	/**
	 * @see AccountDAO#login
	 */
	public Account login(final Account account); throws DAOException {
		Account _account = null;
		final String queryString =
			"select account from Account as account "
				+ " where account.accountName = :accountName"
				+ " and account.password = :password";
		try {
			//验证帐号
			beginTransaction();;
			final Query query = getSession();.createQuery(queryString);;
			//设置参数
			query.setString("accountName", account.getAccountName(););;
			query.setString("password", account.getPassword(););;
			//Execute Query...
			final Iterator it = query.iterate();;
			if (it.hasNext();); {
				_account = (Account); it.next();;
			}
			//结束事务,false表示不提交
			endTransaction(false);;
		} catch (HibernateException he); {
			//但发生异常时事务回滚
			rollback();;
			log.error(he);;
			throw new DAOException(he);;
		} finally {
			//结束会话
			closeSession();;
		} //end try...catch...finally....
		return _account;
	} //end login();
} //EOC AccountDAOHibImpl


在业务逻辑层中通过DAO工厂来取这些DAO并执行之,这里有几个问题不是很确信:
1:在DAO中每个方法都需要创建一个session和tx,这在一般应用中问题不大,我考虑的是但业务逻辑层有如果需要调用多个DAO的方法时,岂不需要多个session和tx,这样其实也就美了事务的的操作了,所以想请教有没有好的解决方案;)

2:昨天才想到,其实对对象的CRUD来说,CUD方法非常的类似,
而通过Hiberante一封装,变得更抽象了,比如CREATE方法都可以抽象成:
...
//事务开始
beginTransaction();;
//创建对象
session.save(obj);;
//结束事务
endTransaction(true);;
...


但还没做更进一步的研究和试验,不知道是否可以实现,如果可以的话,把这三个方法再往上一抽,剩下的DAO实现中就只要完成一些查询等就够了,HOHO,哪岂不很爽》?呵呵:)回头试试去:)

嗯,还有很多问题,大家一起来讨论下:)
   发表时间:2003-09-15  
DAO层的类层次结构:
0 请登录后投票
   发表时间:2003-09-15  
换一个全一点的:)
0 请登录后投票
   发表时间:2003-09-16  
我其实不是很同意你的封装方法,当然意见可以有分歧,不过你的思路很不错,所以放进精华文章。

面向对象应该根据业务逻辑来封装对象,而不是按照使用的API来封装,我的面向对象的设计思路都写在  《面向对象的思维方法》

http://hibernate.fankai.com/viewtopic.php?t=38

里面。我考虑封装的出发点和你不太一样的。


引用
1:在DAO中每个方法都需要创建一个session和tx,这在一般应用中问题不大,我考虑的是但业务逻辑层有如果需要调用多个DAO的方法时,岂不需要多个session和tx,这样其实也就美了事务的的操作了,所以想请教有没有好的解决方案;)


可以用ThreadLocal 来管理Session,论坛有这方面的几个帖子,你用论坛搜索功能搜一下。
0 请登录后投票
   发表时间:2003-09-16  
TO:robbin

本来就是拿来讨论的,呵呵,
现在还没研究过TreadLocal,回头看看去

to:cxhz_cn
用DAO可以对业务逻辑称屏蔽具体的持久层实现,
比如AccountDAO,这只是个接口,在业务逻辑中只使用这个接口,而具体的实现则有DAO工厂提供,所以但你换一种持久层实现的时候非常方便,我曾经用配置文件来做过,可以在程序运行环境下更换不同的DAO实现以,可以访问不同的数据源,呵呵:)

BTW:看你的ID是不是杭州的?
0 请登录后投票
   发表时间:2003-09-19  
用DAO封装Hibernate的操作是个很不错的设计。由于在大型的架构里,DAO作为业务处理的原子操作层,在其之上,我们需要一层综合的业务处理层来完成高级的业务方法。而这些高级业务操作一般都采用SessionBean来实现,所以建议把你的DAO里的事务处理放到这些高级业务方法里来完成。举个例子:

很多场合我们需要建立客户资料。而往往在设计的时候就把客户资料做成了客户基本资料、客户的扩展资料等不同的对象。这些对象的操作都是封装在DAO里的。有CustomerBaseDAO、LinkmanDAO。这样如果我们有一个高级业务方法:创建客户。则该业务方法就可以采用两种事务处理:

1、容器管理的事务
2、JTA

两种方式做起来都比你把事务处理放到每个DAO里来得好得多。这样系统的层次结构也十分的清楚。
0 请登录后投票
   发表时间:2003-09-19  
tks tuskrabbit:)
0 请登录后投票
   发表时间:2003-10-06  
robbin 写道
我其实不是很同意你的封装方法,当然意见可以有分歧,不过你的思路很不错,所以放进精华文章。

面向对象应该根据业务逻辑来封装对象,而不是按照使用的API来封装,我的面向对象的设计思路都写在  《面向对象的思维方法》

http://hibernate.fankai.com/viewtopic.php?t=38

里面。我考虑封装的出发点和你不太一样的。


引用
1:在DAO中每个方法都需要创建一个session和tx,这在一般应用中问题不大,我考虑的是但业务逻辑层有如果需要调用多个DAO的方法时,岂不需要多个session和tx,这样其实也就美了事务的的操作了,所以想请教有没有好的解决方案;)


可以用ThreadLocal 来管理Session,论坛有这方面的几个帖子,你用论坛搜索功能搜一下。


我没看过hibernate源码,但感觉hibernate已经封装了domain store,完成了底层dao的持久化,所以完全可以把映射类直接参与业务逻辑transparently,而不必再次把hibernate类封装在dao模式中,当然会有诸如session.update()等难以避免的操作。我才接触hibernate,望多多指教。
0 请登录后投票
   发表时间:2003-10-07  
l_yeung 写道
AOP 也是不错的选择

或许IoC是更加不错的选择
0 请登录后投票
   发表时间:2003-10-09  
大家还有别的更好的设计没有呢,拿出来讨论一下可好
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics