论坛首页 Java版 DAO

讨论:在DAO中对Hibernate的封装

浏览 60151 次
该帖已经被评为精华帖
作者 正文
最后更新时间:2003-09-15
我在现在的项目中在DAO层中对Hiberante做了如下封装:
用一个HibernateDAO封装一些共同的操作:
[code:1]
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
[/code:1]

在具体的DAO中,用有个DAO接口来定义方法(如AccountDAO),
从HiberanteDAO继承并实现AccountDAO,做具体的持久层操作:
[code:1]
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
[/code:1]

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

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

但还没做更进一步的研究和试验,不知道是否可以实现,如果可以的话,把这三个方法再往上一抽,剩下的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版 DAO

跳转论坛:
JavaEye推荐