Hibernate延迟加载应用程序devise
我倾向于将Hibernate与Spring框架结合使用,它是声明式事务分界function(例如@Transactional )。
众所周知,hibernate试图尽可能保持非侵入性和透明性 ,但是在使用lazy-loaded
关系时,这样做会更具挑战性 。
我看到许多不同透明度的devisescheme。
- 使关系不会延迟加载(例如,
fetchType=FetchType.EAGER)
- 这违背了懒加载的整个想法。
- 使用
Hibernate.initialize(proxyObj);
初始化集合Hibernate.initialize(proxyObj);
- 这意味着相对较高的DAO耦合
- 虽然我们可以用
initialize
来定义一个接口,但其他的实现不能保证提供任何等价的东西。
- 将事务行为添加到持久
Model
对象本身(使用dynamic代理或@Transactional
)- 我还没有尝试dynamic代理的方法,虽然我似乎从来没有得到@Transactional工作在持久对象本身。 可能是因为hibernate是在一个代理服务器上运行的。
- 交易实际发生时失去控制权
- 提供惰性/非惰性API,例如
loadData()
和loadDataWithDeps()
- 强制应用程序知道何时使用哪个例程,再次紧密耦合
- 方法溢出,
loadDataWithA()
,…,loadDataWithX()
- 强制查找依赖关系,例如,仅通过提供
byId()
操作- 需要大量非面向对象的例程,例如
findZzzById(zid)
,然后getYyyIds(zid)
而不是z.getY()
- 如果事务之间存在大量的处理开销,那么逐个获取集合中的每个对象会非常有用。
- 需要大量非面向对象的例程,例如
- 使应用程序 @Transactional,而不是只有DAO的一部分
- 嵌套事务的可能考虑
- 需要适应事务pipe理的例程(例如,非常小的)
- 虽然可能会导致大规模的交易,但对程序的影响很小
- 为DAO提供dynamic获取configuration文件 ,例如
loadData(id, fetchProfile);
- 应用程序必须知道使用哪个configuration文件时
- 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文件是一种方法。