我的项目有一个扣费的业务需要用一个完整的事务封装,而我考虑让数据库连接数尽可能的少,所以用了一个session,并且执行具体操作的时候把这个session传递给数据库操作函数(数据库操作函数封装在另一个类中,util对象是这个类的实例):
Session mysession=HibernateUtil.currentSession();
Transaction tx = null;
try {
tx=mysession.beginTransaction();
System.out.println("Transaction begin!");
                        //用户身份验证,用户的对象信息存储在subscriber对象中
Subscriber subscriber=util.getSubscriberByAuthcode_new(mysession, authcode);
//用户要购买的节目信息存储在program对象中
                        ProgramPrice program = util.getProgramByGUID_new(mysession,GUID);
//给该用户的账户扣除该节目的费用
                        util.deductBalance_new(mysession,subscriber, program);
String result = "0" + "#" + program.getPrice();
//提交这个事务
tx.commit();
System.out.println("Transaction has commited!");
return result;
} catch (Exception e) {
log.error("catch Exception: " + e.getMessage());
if(tx!=null)
tx.rollback();
}finally{
HibernateUtil.closeSession();
}
这样做的话,第一次提交应用正常运行。但是第二次再刷新网页,提示:session is closed! 难道说不可以这样只申请一个session然后传给各个数据库操作函数以保证一个事务就使用一个session? 如果我又想使用这种包含多个数据库操作的事务,又想尽量减少数据库连接数,到底该怎么做?谢谢!

解决方案 »

  1.   

    用过滤器:建一个如下类代替HibernateUtil.
    public class HibernateFilter implements Filter {

    private static ThreadLocal<Session> hibernateHolder = new ThreadLocal();

    private static SessionFactory factory = null; 

    public void destroy() {
    } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
    FilterChain filterChain) throws IOException, ServletException {
    try {
    filterChain.doFilter(servletRequest, servletResponse);
    } finally {
    Session session = (Session)hibernateHolder.get();
    if (session != null) {
    if (session.isOpen()) {
    session.close();
    }
    hibernateHolder.remove();
    }
    }
    } public void init(FilterConfig filterConfig) throws ServletException {
    try {
    Configuration cfg = new Configuration().configure();
    factory = cfg.buildSessionFactory();
    }catch(Exception e) {
    e.printStackTrace();
    throw new ServletException(e);
    }
    }

    public static Session getSession() {
    Session session = (Session)hibernateHolder.get();
    if (session == null) {
    session = factory.openSession();
    hibernateHolder.set(session);
    }
    return session;
    }
    }
    在web.xml中添加:filter>
    <filter-name>HibernateFilter</filter-name>
       <filter-class>xx.xx.xx.util.HibernateFilter</filter-class>
      </filter>
      <filter-mapping>
       <filter-name>HibernateFilter</filter-name>
       <url-pattern>/*</url-pattern>
      </filter-mapping>
      

  2.   

    数据库资源应该采用的是"Open In View",应该采用过滤器.
      

  3.   

    如果我又想使用这种包含多个数据库操作的事务,又想尽量减少数据库连接数,到底该怎么做?谢谢! session的数量与数据库连接数无关的,即使有多个session,对应的数据库连接数与只有一个session对应的数据库连接数是一样的,也就是,你用一个session操作跟用多个session操作数据库是一样的。Session mysession=HibernateUtil.currentSession(); 
    这句代码有问题了,因为currentSession只有一个,而你这样会关闭session,要不你就用filter来判断session有没有关闭,关闭了就打开另外一个,要不,你可以选择使用对于每个线程有一个session,ThreadLocal <Session> hibernateHolder = new ThreadLocal(); 
    我推荐第二种方案。
      

  4.   

    加上spring支持 吧。。 不用管理session 和 事务了
      

  5.   

      你用spring的session来管理事务,这样不就会很简单了么?
      

  6.   

    2楼的高手已经帮你解决他一直不让你的session关闭 在你用尽了所有的JPI的时候在用早doFilter里面判断并关闭session
    这样就避免了延时加载所报的session is cloase()
      

  7.   


    为什么你不是写在destroy里面而是写在doFilter里面,对于session关闭
      

  8.   

    其实有一种解决方案是很好的~
                              Spring  
     他本身就提供了事务的支持~
     LZ可以去试一下o..
      

  9.   

    session的数量与数据库连接数无关的。
    即使有多个session,对应的数据库连接数与只有一个session对应的数据库连接数是一样的,也就是,你用一个session操作跟用多个session操作数据库是一样的。 
    使用Hibernate时,你就不用管数据库连接问题,只管拿过来用就行了!后台都是封装好的!
      

  10.   

    为什么你不是写在destroy里面而是写在doFilter里面,对于session关闭doFilter处理对客服端端的请求和想客服端的回复在请求中一直开着session 当客户端回复时就关闭session
      

  11.   

    楼主,首先我提几点你代码的问题Session mysession=HibernateUtil.currentSession(); ------------------------------1
    Transaction tx = null; 
    try { 
    tx=mysession.beginTransaction(); 
    System.out.println("Transaction begin!"); 
                            //用户身份验证,用户的对象信息存储在subscriber对象中 
    Subscriber subscriber=util.getSubscriberByAuthcode_new(mysession, authcode); 
    //用户要购买的节目信息存储在program对象中 
                            ProgramPrice program = util.getProgramByGUID_new(mysession,GUID); 
    //给该用户的账户扣除该节目的费用 
                            util.deductBalance_new(mysession,subscriber, program); 
    String result = "0" + "#" + program.getPrice(); 
    //提交这个事务 
    tx.commit(); 
    System.out.println("Transaction has commited!"); 
    return result; 
    } catch (Exception e) { 
    log.error("catch Exception: " + e.getMessage()); 
    if(tx!=null) 
    tx.rollback(); 
    }finally{ 
    HibernateUtil.closeSession(); -----------------------------------------2
    } 你自己先看清楚你关闭的是什么session,你把总的session关闭了,当然没有session再去支持你的事务了啊
      

  12.   

    楼主, 使用过spring 吗, 使用spring 监听session  , 一切问题全部帮你搞定
      

  13.   

    顶 , 过滤器中关闭session