Posted on 2006-09-13 10:12
Jason Cui 阅读(2414)
评论(13) 编辑 收藏 网摘 所属分类:
编程经验
半年前开始研究NHibernate,受http://www.codeproject.com/aspnet/NHibernateBestPractices.asp这篇文章的导向,开始按照它的方式来使用NHibernate,作者还称之为最佳实践。看上去的确如此,充分的考虑到了效率问题,把SessionFactory放到Application级的缓存中,把Session放到Context的缓存中,每个Request开始的时候Open一个Session,结果的时候Close它。而且在它的源码中,Flush也是在Close的时候进行的。
这样做的一开始就遇到一个问题,就是会出现一些奇怪的保存数据的情况。测试人员比较少,没有及时发现问题,等到网站发布出去才发觉,很多用户的密码被清空了。变成了Null。赶紧想原因,原来用了一个精简版的User类保存在Session中,不必每次都去数据库里取他的信息,而在用户未登录之前,这个类是New出来的。这样,在请求结束的时候,这个User就被保存回去了,导致出现了很多空的匿名用户,还有很多用户的密码被清空了。
好不容易解决了这个问题,取消了在Request结束的时候保存数据,而是每个动作后直接Flush。此后一直相安无事。直到这两天升级成Asp.net 2.0,每到下午2点左右的时候就会出现严重的异常导致系统的w3wp进程不停的重启,系统无法正常工作,而切换回1.1版本又没有问题。为了这个问题搞的我一周时间焦头烂额。直到昨天才找到问题的根源。这个异常是由数据库连接池引起的。日志信息里显示检测到死锁,一开始一直不知道这个死锁指的是什么。现在才明白,是数据库连接的死锁。
在1.1的状态下,如果数据库连接被用满,下一个用户会看到服务器错误的页面,等待前面的连接释放掉,后面的用户才能再访问。这时候出现的异常信息被1.1自己处理掉了。而到了2.0,这个异常属于进程外的异常信息,会被抛出,导致进程的死掉。
由于Session被放到Context的上下文里,每个连接建立一次Session。当上文的作者假设你的每个请求处理速度都快到可以忽略的时候,这是没有问题。然而在我们的网站里,每个页面里可能有数十次数据库处理,整个页面的生成时间超过1秒,这就变成了整个网站所能承受的并发会话数直接受到了数据库连接池所允许的连接数的限制。于是再次修改程序,把Session变成每次使用数据库之前Open,读取完成马上Close。按照原作者的分析,与数据库之间的Connection的Open和Close是相当费时的操作,然而在.Net平台下,所有的连接默认受到数据库连接池的处理,这个过程其实已经被缓存过了,没必须再占着Connection不放了。
另外,为了避免系统两次出现不可知的异常导致服务器当机,直接修改了aspnet.config文件,把未知异常的处理方式修改回1.1默认的方式,也就是忽略它,继续执行。虽然微软不推荐这样做,但是在这样一个没有足够的测试时间和能力的环境下,也只好这样了。
Feedback
如果不忽略未知异常的话,根据已经改变了的asp.net2.0的异常机制,怕是要上来就写catch(){}了.
NHibernate 与java中的 Hibernate 有什么不同?
共享一个web打印解决方案 http://qq6441.meibu.com 这个有dotnet版本的。
Hibernate 这套东西效率到底怎么样?
做办公之类的东西没问题,如果做网站,访问量大,并发频繁,它的效率也没问题吗?一直有所顾忌...
我觉得如果网站的访问量大到受ORM层影响的时候,应该考虑全站静态生成了。
不要看它的源代码了,那个有误导,在并发量很大的情况下,会出现死锁。
# re: NHibernate在Asp.net中的实际应用 回复 更多评论
2007-01-01 21:52 by Jason Cui
不要看它的源代码了,那个有误导,在并发量很大的情况下,会出现死锁。
----------------------------------------------
Jason Cui这么说未免小气,其实作者(http://devlicio.us/blogs/billy_mccafferty/)已经在他的Blog里面说明这个问题了,并分别针对ASP.NET的情况做了处理,之前的问题原因一是.net2.0对于线程异常默认处理方法的变化,二是作者对使用CallContext在asp.net环境下的使用误区造成的。不过作者已经在他的新文章里面说明了,对应用NHibernate进行项目开发感兴趣的朋友可以一并去看看(http://devlicio.us/blogs/billy_mccafferty/archive/2007/04/03/nhibernate-best-practices-with-asp-net-1-2nd-ed.aspx) 不过 Jason Cui还是挺不错的,感觉得到他是个真正的程序员。 :)
这种放在Context里的问题 java里也出过
可是看了最新的NHibernate src里的Example
仍然提供了放在Session里一个Quick Start例子
不知道这些人怎么想的
Open Session in View 在并发量大而且页面返回时间较长的情况下的确是有瓶颈问题,但它也为nh的lazy-loading带来便利。其实还是看应用的性质。不过,个人认为声明式的事务才是比较好的解决方案。
不错,确实没有必要在request开始的时候就openSession,如果页面处理比较复杂的话,打开的数据库连接耗费的内存是比较可观的。个人认为还是在任务执行时打开连接,执行完就关闭的策略比较好。