论坛首页 Java企业应用论坛

Hibernate3线程绑定session的配置(不用Spring),何时关闭sesssion?

浏览 9220 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (3) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-10-29   最后修改:2008-11-05
在用hibernate3的过程中(先说明下,项目中没有用到Spring),出现过1次由于Oracle数据库无法分发连接造成项目不能正常运行的错误。但当时数据库的设置的可连接数是500,而且当时我用plus查询v$session时数量只有93个。之后查看日志文件及分析项目组各人当时手头的工作时,发现有可能是因为有人在拉报表时,造成数据库瞬间摒死。

由于平时数据库的连接一直很稳定,对于关闭session的问题也是凭以往的经验而行。但这次我们的疏忽造成了不良影响,因此,我自己总结了下对关闭session问题的想法和疑惑,有不对的地方和疑点,希望有心人多多指教,不盛感激!

我的理解,线程绑定是对Hibernate中线程进行有效管理的一种方式。由SessionFactory的多线程性,若想实现多线程共享一个Session实例是不行的。而解决办法可以为每个线程放一个Session的副本,并由每个线程自己维护这个Session,包括获得、使用、销毁。这样,可以实现Session的线程内共享。

在我看来,Session的线程内共享,是指,Session做为一种持久化的工具,可以用来将其中的各种对象与数据库之间进行交互。所以,直到未被销毁前,Session可以用来做各种各样的操作,如查询、保存、修改、删除等。但任何数据库都有最大连接限制,所以,当完成对数据库的操作后,必须断开与数据库的连接。然而,session只要不销毁,它与数据库的连接将一直存在,并随着用户操作的增加,连接数将不断增加。

因此,这里有个矛盾:既要实现session的共享,也即只用一个session来完成不同的操作,又要尽量使每个操作在完成后断开连接,也即关闭session。

对此,很多人在编程时可能都是这样做的:

1.每完成一个操作,都关闭当前线程中的Session,当再次需要时,由线程再次从SessionFactory中去获取。这样,可以保证所有的连接都能被释放,不会造成数据库连接次数的爆满。但这样做的话,线程内的Session一获得,一个操作后就销毁了,下一个操作还要到SessionFactory中去取,线程内共享Session还有什么意义?。

2.所有操作均不关闭Session,而是在每个请求结束后统一关闭。这样,很好地实现了线程内Session的共享。但这样的话,每个用户占用的连接数将大大增加,用户数量很多的话,很可能在某个时刻连接数没有得到及时释放,造成数据库连接爆了。打个比方,有个循环,内中有个未关闭Session的方法。如果想在这个循环内共享Session,在循环后再关闭这个Session,就很可能造成连接数在瞬间爆增(尤其在循环很大的情况下)。

有些人可能这样想:我在一个请求(jsp页面或servlet)的最后一个方法中关闭Session不就行了吗?然而,在当前页面中,这个方法可能是最后用到的,但到了另外一个页面中,说不定是第一个用到的。假如每个页面都在最后一个使用的方法上关闭Session,也许在XX个页面之后,所有的方法都关闭Session了。
   发表时间:2008-11-03  
刚学Hibernate.正郁闷到底应该何时关闭Session.
LZ,有没有好的建议啊?
0 请登录后投票
   发表时间:2008-11-04  
jiangli 写道
在用hibernate3的过程中,出现过1次由于Oracle数据库无法分发连接造成项目不能正常运行的错误。但当时数据库的设置的可连接数是500,而且当时我用plus查询v$session时数量只有93个。之后查看日志文件及分析项目组各人当时手头的工作时,发现有可能是因为有人在拉报表时,造成数据库瞬间摒死。

由于平时数据库的连接一直很稳定,对于关闭session的问题也是凭以往的经验而行。但这次我们的疏忽造成了不良影响,因此,我自己总结了下对关闭session问题的想法和疑惑,有不对的地方和疑点,希望有心人多多指教,不盛感激!

我的理解,线程绑定是对Hibernate中线程进行有效管理的一种方式。由SessionFactory的多线程性,若想实现多线程共享一个Session实例是不行的。而解决办法可以为每个线程放一个Session的副本,并由每个线程自己维护这个Session,包括获得、使用、销毁。这样,可以实现Session的线程内共享。


session不应该多线程,那将是灾难。想想,因为一级缓存的缘故,有可能引起数据脏读,而且session不释放数据库链接,也会造成大量的资源浪费。session缓存对象过多,也是浪费内存,还得手动去清理?hibernate设计session的目的就是让我们用了就close。实际上,每个线程的session都是不同的。


在我看来,的Session的线程内共享,是指,Session做为一种持久化的工具,可以用来将其中的各种对象与数据库之间进行交互。所以,直到未被销毁前,Session可以用来做各种各样的操作,如查询、保存、修改、删除等。但任何数据库都有最大连接限制,所以,当完成对数据库的操作后,必须断开与数据库的连接。然而,session只要不销毁,它与数据库的连接将一直存在,并随着用户操作的增加,连接数将不断增加


非也。。。session只有当你真正需要访问数据库的时候才获取链接,然后在事务提交过后释放链接(Spring中是这样实现的)。也就是说,当你Session s=SessionFactory.openSession();的时候session并没有获得数据库链接,甚至在Query q=s.createQuery(hql)时都没有获得连接,真正获得连接是在q.list()的时候。当然还有其他时候。。。。


因此,这里有个矛盾:既要实现session的共享,也即只用一个session来完成不同的操作,又要尽量使每个操作在完成后断开连接,也即关闭session。

对此,很多人在编程时可能都是这样做的:

1.每完成一个操作,都关闭当前线程中的Session,当再次需要时,由线程再次从SessionFactory中去获取。这样,可以保证所有的连接都能被释放,不会造成数据库连接次数的爆满。但这样做的话,线程内的Session一获得,一个操作后就销毁了,下一个操作还要到SessionFactory中去取,线程内共享Session还有什么意义?。

2.所有操作均不关闭Session,而是在每个请求结束后统一关闭。这样,很好地实现了线程内Session的共享。但这样的话,每个用户占用的连接数将大大增加,用户数量很多的话,很可能在某个时刻连接数没有得到及时释放,造成数据库连接爆了。打个比方,有个循环,内中有个未关闭Session的方法。如果想在这个循环内共享Session,在循环后再关闭这个Session,就很可能造成连接数在瞬间爆增(尤其在循环很大的情况下)。

有些人可能这样想:我在一个请求(jsp页面或servlet)的最后一个方法中关闭Session不就行了吗?然而,在当前页面中,这个方法可能是最后用到的,但到了另外一个页面中,说不定是第一个用到的。假如每个页面都在最后一个使用的方法上关闭Session,也许在XX个页面之后,所有的方法都关闭Session了。

0 请登录后投票
   发表时间:2008-11-04  
我说的都是在spring管理下的SESSION,因为我用的就是Spring。所以在Spring下,只要你记得提交事务,就没有问题
如果是纯hibernate,想在一个存活实际很长的线程中共享session,那么是否考虑一下当不需要连接的时候session.disconnect()(好像有这个方法,虽然不推荐使用了)。此时session的一级缓存还在,要再次连接数据库的时候就重新获得session。如何?

或者,用完了session就直接close,然后利用二级缓存来解决数据共享


0 请登录后投票
   发表时间:2008-11-04  
如果只用hibernate,就在finally块中关闭,仅此而已。
0 请登录后投票
   发表时间:2008-11-04   最后修改:2008-11-04
你可以看看OpenSessionInViewFilter,它和一次完整的请求过程对应的线程相绑定
1 请登录后投票
   发表时间:2008-11-04  
taupo 写道
jiangli 写道
在用hibernate3的过程中,出现过1次由于Oracle数据库无法分发连接造成项目不能正常运行的错误。但当时数据库的设置的可连接数是500,而且当时我用plus查询v$session时数量只有93个。之后查看日志文件及分析项目组各人当时手头的工作时,发现有可能是因为有人在拉报表时,造成数据库瞬间摒死。

由于平时数据库的连接一直很稳定,对于关闭session的问题也是凭以往的经验而行。但这次我们的疏忽造成了不良影响,因此,我自己总结了下对关闭session问题的想法和疑惑,有不对的地方和疑点,希望有心人多多指教,不盛感激!

我的理解,线程绑定是对Hibernate中线程进行有效管理的一种方式。由SessionFactory的多线程性,若想实现多线程共享一个Session实例是不行的。而解决办法可以为每个线程放一个Session的副本,并由每个线程自己维护这个Session,包括获得、使用、销毁。这样,可以实现Session的线程内共享。


session不应该多线程,那将是灾难。想想,因为一级缓存的缘故,有可能引起数据脏读,而且session不释放数据库链接,也会造成大量的资源浪费。session缓存对象过多,也是浪费内存,还得手动去清理?hibernate设计session的目的就是让我们用了就close。实际上,每个线程的session都是不同的。


在我看来,的Session的线程内共享,是指,Session做为一种持久化的工具,可以用来将其中的各种对象与数据库之间进行交互。所以,直到未被销毁前,Session可以用来做各种各样的操作,如查询、保存、修改、删除等。但任何数据库都有最大连接限制,所以,当完成对数据库的操作后,必须断开与数据库的连接。然而,session只要不销毁,它与数据库的连接将一直存在,并随着用户操作的增加,连接数将不断增加


非也。。。session只有当你真正需要访问数据库的时候才获取链接,然后在事务提交过后释放链接(Spring中是这样实现的)。也就是说,当你Session s=SessionFactory.openSession();的时候session并没有获得数据库链接,甚至在Query q=s.createQuery(hql)时都没有获得连接,真正获得连接是在q.list()的时候。当然还有其他时候。。。。


因此,这里有个矛盾:既要实现session的共享,也即只用一个session来完成不同的操作,又要尽量使每个操作在完成后断开连接,也即关闭session。

对此,很多人在编程时可能都是这样做的:

1.每完成一个操作,都关闭当前线程中的Session,当再次需要时,由线程再次从SessionFactory中去获取。这样,可以保证所有的连接都能被释放,不会造成数据库连接次数的爆满。但这样做的话,线程内的Session一获得,一个操作后就销毁了,下一个操作还要到SessionFactory中去取,线程内共享Session还有什么意义?。

2.所有操作均不关闭Session,而是在每个请求结束后统一关闭。这样,很好地实现了线程内Session的共享。但这样的话,每个用户占用的连接数将大大增加,用户数量很多的话,很可能在某个时刻连接数没有得到及时释放,造成数据库连接爆了。打个比方,有个循环,内中有个未关闭Session的方法。如果想在这个循环内共享Session,在循环后再关闭这个Session,就很可能造成连接数在瞬间爆增(尤其在循环很大的情况下)。

有些人可能这样想:我在一个请求(jsp页面或servlet)的最后一个方法中关闭Session不就行了吗?然而,在当前页面中,这个方法可能是最后用到的,但到了另外一个页面中,说不定是第一个用到的。假如每个页面都在最后一个使用的方法上关闭Session,也许在XX个页面之后,所有的方法都关闭Session了。


说的对,session用完后一定要及时关闭
0 请登录后投票
   发表时间:2008-11-04  
Calf 写道
刚学Hibernate.正郁闷到底应该何时关闭Session.
LZ,有没有好的建议啊?

如果用spring的话,可以将事务与session交给spring来管理,自己不用管理。如果单只是用hibernate,一般的方法会用线程绑定,我现在的方法是在DAO层里开始session与事务,在业务层里提交事务与关闭session。
0 请登录后投票
   发表时间:2008-11-04  
多谢taupo的热心回复。
你说得很对,session是不能被多个线程共享的,这才用线程去绑定它。但我发现在B/S的项目中,多个用户是可以在一个线程中的。按我的方法,在业务层关闭session的话,每个用户在请求时都将在线程中创建一个session,然后在请求结束后关闭它。

而且,按照你的意思,session中的连接会在事务提交过后释放。那这样的话,那岂不是session自始至终只需要一个,而且也不用关闭?因为反正连接会在事务提交过后释放,我还关闭session作什么呢,用它在服务器上一直做缓存不是更好?所以,连接应该是在session被close后才会释放的。
0 请登录后投票
   发表时间:2008-11-04  
cats_tiger 写道
如果只用hibernate,就在finally块中关闭,仅此而已。

是的,一般要关闭都会在finally方法中关闭。但finally可以用在任何地方,关键是我们如何正确地使用。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics