论坛首页 Java版 DAO

把SESSION放在DAO层之外的一种解决办法.

浏览 18456 次
该帖已经被评为精华帖
作者 正文
时间:2004-03-06
一、建立一个HIBERNATE的初始化类,注意类中STATIC变量的应用。

package com.yours.hibernate_frame.datamodel;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;

public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
sessionFactory =
new Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException(
"Exception building SessionFactory: " + ex.getMessage(),ex);
}
}

public static final ThreadLocal session = new ThreadLocal();

public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Open a new Session, if this Thread has none yet
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}

public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}


二、在DAO中 HibernateUtil.currentSession()被多次调用,但是由于HibernateUtil使用了静态(static)块,所以sessionFactory只会在该类载入内存中时调用一次,所以不会存在多次调用的情况,也就不会占用太多的资源。在TOMCAT等JSP容器中,sessionFactory是被多用户共享,还是每个用户使用一个sessionFactory,这点我不是很清楚,希望有人能提自已的看法。

JAVA类变量的传递,本质是传递内存地址(原始变量除外),由于HibernateUtil中的session是静态变量,所以可以直接在DAO中调用HibernateUtil.closeSession()关闭,因此在DAO中增加如下一个方法,用来代替在Filter中自动关闭SESSION,这种做法有点象C++的析构函数。

public void closeSession() throws HibernateException {
HibernateUtil.closeSession();
}


package com.yours.admin.dao;
import com.yours.admin.jdo.*;
import com.yours.hibernate_frame.datamodel.HibernateUtil;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.Session;
/**
* <p>Title:USER </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2004</p>
* <p>Company: </p>
* @author 段洪杰
* @version 1.0
*/

public class UserDAOImpl implements UserDAO {
public UserDAOImpl() {
}
/**
* 建立用户
* @param user User
* @throws HibernateException
*/
public void setUser(User user) throws HibernateException{
Session s = HibernateUtil.currentSession();
Transaction tx = null;
try{
tx = s.beginTransaction();
s.save(user);
tx.commit();
}catch(HibernateException he){
if ( tx!=null ){
tx.rollback();
}
throw he;
}
s.flush();
}
/**
* 删除用户
* @param user User
* @throws HibernateException
*/
public void removeUser(User user) throws HibernateException {
Session s = HibernateUtil.currentSession();
Transaction tx = null;
try{
tx = s.beginTransaction();
s.delete(user);
tx.commit();
}catch(HibernateException he){
if ( tx!=null ){
tx.rollback();
}
throw he;
}
s.flush();
}
/**
* 通过Id取得用户
* @param id String
* @throws HibernateException
* @return User
*/
public User getUserById(String id) throws HibernateException {
User user = null;
Session s = HibernateUtil.currentSession();
Transaction tx = null;
try{
tx = s.beginTransaction();
user = (User) s.load( User.class, id );
tx.commit();
}catch(HibernateException he){
if ( tx!=null ){
tx.rollback();
}
throw he;
}
s.flush();
return user;
}
/**
* 关闭Hibernate的session
*/
public void closeSession() throws HibernateException {
HibernateUtil.closeSession();
}

}

----- 希望大家对此贴进行讨论,批评的意见也非常欢迎!
   
时间:2004-03-07
务必给点意见,痛批或支持都可以!
   
0 请登录后投票
时间:2004-03-07
这不就是Hibernate文档里提到那个session locator模式吗?你不妨先说说看,你觉得这么做的好处在哪里?我已经发现了一些问题,不过先听听你自己的想法吧。
   
0 请登录后投票
时间:2004-03-07
gigix 写道
这不就是Hibernate文档里提到那个session locator模式吗?你不妨先说说看,你觉得这么做的好处在哪里?我已经发现了一些问题,不过先听听你自己的想法吧。


我觉在在DAO中关闭SESSION有些勉强.如果多个DAO共一个SESSION,又违反了SESSION用过后要极时关闭的原则.

不把sessionFactory绑定在jndi上,分步调程序时要方便的多.
   
0 请登录后投票
时间:2004-03-07
其实多个DAO共用一个session并不会违反session用过后及时关闭的原则。你可以选择在调用DAO的地方关闭session。比如在一个SLSB中,
dao1.dosomething();
HibernateSession.closeSession();

再举个例子
dao1.dosomething();
dao2.dosomething();
HibernateSession.closeSession();
虽然没有在每个dao方法中关闭session,但也不能称作不及时,因为在第一个方法调用后你还要用到session。所以没有必要太在乎session是否被及时关闭,这不会带来多少性能上的损失。
再比如,在两个dao中加一些语句,除非是很巨大的计算量,不然时间不会很长,至少比访问数据库的时间要小。如果是很大量的计算就应该把这部分分离出去。
   
0 请登录后投票
时间:2004-03-07
sayor SAP的说法很有道理, 我的想法也基本跟他的相似.不过
dao1.dosomething();
dao2.dosomething();
HibernateSession.closeSession();
的做法不太符合一般人的习惯,一般是有打开才有关闭. 所以不如再加一个数据抽象层改为:
dataMode.begin();
dao1.dosomething();
dao2.dosomething();
dataMode.end();

把HibernateSession作为一个单例封装到dataMode中去.
如果以后不再用hibernate了.以后调用DAO时还可以象上面一样的使用.但是由于HibernateSession用的是静态变量,把HibernateSession作为一个单例封装到dataMode中去,又有画蛇添足的感觉.
   
0 请登录后投票
时间:2004-03-07
我的做法是在business service组件上加一个拦截器,每调用一个business service方法之后自动关闭session,这样业务代码就完全不必关系session的开闭、事务的提交/回滚。你觉得这个做法怎么样呢?
   
0 请登录后投票
时间:2004-03-08
gigix 写道
我的做法是在business service组件上加一个拦截器,每调用一个business service方法之后自动关闭session,这样业务代码就完全不必关系session的开闭、事务的提交/回滚。你觉得这个做法怎么样呢?


AOP(面向方面编程)技术,似乎能很好的解决此类问题. 自已编写组件拦截器,好象太麻烦.
   
0 请登录后投票
时间:2004-03-09
dhj1 写道
gigix 写道
我的做法是在business service组件上加一个拦截器,每调用一个business service方法之后自动关闭session,这样业务代码就完全不必关系session的开闭、事务的提交/回滚。你觉得这个做法怎么样呢?


AOP(面向方面编程)技术,似乎能很好的解决此类问题. 自已编写组件拦截器,好象太麻烦.


我说的就是AOP的拦截器,基于AOP-Alliance API,用Spring实现。
   
0 请登录后投票
时间:2004-03-09
用Spring的HibernateTransactionManager类吧,它能够让你写出更漂亮的代码
   
0 请登录后投票
论坛首页 Java版 DAO

跳转论坛:
JavaEye推荐