锁定老帖子 主题:讨论:在DAO中对Hibernate的封装
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2003-10-13
引用 如果JDO2.0规范能够让Gavin King 感到满意的话,那么Hibernate兼容JDO是势在必行的,所以大家还是尽量用DAO吧,以免以后API再改一次
但是我认为hibernate内部已经实现小粒度的dao层,就不必再在hibernate外部包层dao了,这才是o/r mapping的本意,为防止hibernate的api变动(这是Gavin King 的问题),可以把逻辑封装在大一点的业务块中 |
|
返回顶楼 | |
发表时间:2003-10-13
Haiqing 写道 引用 如果JDO2.0规范能够让Gavin King 感到满意的话,那么Hibernate兼容JDO是势在必行的,所以大家还是尽量用DAO吧,以免以后API再改一次
但是我认为hibernate内部已经实现小粒度的dao层,就不必再在hibernate外部包层dao了,这才是o/r mapping的本意,为防止hibernate的api变动(这是Gavin King 的问题),可以把逻辑封装在大一点的业务块中 可否说的更加直白些?怎么在开发中使用hibernate |
|
返回顶楼 | |
发表时间:2003-10-13
怎样做比较好?每个持久类设计一个DAO还是一堆持久类合起来设计一个DAO?
|
|
返回顶楼 | |
发表时间:2003-10-13
muziq 写道 怎样做比较好?每个持久类设计一个DAO还是一堆持久类合起来设计一个DAO?
看你的业务需求了,从业务流程来推,不要盯着持久类,就给它加上CRUD,这不是做设计。 |
|
返回顶楼 | |
发表时间:2003-10-13
robbin说的不错,那是不是就按照业务相近的操作合到一个DAO里面?
|
|
返回顶楼 | |
发表时间:2003-10-13
贴一段roller中的对Hibernate的封装,再使用中,其DAO层中一个
PersistentStrategy(是接口)变量, 如果是hibernate实现,则其为HibernateStrategy(DAO持久层实现类), 如果不用Hibernate,则改用其他的实现类 在DAO中各种方法就是通过调用这个类来实现各种操作, 比如CRUD基本就全部封装掉了,对于查询,他的query(hql,object[],type[])也足够用了, 其他可以通过getSession()来实现特殊的访问操作, 所以,现在的焦点是如何设计业务层对DAO的访问,而不需要太关心DAO之下的实现了,即使以后Hibernate升级或者甚至你更换了DAO的实现类,对你的业务逻辑层是无需更改的,而如果在你的业务逻辑层中获取Session并传递的化,就将业务逻辑和DAO绑的太紧了 roller中的这个已经很不错了:) //在我的实现中,ThreadLocalSession是分开的,在HibernateDAO中定义了一些公用的方法,而具体的实现类则继承自HibernateDAO并实现其接口, 目前来说基本满足应用的需求:) /* * Created on Mar 7, 2003 */ package org.roller.business.hibernate; import net.sf.hibernate.HibernateException; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.type.Type; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.roller.RollerException; import org.roller.model.PersistenceStrategy; import org.roller.pojos.PersistentObject; import java.util.List; /////////////////////////////////////////////////////////////////////////////// /** * Reusable Hibernate implementations of CRUD operations. * @author David M Johnson */ public class HibernateStrategy implements PersistenceStrategy { private SessionFactory mSessionFactory; private ThreadLocal mSessionTLS = new ThreadLocal();; private static Log mLogger = LogFactory.getFactory();.getInstance(HibernateStrategy.class);; //------------------------------------------------------------------------- public HibernateStrategy(SessionFactory factory); throws RollerException { mSessionFactory = factory; } //------------------------------------------------------------------------- private boolean isAvailable(); { return mSessionTLS.get();!=null; } //------------------------------------------------------------------------- /** get session for current thread */ protected Session getSession(); { Session ses = (Session);mSessionTLS.get();; if ( ses == null ); { try { ses = mSessionFactory.openSession();; mLogger.debug(Messages.getString( "HibernateStrategy.openedSession");+ses);; } catch (HibernateException e); { mLogger.error(Messages.getString( "HibernateStrategy.exceptionOpeningSession"););; throw new RuntimeException();; } mSessionTLS.set(ses);; } return ses; } //------------------------------------------------------------------------- /** remove session from thread, flush it and close it. */ public void release(); throws RollerException { Session ses = (Session);mSessionTLS.get();; if ( null == ses ); return; // there is no session to release mSessionTLS.set(null);; // sets thread's session to null try { ses.flush();; } catch (HibernateException he); { mLogger.debug(Messages.getString( "HibernateStrategy.exceptionClosing");,he);; } try { if ( ses.isOpen(); ); ses.close();; } catch (HibernateException he); { mLogger.debug(Messages.getString( "HibernateStrategy.exceptionClosing");,he);; } mLogger.debug("HibernateStrategy.closedSession"+ses);; } //------------------------------------------------------------------------- /** * Removes object using an existing transaction. * @param clazz Class of object to remove. * @param id Id of object to remove. * @throws RollerException Error deleting object. */ public void removePersistentObject( String id, Class clazz ); throws RollerException { if ( id == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidId"););; } if ( clazz == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidClass"););; } // Create persistent instance and delete it Object obj; try { obj = getSession();.load(clazz,id);; getSession();.delete(obj);; getSession();.flush();; } catch (HibernateException e); { String msg = Messages.formatString( "HibernateStrategy.exceptionRemoving",id,clazz.getName(););; mLogger.error(msg);; // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; throw new RollerException(e);; } } //------------------------------------------------------------------------- /** * Retrieve object, begins and ends its own transaction. * @param clazz Class of object to retrieve. * @param id Id of object to retrieve. * @return Object Object retrieved. * @throws RollerException Error retrieving object. */ public PersistentObject retrievePersistentObject(String id, Class clazz); throws RollerException { if ( id == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidId"););; } if ( clazz == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidClass"););; } Object obj = null; Session ses = getSession();; try { obj = (PersistentObject);ses.load( clazz, id );; } catch (HibernateException e); { String msg = Messages.formatString( "HibernateStrategy.exceptionRetrieving",id,clazz.getName(););; mLogger.debug(msg,e);; // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; } return (PersistentObject);obj; } //------------------------------------------------------------------------- /** * Store object using an existing transaction. * @param obj * @throws RollerException */ public PersistentObject storePersistentObject(PersistentObject obj); throws RollerException { if ( obj == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullPassedIn"););; } Session ses = getSession();; try { // Dave: I tried using ses.saveOrUpdate(); here, but it did not work. if ( obj.getId(); == null || obj.getId();.trim();.equals(""); ); { // Object has never been written to database, so save it. // This makes obj into a persistent instance. ses.save(obj);; } if ( !ses.contains(obj); ); { // Object has been written to database, but instance passed in // is not a persistent instance, so must be loaded into session. PersistentObject vo = (PersistentObject);ses.load(obj.getClass();,obj.getId(););; vo.setData(obj);; obj = vo; } // performance killer? -> ses.flush();; } catch (HibernateException e); { String msg = Messages.formatString( "HibernateStrategy.exceptionStoring",obj.getId(););; mLogger.error(msg);; // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; throw new RollerException(msg,e);; } return obj; } //------------------------------------------------------------------------- public List query( String query, Object[] args, Object[] types); throws RollerException { return query(query, args, (Type[]);types);; } //------------------------------------------------------------------------- public List query( String query, Object[] args, Type[] types ); throws RollerException { if ( query == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidQuery"););; } if ( args == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidArgArray"););; } if ( types == null ); { throw new RollerException(Messages.getString( "HibernateStrategy.nullNotValidArrayType"););; } try { if (query.indexOf("$"); > -1); { query = query.replaceAll("\\$\\d+", "\\?");; } return getSession();.find(query,args,types);; } catch (HibernateException e); { String msg = Messages.getString("HibernateStrategy.duringQuery");; mLogger.error(msg,e);; // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; throw new RollerException(msg,e);; } } //------------------------------------------------------------------------- public List query( String query ); throws RollerException { try { if (query.indexOf("$"); > -1); { query = query.replaceAll("\\$\\d+", "\\?");; } return getSession();.find(query);; } catch (HibernateException e); { String msg = Messages.getString("HibernateStrategy.duringQuery");; mLogger.error(msg,e);; // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; throw new RollerException(msg,e);; } } //------------------------------------------------------------------------- public void commit(); throws RollerException { try { if (isAvailable();); getSession();.flush();; } catch (HibernateException he); { // Gavin: "make sure you never catch + handle an exception and // then keep using the session (ObjectNotFoundException included!);" release();; throw new RollerException(he);; } } //------------------------------------------------------------------------- public void rollback(); throws RollerException { } } |
|
返回顶楼 | |
发表时间:2003-10-13
引用 roller中的这个已经很不错了:)
在那里可以得到roller的完整代码? |
|
返回顶楼 | |
发表时间:2003-10-13
|
|
返回顶楼 | |
发表时间:2003-10-14
tuskrabbit, 写的很好
|
|
返回顶楼 | |
发表时间:2003-10-15
我也同意 tuskrabbit 的说法。
我在程序里也是使用 DAO 模式来封装数据库操作的,这两天仔细的看了这里的文章,也 修改了我的 DAO 的设计,把我的思路和大家共享下: 先介绍下代码(为了方便理解,我把 对参数的检查和异常处理 的相关部分去掉了): 帐户类,一个 PO: Account { String username; String password; } DAO 接口 interface AccountDAO { public void addAccount( Account account );; public void updateAccount( Account account );; public void removeAccount( String username );; public Account findByUsername( String username );; } AccountDAO 的实现 class AccountDAOHibernate { public void addAccount( Account account ); { HibernateUtil.add( account );; } public void updateAccount( Account account ); { HibernateUtil.update( account );; } public void removeAccount( String username ); { HibernateUtil.remove( Account.class, username );; } public Account findByUsername( String username ); { account = (Account); HibernateUtil.findById( Account.class, username );; } } HibernateUtil 是对 Hibernate 的基本 crud 操作的封装 我参考了 poll 的实现 class HibernateUtil { public static void add( Object object ); throws HibernateException { Session s = HibernateSessionFactory.currentSession();; s.save( object );; s.flush();; } public static void update( Object object ); throws HibernateException { Session s = HibernateSessionFactory.currentSession();; s.saveOrUpdate( object );; s.flush();; } public static void remove(Class clazz, String id); throws HibernateException { Session s = HibernateSessionFactory.currentSession();; Object object = s.load(clazz, id);; s.delete( object );; s.flush();; } public static Object findById( Class clazz, String id ); throws HibernateException { Object obj = null; Session s = HibernateSessionFactory.currentSession();; obj = s.load( clazz, id );; s.flush();; return obj; } } HibernateSessionFactory 使用 ThreadLocal 做 Session 管理,实现和 hibernate 网站上的一样 参考:http://hibernate.bluemars.net/42.html class HibernateSessionFactory { public static final ThreadLocal session = new ThreadLocal();; private static SessionFactory sessionFactory; private static Configuration conf; public static void init(); { conf = new Configuration();.configure();; sessionFactory = conf.buildSessionFactory();; } public static Session currentSession(); { Session s = (Session); session.get();; if (s == null); { s = sessionFactory.openSession();; session.set(s);; } return s; } public static void closeSession(); { Session s = (Session); session.get();; session.set(null);; if (s != null); s.close();; } } 说明: 1.DAO 模式的目的是为了把数据库操作封装在 DAO 层下 Session 应该被封装在 DAO 层里 2.何时关闭 Session: 由于使用了 ThreadLocal 来管理 Session,我没有在 DAO 的方法里关闭 Session 这样,同一个 thraed 里的各个 DAO 方法可以访问到 同一个 Session,可以利用 Hibernate 的 lazy load 功能。 在 web 应用程序里可以使用 HibernateFilter 来处理 Session 的关闭: 参考:http://hibernate.bluemars.net/110.html public class HibernateFilter implements Filter { public void init(FilterConfig filterConfig); throws ServletException { HibernateSessionFactory.init();; } public void doFilter( ... ); { try{ filterChain.doFilter( servletRequest, servletResponse );; } finally { try { HibernateSessionFactory.closeSession();; } catch (HibernateException e); { log.error( "Error closing current session " + e );; } } } public void destroy(); { } } 3.对 Transaction 的处理 不在 DAO 层处理 Transaction 如果确实需要 Transaction ,在上一层,比如业务层里的 Session Bean 里来做。 |
|
返回顶楼 | |