Hibernate延迟加载应用程序devise

我倾向于将Hibernate与Spring框架结合使用,它是声明式事务分界function(例如@Transactional )。

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


我看到许多不同透明度的devisescheme。

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

我错过任何select吗?


试图最大限度地减less应用程序devise中lazy-loaded关系的影响时,您最喜欢哪种方法?

(哦,对于WoT抱歉)

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

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

请注意,Hibernate不能读取想法,因此如果您知道您需要特定操作的一组特定的依赖关系,则需要以某种方式expression您对Hibernate的意图。

从这个angular度来看,明确地expression这些意图的解决scheme(即2,4和7)看起来是合理的,不会因缺乏透明度而受到影响。

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

  • 对象foo被加载并放入地图;
  • 另一个线程从地图中获取这个对象,并调用foo.getBar() (之前从未被调用过的并且被懒计算);
  • 繁荣!

所以,为了解决这个问题,我们有一些规则:

  • 尽可能透明地包装会话(例如OpenSessionInViewFilter for webapps);
  • 有线程/线程池共同的API,其中db会话绑定/取消绑定在层次结构中的某个地方完成(包装在try/finally ),所以子类不必考虑它;
  • 当在线程之间传递对象时,传递ID而不是对象本身。 接收线程如果需要的话可以加载对象;
  • 当caching对象时,永远不要caching对象,但他们的ID。 在您的DAO或pipe理器类中有一个抽象方法,以便在知道该ID时从第二级Hibernatecaching中加载该对象。 从二级Hibernatecaching中检索对象的成本仍然比去DB要便宜。

正如你所看到的,这确实远没有非侵入性和透明性 。 但是成本还是可以承受的,与我为了急切加载而必须支付的价格相比。 后者的问题是,有时在加载单个引用的对象时会导致蝴蝶效应,更不用说收集实体了。 内存消耗,CPU使用率和提及最less的延迟也差得多,所以我想我可以忍受它。

如果你正在构build一个Web应用程序,一个非常常见的模式是使用OpenEntityManagerInViewFilter 。

如果你正在构build一个服务,那么我将在服务的公共方法上而不是在DAO上打开TX,因为一个方法通常需要获取或更新几个实体。

这将解决任何“惰性负载exception”。 如果您需要更高级的性能调整function,我认为获取configuration文件是一种方法。