锁定老帖子 主题:『提问』关闭session的老问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2004-11-06
我采用SLSB-->DAO-->Hibernate-->DB开发我的持久层,DAO中封装的方法是对PO的CURD操作,SLSB负责具体的业务逻辑。 我最初的期望是由DAO完成所有的底层操作,包括异常也全部以DAOException抛出,由于不想在SLSB中出现Hiberante代码,我把session的开、关,全部放在了DAO的方法操作中,并采用threadlocal方式管理,事务使用容器管理。 我的这种做法在单个DAO方法操作单个线程session时没有问题,但是当我在DAO方法中,希望调用其他的DAO操作时,由于每个操作都关闭本线程的session,会导致最初的DAO方法还没有执行完毕时,线程就被关闭了从而报错。 这个问题考虑良久,现在我处在两种解决方案的矛盾中:方法一:把session的关闭放到SLSB的业务方法中,在执行完DAO操作后再关闭,但是这样似乎DAO的封装就不再完整,记得robbin说过SLSB中不应出现Hibernate的代码;方法二:在DAO方法中不使用threadlocal,每个方法都开关自己的session,这样我已经可以正常实现我的所有操作了,但是看了以前的帖子,这似乎也不是个好的解决方案。 想了半天,没有一个好的结果,我把我的代码贴上来,可能我对threadLocal的理解不太正确,如果代码中的使用不对,请指正,谢谢! 配置文件: 这是一个目录类,在PO中我只定义了一个many-to-one的parentCategory属性,也就是说只有单向的关联。 ... public class CategoryDaoHibernateImpl implements CategoryDao { ... //删除一个目录方法,执行时需要查找该目录的所有子目录并先把子目录删掉 public boolean delCategory(Category category); throws DaoException{ Session session = null; boolean returnValue = false; try { session = HibernateUtil.currentSession();; } catch (InfrastructureException ex); { throw new DaoException("CategoryDao的delCategory方法发生InfrastructureException",ex);; } try { ArrayList childCate = (ArrayList);this.getChildCategory(category);; if(childCate!=null);{ for(int i=0;i<childCate.size();;i++);{ this.delCategory((Category);childCate.get(i););; } } session.delete(category);; session.flush();; returnValue = true; } catch (HibernateException ex); { throw new DaoException("CategoryDao的delCategory方法发生HibernateException",ex);; } finally{ try { HibernateUtil.closeSession();; } catch (InfrastructureException ex); { throw new DaoException("CategoryDao的delCategory方法发生InfrastructureException",ex);; } //取得子目录方法,得到该目录下的所有子目录 public Collection getChildCategory(Category parentCategory);throws DaoException{ Session session = null; ArrayList category = null; try { session = HibernateUtil.currentSession();; } catch (InfrastructureException ex); { throw new DaoException("CategoryDao的getChildCategory方法发生InfrastructureException",ex);; } try { Query q = session.createQuery("select from Category as category where category.parentCategory=:parentCategory");; q.setParameter("parentCategory",parentCategory);; category = (ArrayList);q.list();; if(category.size();==0);{ System.out.println("没有找到与parentCategory: id ="+parentCategory.getId();+"对应的区域对象");; return null; } else{System.out.println("category.size= "+category.size(););;} session.flush();; } catch (HibernateException ex); { throw new DaoException("CategoryDao的getChildCategory方法发生HibernateException",ex);; } finally{ try { HibernateUtil.closeSession();; System.out.println("改改后的getChildCategory的finally");; } catch (InfrastructureException ex); { throw new DaoException("CategoryDao的getChildCategory方法发生InfrastructureException",ex);; } } return category; } EJB中的调用就是一句: returnValue = categoryDao.delCategory(category);; 错误提示信息: 11:21:14,359 ERROR SessionImpl:2343 - Could not synchronize database state with session net.sf.hibernate.HibernateException: Session is closed 你的分析: 出错信息很明显,就是我在查找子目录的方法中关掉了删除目录方法中的session,只是这个问题到底应该怎么样解决才是比较完美的呢,谢谢 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-11-08
我的做法是在所有的方法里都不关闭,
最后在filter里统一关闭 |
|
返回顶楼 | |
发表时间:2004-11-08
yangstarfly 写道 我的做法是在所有的方法里都不关闭,
最后在filter里统一关闭 你指的是servlet的filter 吗?我的DAO是提供给EJB使用的,我希望能在DAO这一层本身完全控制Hibernate,退一步在EJB中统一关闭也可以吧,在EJB中是否也可以实现对针对具体方法的Filter? Filter模式能不能实现在一个DAO或者EJB中?对Filter不太了解的说 |
|
返回顶楼 | |
发表时间:2004-11-08
在看了你的问题后,和你不同的地方主要有两点。
1。ThreadLocal 在使用ThreadLocal上,我们的做法也是和你的一样,但是名字不叫HibernateUtil, 而是PersistenceUtil. 这样的话在业务逻辑里调用PersistenceUtil也没有违反"在业务逻辑中不出现Hiternate的code"定律 2。Transaction 管理Transaction是在SLSB或者业务对象里面管理。以下的事件是在业务逻辑实现的,DAO里只是从ThreadLocal里去取到一个session. begin transaction commit rollback session close public CompanyModel addCompany(CompanyModel model);{ try{ PersistenceUtil.beginTransaction();; CompanyModel result = (CompanyModel);companyDAO.create(model);; PersistenceUtil.commitTransaction();; return result; }catch(PersistenceException pe);{ PersistenceUtil.rollbackTransaction();; throw new BusinessException(pe);; }finally{ PersistenceUtil.closeSession();; } } |
|
返回顶楼 | |
发表时间:2004-11-08
上一篇文章里的code是SLSB里的代码。
以下是DAO里的代码 public Object create(Object model); throws DAOException{ try{ Session s = HibernateUtil.currentSession();; s.save( model );; }catch(HibernateException he);{ throw new DAOException(he);; } return model; } |
|
返回顶楼 | |
发表时间:2004-11-08
谢谢你的回复,你们这样的实现应该是比较清晰合理的,很有参考价值,谢谢:)
不知能否贴出PersistenceUtil的代码,想看看你们对Transaction的封装,因为我对事务的处理仅仅是在EJB部署描述里申明为“Required”,然后在catch到异常的时候调用 sessionContext.setRollbackOnly(),这样做不知道有没有隐患 |
|
返回顶楼 | |
发表时间:2004-11-09
以下代码供参考
PersistenceUtil.java public class PersistenceUtil { private static Log log = LogFactory.getLog(PersistenceUtil.class);; public static Session currentSession(); throws PersistenceException { try { return HibernateUtil.currentSession();; } catch (HibernateException he); { throw new PersistenceException(he);; } } public static void closeSession(); throws PersistenceException { try { HibernateUtil.closeSession();; } catch (HibernateException he); { throw new PersistenceException(he);; } } public static void beginTransaction(); throws PersistenceException { try { HibernateUtil.beginTransaction();; } catch (HibernateException he); { throw new PersistenceException(he);; } } public static void commitTransaction(); throws PersistenceException { try { HibernateUtil.commitTransaction();; } catch (HibernateException he); { throw new PersistenceException(he);; } } public static void rollbackTransaction(); throws PersistenceException { try { HibernateUtil.rollbackTransaction();; } catch (HibernateException he); { throw new PersistenceException(he);; } } } HibernateUtil.java public class HibernateUtil { private static Log log = LogFactory.getLog(HibernateUtil.class);; private static SessionFactory sessionFactory; private static final ThreadLocal threadSession = new ThreadLocal();; private static final ThreadLocal threadTransaction = new ThreadLocal();; public static SessionFactory getSessionFactory();{ if(sessionFactory == null);{ try { // Create the SessionFactory sessionFactory = new Configuration();.configure();.buildSessionFactory();; } catch (HibernateException ex); { ex.printStackTrace();; throw new RuntimeException("Configuration problem: " + ex.getMessage();, ex);; } } return sessionFactory; } public static Session currentSession(); throws HibernateException { Session s = (Session); threadSession.get();; // Open a new Session, if this Thread has none yet if (s == null); { s = getSessionFactory();.openSession();; log.debug("###Opening new Session for this thread:" + s);; threadSession.set(s);; }else{ log.debug("###Session was existed:" + s);; } return s; } public static void closeSession(); throws HibernateException { Session s = (Session); threadSession.get();; threadSession.set(null);; if (s != null);{ log.debug("###Closing Session of this thread. " + s);; s.close();; } } public static void beginTransaction(); throws HibernateException { Transaction tx = (Transaction); threadTransaction.get();; try { if (tx == null); { tx = currentSession();.beginTransaction();; log.debug("###Starting new database transaction in this thread:" + tx);; threadTransaction.set(tx);; }else{ log.debug("###Tx was existed:" + tx);; } } catch (HibernateException ex); { throw ex; } } public static void commitTransaction(); throws HibernateException { 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 (HibernateException ex); { rollbackTransaction();; throw ex; } } public static void rollbackTransaction(); throws HibernateException { 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();; } } catch (HibernateException ex); { throw ex; } finally { closeSession();; } } } |
|
返回顶楼 | |
发表时间:2004-11-09
多谢bean,这代码写的比我漂亮多了,学习中:)
|
|
返回顶楼 | |
发表时间:2004-11-09
又翻出了很早以前看过的帖子:
http://www.hibernate.org.cn/56.html 也是robbin的大作,他一再强调用容器管理事务是不不需要写Transaction代码的,只要在部署描述里面配置,我现在用的就是这种方法,不过bean你们用的方法好像是使用了JTA,请问你们用的应该是BMT是吗? |
|
返回顶楼 | |
发表时间:2004-11-09
我们在使用Hibernate的这个项目里,没有用EJB.
我的那段代码addCompany(CompanyModel model)。。。是在业务逻辑类里面实现的。 前面的有一篇文章里我写的是说在SLSB里写的。是我说错了,对不起! |
|
返回顶楼 | |