`
huangjiej
  • 浏览: 3261 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

延迟加载时为什么不自动open session呢?

阅读更多
    用了hibernate都有差不多2年时间,一直都没有深入研究,最近学习起它的延迟加载。
    在网上找了很多资料,它们都是说,使用延迟加载时,被加载对象(也就是那个proxy)必须是同一个session打开的前提下,才能获取数据,否则,会抛出session is closed 或 disconnection session 异常。
    对此,我有个疑问,为什么hibernate在检测到与proxy相关联的session 是close或disconnection 时,不自动open,反而是抛异常。可能是为了事务的一致性考虑。
    了解这个问题的目的是要找出一种方法替代opensessioninview,我认为,延迟加载可以用于2个场景中,一个是从数据库取出数据,并传递到view层展现;另一个是在后台处理的时候。若是第一种场景的话,我觉得proxy取数据时,自己打开session并以只读方法加载数据,并不需要用opensessioninview的长连接。至于后一种在后台处理时,大可以把所需要的数据预先取出,而不需要使用延迟加载。
    希望各位发表一下意见。
分享到:
评论
15 楼 crazyfighter 2008-12-14  
huangjiej 写道
    用了hibernate都有差不多2年时间,一直都没有深入研究,最近学习起它的延迟加载。
    在网上找了很多资料,它们都是说,使用延迟加载时,被加载对象(也就是那个proxy)必须是同一个session打开的前提下,才能获取数据,否则,会抛出session is closed 或 disconnection session 异常。
    对此,我有个疑问,为什么hibernate在检测到与proxy相关联的session 是close或disconnection 时,不自动open,反而是抛异常。可能是为了事务的一致性考虑。
    了解这个问题的目的是要找出一种方法替代opensessioninview,我认为,延迟加载可以用于2个场景中,一个是从数据库取出数据,并传递到view层展现;另一个是在后台处理的时候。若是第一种场景的话,我觉得proxy取数据时,自己打开session并以只读方法加载数据,并不需要用opensessioninview的长连接。至于后一种在后台处理时,大可以把所需要的数据预先取出,而不需要使用延迟加载。
    希望各位发表一下意见。

14 楼 hypercube1024 2008-12-13  
HRoger 写道
最近,我也碰到了这个问题,感觉延迟加载就像鸡肋,我的客户端是基于Eclipse的rpc的,通过webservice来调用的,很难实现opensessioninview,我只能lazy=“false”来解决了,不知大家对于webservice这样东西,用Hibernate有什么好的建议


用webservice的话我一般就做一个dto然后用BeanUtils拷贝一下属性了,虽然麻烦一点,不过也是没有办法,总比lazy=false好点,毕竟如果是是集合的话,还是影响性能的,需要什么属性就做一个相应的dto,通过BeanUtils拷贝还是很方便的.
13 楼 taupo 2008-12-12  
opensessioninview并不等于长连接
opensessioninview只是保持session不关闭,但是在一般情况下,当事务提交过后,session会释放数据库连接,但是session并不关闭
当再次需要读取数据库时,session会重新获取连接
12 楼 elam 2008-12-12  
我弱弱的问下拦截器不行么?
拦截器难道算是长连接么?
11 楼 xieke 2008-12-12  
robbin 写道
事情没你想像的那么简单。Hibernate通过Session的一级缓存来管理持久化对象的状态,当Session关闭之后,持久化对象究竟处于何种状态是未知的,此时如果自动打开第2个Session,这个Session的缓存里面没有这个持久化对象的引用关系,因此无法判断对象状态,那么就很有可能带来一些不可预知的后果,比方说应该update的时候却没有update,应该级联插入却没有插入等等。



其实没有想象中这么复杂的,一级缓存存在的主要目的是维护事务独立性,
也就是在事务中的未提交数据在一级缓存中,不会影响到二级缓存,
当事务提交后,一级缓存同步到二级缓存中,
到达页面中的时候,事务当然已经结束,此时一级缓存已经同步到二级缓存中。
归根结底,页面层次只是view级别,
所以新开一个session用于页面延迟加载,也就是新开一个数据库连接用来查看而已,
直接使用二级缓存是没有问题的。

10 楼 yujianqiu 2008-04-19  
我觉得如果你有这个困惑的话,就有必要去学习一下什么是Session了。
关闭Session不意味着关闭Connection;
长连接是一个相对的概念,opensessioninview不是长连接的代名词。

HRoger的问题,是一个设计问题,也是一个技巧问题。
google一下DTO,也可以查查Hibernate API中Hibernate.initialize()这个方法。
9 楼 HRoger 2008-04-01  
最近,我也碰到了这个问题,感觉延迟加载就像鸡肋,我的客户端是基于Eclipse的rpc的,通过webservice来调用的,很难实现opensessioninview,我只能lazy=“false”来解决了,不知大家对于webservice这样东西,用Hibernate有什么好的建议
8 楼 huangjiej 2008-03-14  
to hrtc:

   "再重连后我觉得还是同一个session",是的,重连是同一个session的,可看我上面回复的内容。
   至于“另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了” ,这个要分2个情况考虑哦,一种是没有使用lazy的或者lazy的属性的值都已经取出来的,这个应该是没有问题的。另一种是使用了lazy,而且这个对象中的lazy属性没有加载数据,这个很大可能会出问题,因为这时是2个session同时操作一个对象。
    我没有试过,抽空测试一把把结果告诉大家。
  
7 楼 huangjiej 2008-03-14  
哦,那proxy其实是有绑定session的
我稍稍看一下源码,hibrenate的延迟加载代理对象分成
PersistentCollection 集合类的延迟加载,在其抽象实现类(AbstractPersistentCollection)里,保存了SessionImplementor(保存session与其它hibernate对象的关联,实际上session也继承此接口),只不过是私有变量。
HibernateProxy(好像是代理实体类的),有方法 getHibernateLazyInitializer()取出LazyInitializer,在LazyInitializer身上,我们也能看到SessionImplementor,所以要取出session还是有可能的,只不过,这就带有一定的bad smell,呵呵。
恰巧,我也找到一份这样的代码,其思想是在hibernate抛出session close异常时,会创建一个session并查询数据,(http://www.360works.com/articles/detail/56/),“Hibernate Lazy Loading patch” ,它是基于hibernate2的,直接是修改了hibernate里面的代码.
6 楼 robbin 2008-03-14  
huangjiej 写道
robbin说的的确有道理,2个session处理同一个对象时,很容易会出现不可预料的结果。但是,请想一下延迟加载的使用场景,一般是在后台查询数据然后在前台部分显示,在这种情况下,打开的第二个session只是用于数据的加载,并不会对相关数据进行增删改操作。与此同时,我认为session的生存期是比较短的,如在opensessioninview的模式中,session会在请求结束时close掉,并且会被回收,所以当我打开第二个session加载数据,完毕后关闭,不使用第二个session执行增删改操作,理论上是不会出现这种不可预知的后果。
因此,我观点是在view层展示数据的时候,session reconnect或者新开一个session去取lazy数据,这种方法是可取的。不知robbin有何看法。


session reconnect是完全可以的,但问题是你还是要持有session,否则你从哪来reconnect?既然你要一直持有session,那就还是OpenSessionInView模式,没啥本质区别,唯一的区别只在于底层的数据库连接是否被分配而已。

如果关闭session再次打开,即使是只读,也一定会报错。这是因为lazy的对象引用关系是关联到当前的session上的,你关闭掉session以后,打开一个新的session,这个新的session和你内存当中的lazy对象没有任何引用关系,所以当你存取lazy对象的时候,lazy对象找不到引用的session,就会报错。


5 楼 hrtc 2008-03-14  
hibernate里应该不能2个session里处理同一个对象的,这里的对象是指session维护的java对象,一个对象只能被一个session处理,但多个session可以处理数据库中同一条记录,session close后只是清除缓存(快照并非里面的对象),只要有引用指着原有对象,该对象不会释放,再重连后我觉得还是同一个session,lz你用了延迟加载,取数据时当然会去查数据库。另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了。以上是我的理解,不知正不正确。
4 楼 huangjiej 2008-03-14  
robbin说的的确有道理,2个session处理同一个对象时,很容易会出现不可预料的结果。但是,请想一下延迟加载的使用场景,一般是在后台查询数据然后在前台部分显示,在这种情况下,打开的第二个session只是用于数据的加载,并不会对相关数据进行增删改操作。与此同时,我认为session的生存期是比较短的,如在opensessioninview的模式中,session会在请求结束时close掉,并且会被回收,所以当我打开第二个session加载数据,完毕后关闭,不使用第二个session执行增删改操作,理论上是不会出现这种不可预知的后果。
因此,我观点是在view层展示数据的时候,session reconnect或者新开一个session去取lazy数据,这种方法是可取的。不知robbin有何看法。
3 楼 luckaway 2008-03-13  
我也有个疑问。sessin关闭之后应该只与数据库断开连接,数据还保存在session中,且此session与用户关联!
ps:
hibernate的源码太复杂了,根本看不懂
2 楼 hrtc 2008-03-13  
好像可以配一个拦截器,当关闭时自动打开(spring中)
1 楼 robbin 2008-03-13  
事情没你想像的那么简单。Hibernate通过Session的一级缓存来管理持久化对象的状态,当Session关闭之后,持久化对象究竟处于何种状态是未知的,此时如果自动打开第2个Session,这个Session的缓存里面没有这个持久化对象的引用关系,因此无法判断对象状态,那么就很有可能带来一些不可预知的后果,比方说应该update的时候却没有update,应该级联插入却没有插入等等。

相关推荐

    Open Session in View模式.PPT

    - 当我们在实体类中定义一个关系属性(如一对多或多对一)并标记为`@OneToMany`或`@ManyToOne`时,如果不指定加载策略,Hibernate会默认使用延迟加载。 - 如果在一个Session结束后尝试访问延迟加载的属性,将会抛...

    ssh_inte2模板常用方法&延迟加载问题

    此时,如果存在延迟加载的对象,其加载动作还没来得及执行,Session就已经被销毁,那么在后续尝试访问这些延迟加载属性时,就会抛出异常,提示对象已经被托管给事务,无法再执行数据库操作。 为了解决这个问题,...

    【北大青鸟内部教程】jsp中关于Hibernate延时加载的问题

    首先,我们需要了解什么是延时加载。延时加载是指当实体对象的某个关联属性没有被立即加载,而是等到第一次访问该属性时才进行加载。这种策略可以避免在初始化对象时加载大量不必要的数据,从而降低内存消耗和提高...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    Spring框架的延迟加载和声明式事务处理是两个关键特性,...通过合理地使用Open Session in View机制,可以解决延迟加载时Session关闭导致的问题,同时,声明式事务处理则简化了事务管理,提升了应用的效率和可扩展性。

    hibernate抓取策略和懒加载案例

    为了避免这种情况,我们可以使用Open Session in View(OSIV)模式或者在查询时显式启用急切加载。 总的来说,选择合适的抓取策略和恰当使用懒加载是优化Hibernate应用性能的重要手段。开发者应根据业务场景灵活...

    SpringBoot-SpringData-懒加载

    懒加载的主要目的是提高应用程序的性能,通过延迟加载(只有在真正需要时才加载)来减少内存消耗和数据库访问。当实体关联关系较多时,一次性加载所有数据可能会导致内存压力增大,此时懒加载就能发挥其优势。 **一...

    spring中lazy=“true”的正常读取关联表(用opensessioninview)

    当一个对象被标记为懒加载时,只有在真正需要访问该对象时,才会执行数据库查询来获取数据,而不是在初始化实体时就加载所有关联的数据。 `lazy="true"` 的使用场景通常是,当一个大型实体类中包含了很多关联的对象...

    hibernate的lazy策略forClass

    当我们定义这些关系时,如果不希望在加载父对象时立即加载子对象,可以设置`fetch`属性为` FetchType.LAZY`。例如: ```java @Entity public class Parent { @Id @GeneratedValue(strategy = GenerationType....

    hibernate在单端关联上的lazy策略

    为避免这种情况,可以使用Open Session in View(OSIV)模式或者在需要时主动初始化关联。 4. **性能考量**:虽然懒加载可以提高性能,但过度依赖它可能导致更多的数据库交互,反而降低性能。因此,开发者需要根据...

    Hibernate面试问题大全

    5. 为什么需要像Hibernate这样的ORM工具? ORM工具如Hibernate的主要优势是隔离开发者与复杂的SQL。除此之外,ORM还提供以下好处: - 提高生产力:高级的面向对象API,减少Java代码量,无需编写SQL - 提高性能:智能...

    Hibernate面试题

    如果希望Hibernate级联保存集合中的对象,则`cascade`属性应该设置为`save-update`,这样可以在保存父对象时自动保存或更新集合中的子对象。因此正确答案为**D) save-update**。 #### 五、Session的方法 `Session`...

    hibernate源代码的zip文件

    Hibernate采用懒加载策略,延迟加载关联对象,直到真正使用时才加载。这通过代理机制实现,例如,当访问一个设置了懒加载的一对多关系时,实际加载的是代理对象,只有在调用其属性时才会触发数据库查询。 七、事务...

    Hibernate 面试题

    `get()`和`load()`效率相对较高,但`load()`不立即执行SQL,可能导致延迟加载问题。 9. **Hibernate缓存机制**:Hibernate的缓存分为一级缓存(Session缓存)和二级缓存(SessionFactory缓存)。一级缓存是内置的,...

    Hibernate映射导致的几个异常

    为避免此问题,可以考虑在查询时显式加载关联的数据,或者使用开放会话视图(Open Session In View)模式。另外,使用`@Transactional`注解或在服务层方法中管理事务可以帮助保持会话的生命周期。 2. **`...

    JAVA面试题(下).pdf

    8. Hibernate的延迟加载机制允许只有在真正需要数据时才加载数据,但它与Session关闭存在矛盾,解决此矛盾的方法包括使用Open Session in View模式等。 9. MyBatis是一个持久层框架,它使用XML配置或注解来定义SQL...

    SSH 面试题

    - **延迟抓取**:仅在需要时加载关联的数据。 #### 12. 何为容器 在软件开发中,**容器**通常指一种能够管理和协调应用组件的服务提供者。例如,在Spring框架中,BeanFactory或ApplicationContext就是一个容器,...

    一次hibernate的优化实践

    - 使用Open Session in View模式需谨慎,因为它可能导致事务边界不清,影响性能。 4. **实体设计与映射优化** - 调整懒加载(Lazy Loading)和急加载(Eager Loading)策略,避免因延迟加载引发的额外查询。 - ...

    hibernate-api

    Session提供了openTransaction()方法来开始事务,commit()或rollback()方法来提交或回滚事务,save()、saveOrUpdate()、update()用于对象的保存和更新,delete()用于对象的删除,get()和load()用于对象的加载。...

Global site tag (gtag.js) - Google Analytics