不要把Hibernate事务控制放在Http请求开始的地方

不要把事务控制放在Http请求开始的地方
javamonkey 原创   更新:2008-04-01 22:48:58  版本: 1.0   

 第一次知道有这么一种控制事务的方法是在一个使用Hibernate的java项目里
程序的架构大概如下,
创建一个ServletFilter,处理所有Web请求,在这个ServletFilter里通过调用SessionFactory得到Session
代码如下:

  1. public void doFilter(ServletRequest request, ServletResponse response,
  2.                          FilterChain chain)
  3. throws IOException, ServletException {
  4. Session session = null;
  5. try {
  6.       session = HibernateUtil.getSessionFactory().openSession();
  7.       session.beginTransaction();
  8.       RequestContext.put(session);
  9.      chain.doFilter(request, response);
  10.        session.getTransaction().commit();
  11.       session.close();
  12. }
  13. catch(Throwable t) {
  14.      HibernateUtil.close(session)
  15. }

   这样管理事务的方法有很大的问题,一是事务的结束时间不但依赖于业务方法执行需要的时间,还取决于JSP 执行时间的长短,如果客户端网络很慢,JSP需要花很长时间才执行完内容的output,那么,这样的事务可能会花费额外的数秒中,那么,很可能出现潜在 的问题:如长时间锁表导致其他用户不可用;性能变得不好等。所以,还是建议把事务管理放在业务方法里面是比较好的. 
 这样在 ServletFilter初始化Session,并在Filter方法执行完毕后关闭Sesion还有一个更常见的应用,那就是便于使用 Lazy load.你可以在你的业务方法里,JSP里任意使用导航到另外一些对象那里,Hibernate会自动根据配置文件去从数据库Load相关对 象。这样做极大的方便程序编写,一是按需所取,你可以从一个User对象几乎导航到系统所有对象.二是Hibernate 本身load策略使用不方便, 只能配好,不能根据需要指定。如用户与好友关系,当用户登录,系统只需要取出用户自己的信息显示就可,根本不需要相关对象,但另外一个需求显示用户的好友 列表则需要Load。因此开发人员干脆不做任何需要设定,全设置Lazy load,在按照上面的Filter来处理
 即使你把关于事务处理的代码放在业务层去控制而只是为了Lazy Load方便,我相信这样做还是有问题,原因有俩个
 1) 系统层次不分明,原来经典的分层架构中是业务层负责处理业务数据,但现在 JSP也会从数据库里取数据(通过Hibernate)
2) 接口设计过于粗糙,如前面说的,所有系统都可以只提供一个业务接口,getUser(),然后,让其他人去使用导航去取别的想要对象,如在JSP里
 <%
        out.println(user.getFriend()[0].getVistLog()[0]);
    %>
    <%
        out.println(user.getPhoto().getPhotoMeta().getPath());
    %>     

3) 爆发性能问题,越来越多的项目里看到了满页甚至俩三页的 SQL输出日志,而执行的业务逻辑取仅仅是联合三,四个表取些数据,过于依赖Hibernate Lazy load的架构必然滋生性能问题(而这在使用纯JDBC的情况下不可能发生)

所以,我认为不要为了迎合Hibernate的目前的Lazy load方式使用文章刚开始用的例子。得不偿失,也许只适合一些Demo系统或者根本不用关系客户感受的系统

那如何解决Lazy Load问题呢,这有些个人建议和想法
1) 数据还是在业务层一次取出,对于复杂的操作,可以考虑用SQL语句,对于简单的操作,你可以显示的调用一下导航,如user.getPhoto(),这么做对性能没有帮助,但至少能保证良好的接口设计和让别人明白你的意图。
2)更改Hibernate的实现机制,支持"智能化 Load",如下面的例子
 
   List list = session.createQuery("from user -- user.friend.vistlog --");
   -- user.friend.vistlog -- 为一普通SQL注释 .意思是告诉 Hibernate你也需要vistlog对象 ,让Hibernate自己去考虑如何优化
   List list = session.createQuery("from user "); 则只是按照默认策略来Load对象
   
   当 然,更改Hibeernate实现简直是不可能做到的事情,只能希望Hibernate社区哪天加上新的实现.如果你自己要做,我的建议是做个伪实现,即 不优化SQL,只是简单的根据注释-- user.friend.vistlog -- 来Load相关对象,这已经是偏离此文的主体了。
   
   总的来说,我并不认为在Http请求出来初始化HibernateSession 和在Http结束前关掉 Session 是一个很好的方法,这不单是技术上有潜在的问题,而且,导致整个架构不够明晰,导致开发人员懒于写优秀的代码。
[light]

<script type="text/javascript"><!-- google_ad_client = "pub-7390275636631344"; google_ad_width = 728; google_ad_height = 90; google_ad_format = "728x90_as"; google_ad_type = "text_image"; google_ad_channel ="5095444487"; google_color_border = "336699"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "008000"; google_color_text = "000000"; //--></script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script> <script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script> <script>window.google_render_ad();</script>
版权声明   给作者写信
本篇文章对您是否有帮助?  投票:         投票结果:     11       1
作者其它文章: 作者全部文章     查看作者的Blog
评论人:xyz20003 发表时间: Tue Apr 01 00:45:47 CST 2008
说的不错,OpenSessionInView的确有这些隐患。

但是因为太方便了,去掉osiv,hibernate就不好用了,本来就是lazy load + cache造成超越jdbc的优点,要是把这些关闭了,实在看不出还有什么使用hibernate的必要,就为了save的时候用javabean何不考虑ibatis呢?

连 接超时导致session无法释放,的确非常唬人,实际上有一种用apache做前端,把网速慢的连接隔离掉的方法,让osiv只从apache到 tomcat起作用,如果客户网速太慢,则让apache去负责等待,不会出现session一直无法释放问的问题。(高并发访问情况待验证)

没有两全其美的方法,诸君任选吧。osiv也只是一种开发手段而已。[M]
评论人:xyz20003 发表时间: Tue Apr 01 00:46:49 CST 2008
你这里的txn控制太弱了,连异常回滚都没有,参考spring的osiv好好写一下吧。
评论人:270996853 发表时间: Tue Apr 01 14:44:15 CST 2008
[good]
评论人:championcgh 发表时间: Tue Apr 01 15:58:48 CST 2008
好东东啊 
评论人:javamonkey 发表时间: Tue Apr 01 22:53:58 CST 2008
增加了处理事务的一个方法HiberanteUtil.close(session)

更多关于Open Session in View可以参考此文
http://www.hibernate.org/43.html
评论人:zf534685796 发表时间: Tue Apr 15 20:17:58 CST 2008
sdf
评论人:yan55667 发表时间: Thu Aug 21 14:54:43 CST 2008
[good][good]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值