好记忆力不如烂笔头102-spring3(22)-高并发下的延迟加载陷阱

好记性不如烂笔头102-spring3(22)-高并发下的延迟加载陷阱

Spring 提供了一个专门的OpenSessionInViewFilter过滤器,能够给每一个请求的过程绑定一个hibernate session。就算最开始的事务已经完成,也可以在web层进行延迟加载的操作。

—– OpenSessionInViewFilter过滤器【部分来自网络】

用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现”Open Session in View”的模式。
例如: 它允许在事务提交之后延迟加载显示所需要的对象。

这个过滤器和 HibernateInterceptor 有点类似:它是通过线程实现的。无论是没有事务的应用,还是有业务层事务的应用(通过HibernateTransactionManager 或
JtaTransactionManager的方式实现)它都适用。在后一种情况下,事务会自动采用由这个filter绑定的Session来进行相关的操作以及根据实际情况完成提交操作。

警告: 如果在你的应用中,一次请求的过程中使用了单一的一个HIbernate Session,在这种情况下,采用这个filter会产生一些以前没遇到的问题。特别需要注意的是通过
Hibernate Session重新组织持久化对象之间关系的相关操作需要在请求的最开始进行。以免与已经加载的相同对象发生冲突。

或者,我们可以通过指定”singleSession”=”false”的方式把这个过滤器调到延期关闭模式。这样在一次请求的过程中不会使用一个单一的Session。每一次数据访问或事务相关操作都使用属于它自己的session(有点像不使用Open Session in View)。这些session都被注册成延迟关闭模式,即使是在这一次的请求中它相关操作已经完成。

“一次请求一个session” 对于一级缓存而言很有效,但是这样可以带来副作用。例如在saveOrUpdate的时候或事物回滚之后,虽然它和“no Open Session in View”同样安全。
但是它却允许延迟加载。

它会在spring的web应用的上下文根中查找Session工厂。它也支持通过在web.xml中定义的“SessionFactoryBeanName”的init-param元素 指定的Session工厂对应的bean的
名字来查找session工厂。默认的bean的名字是”sessionFactory”.他通过每一次请求查找一次SessionFactory的方式来避免由初始化顺序引起的问题(当使用ContextLoaderServlet
来集成spring的时候 ,spring 的应用上下文是在这个filter 之后才被初始化的)。

默认的情况下,这个filter 不会同步Hibernate Session.这是因为它认为这项工作是通过业务层的事务来完成的。而且HibernateAccessors 的FlushMode为FLUSH_EAGER.如果你
想让这个filter在请求完成以后同步session.你需要覆盖它的closeSession方法,在这个方法中在调用父类的关闭session操作之前同步session.此外你需要覆盖它的getSession()
方法。返回一个session它的FlushMode 不是默认的FlushMode.NEVER。需要注意的是getSession()和closeSession()方法只有在single session的模式中才被调用。

—– 这里才是正文 高并发下的延迟加载陷阱

对于访问强度不够大的应用来说,使用OpenSessionInViewFilter可以大幅度降低延迟加载所引发的各种问题。
但是对于访问强度比较大的应用来说,最好不要使用OpenSessionInViewFilter。因为OpenSessionInViewFilter会让每一个web请求都绑定一个session,而hibernate的session往往都会绑定一个数据库连接,一直到访问完成。
我们都知道,高强度的系统访问,最常见的一个瓶颈往往就是数据库。因此使用OpenSessionInViewFilter会带来一些重要的性能问题。比如:加大了对数据库资源访问的并发性(不是所有的web请求都要用到数据库连接),延迟了web请求对数据库资源占用的时间。
因此,使用了OpenSessionInViewFilter会让系统更加容易出现数据库资源上的瓶颈。而数据库的升级是非常困难的,比如从一个普通的高性能PC服务器换成小机组,买一组比较便宜的P570,上百万的开支就花出去了。以后的运维费用,还是一笔天文数字;
如果已经是双RAC的小机,那么需要升级成4节点的小机,更加恐怖的天文数字。 有点走题了….

解决延迟加载的陷阱的自我救赎

如果不用OpenSessionInViewFilter,那么我们就要自己来解决延迟加载的问题,这也是一个痛苦的事情,但是为了让系统更加健壮,这不正好是我们作为有追求的程序猿的攀登方向么?
我们要设计好Service层面上的服务接口,让延迟加载的工作在Service层内完成;还需要提供多种面对不同场景的Service的服务接口。
路漫漫其修远兮,为了更加高的并发性,吾将上下而求索。