Hibernate延迟加载应用程序设计

Joh*_*erg 86 java spring hibernate lazy-loading application-design

我倾向于将HibernateSpring框架结合使用,并使用声明式事务划分功能(例如@Transactional).

众所周知,hibernate试图尽可能地非侵入性透明性,但是这在使用关系时证明更具挑战性lazy-loaded.


我看到了许多具有不同透明度的设计方案.

  1. 使关系不是懒惰的(例如, fetchType=FetchType.EAGER)
    • 这违反了延迟加载的整个想法..
  2. 使用初始化集合 Hibernate.initialize(proxyObj);
    • 这意味着与DAO的相对高耦合
    • 虽然我们可以定义一个接口initialize,但是其他实现并不能保证提供任何等价物.
  3. 将事务行为添加到持久Model对象本身(使用动态代理@Transactional)
    • 我没有尝试过动态代理方法,尽管我似乎从来没有让@Transactional处理持久对象本身.可能是因为hibernate是在代理上运行的.
    • 交易实际发生时失去控制权
  4. 提供惰性/非惰性API,例如loadData()loadDataWithDeps()
    • 强制应用程序知道何时使用哪个例程,再次紧耦合
    • 方法溢出loadDataWithA(),....,loadDataWithX()
  5. 强制查找依赖关系,例如,仅通过提供byId()操作
    • 需要很多非面向对象的例程,例如,findZzzById(zid)然后getYyyIds(zid)而不是z.getY()
    • 如果事务之间存在大量处理开销,则逐个获取集合中的每个对象可能很有用.
  6. 创建@Transactional 应用程序的一部分,而不仅仅是DAO
    • 嵌套事务的可能考虑因素
    • 需要适用于事务管理的例程(例如,足够小)
    • 虽然可能导致大量交易,但程序性影响较小
  7. 为DAO提供动态提取配置文件,例如,loadData(id, fetchProfile);
    • 应用程序必须知道何时使用哪个配置文件
  8. AoP类型的事务,例如,拦截操作并在必要时执行事务
    • 需要字节码操作或代理使用
    • 执行交易时失去控制权
    • 黑魔法,一如既往:)

我错过了任何选择吗?


在尝试最小化lazy-loaded应用程序设计中关系的影响时,哪种方法是您首选的方法?

(哦,对不起WoT)

axt*_*avt 26

众所周知,hibernate试图尽可能地具有非侵入性和透明性

我会说最初的假设是错误的.转换持久性是一个神话,因为应用程序总是应该关注实体生命周期和被加载的对象图的大小.

请注意,Hibernate无法读取想法,因此如果您知道某个特定操作需要一组特定的依赖关系,那么您需要以某种方式表达您对Hibernate的意图.

从这个角度来看,明确表达这些意图的解决方案(即2,4和7)看起来是合理的,并且不会缺乏透明度.


min*_*das 7

我不确定你暗示哪个问题(由懒惰引起),但对我来说最大的痛苦是避免在我自己的应用程序缓存中丢失会话上下文.典型:

  • 对象foo被加载并放入地图中;
  • 另一个线程从map和调用中获取此对象foo.getBar()(以前从未调用过的东西并且是惰性求值的);
  • 繁荣!

因此,为了解决这个问题,我们有许多规则:

  • 尽可能透明地包装会话(例如,OpenSessionInViewFilter对于webapps);
  • 有线程/线程池的通用API,其中db session bind/unbind在层次结构中的某个位置完成(包装try/finally),因此子类不必考虑它;
  • 在线程之间传递对象时,传递ID而不是对象本身.接收线程可以在需要时加载对象;
  • 在缓存对象时,永远不要缓存对象,而应缓存它们的ID.在您知道ID时,在DAO或manager类中有一个抽象方法从第二级Hibernate缓存加载对象.从二级Hibernate缓存中检索对象的成本仍然比去DB要便宜得多.

正如您所看到的,这确实无法接近非侵入性和透明性.但是成本仍然可以忍受,与我为急切装载所需支付的价格相比.后者的问题是,有时它会在加载单个引用对象时导致蝴蝶效应,更不用说实体集合了.内存消耗,CPU使用率和延迟提到最少也差得多,所以我想我可以忍受它.