java Hibernate lazyload应用程序设计
我倾向于将Hibernate与Spring框架及其声明性事务划分功能(例如@Transactional)结合使用
众所周知,hibernate试图尽可能做到无创和透明,然而,这证明在使用lazy-loaded
关系时更具挑战性
我看到许多具有不同透明度的设计方案
- 使关系不延迟加载(例如,
fetchType=FetchType.EAGER)
- 这就是延迟加载的整个概念李>
- 使用
Hibernate.initialize(proxyObj);
初始化集合- 这意味着与DAO的耦合度相对较高
- 尽管我们可以用
initialize
定义接口,但其他实现不保证提供任何等效的接口李>
- 将事务行为添加到持久
Model
对象本身(使用dynamic proxy或@Transactional
)- 我没有尝试过动态代理方法,尽管我似乎从未让@Transactional处理持久对象本身。可能是因为hibernate在代理服务器上运行李>
- 交易实际发生时失去控制
- 同时提供惰性/非惰性API,例如
loadData()
和loadDataWithDeps()
- 强制应用程序知道何时使用哪个例程,同样是紧密耦合
- 方法溢出,
loadDataWithA()
loadDataWithX()
- 强制查找依赖项,例如,仅提供
byId()
操作- 需要大量非面向对象的例程,例如
findZzzById(zid)
,然后getYyyIds(zid)
而不是z.getY()
- 如果事务之间存在较大的处理开销,则逐个获取集合中的每个对象可能很有用李>
- 需要大量非面向对象的例程,例如
- 使应用程序@成为事务的一部分,而不仅仅是DAO
- 嵌套事务的可能考虑事项
- 需要适应事务管理的例程(例如,足够小)
- 编程影响小,但可能导致大型事务
- 为DAO提供动态fetch profiles,例如
loadData(id, fetchProfile);
- 应用程序必须知道何时使用哪个配置文件
- AoP类型的事务,例如,在必要时拦截操作并执行事务
- 需要字节码操作或代理使用
- 执行交易时失去控制
- 黑魔法,一如既往:)
我错过了任何选择吗
在应用程序设计中尽量减少lazy-loaded
关系的影响时,您首选哪种方法
(哦,对不起WoT)
# 1 楼答案
我不确定你在暗示哪个问题(由懒散引起),但对我来说,最大的痛苦是避免在我自己的应用程序缓存中丢失会话上下文。典型案例:
foo
被加载并放入地图李>foo.getBar()
(以前从未调用过,而且是惰性的)李>因此,为了解决这个问题,我们有一些规则:
OpenSessionInViewFilter
用于网络应用程序)李>try/finally
)完成,这样子类就不必考虑它李>正如你所看到的,这确实远不及非侵入性和透明的。但是,与我为迫不及待的装载而付出的代价相比,成本仍然可以承受。后者的问题是,在加载单个引用对象时,有时会导致蝴蝶效应,更不用说加载实体集合了。内存消耗、CPU使用率和延迟也是最糟糕的,所以我想我可以接受
# 2 楼答案
一种非常常见的模式是在构建web应用程序时使用OpenEntityManagerInViewFilter
如果您正在构建一个服务,我会在该服务的公共方法上打开TX,而不是在DAO上,因为一个方法通常需要获取或更新多个实体
这将解决任何“延迟加载异常”。如果您需要更高级的性能调优工具,我认为获取配置文件是一个不错的选择
# 3 楼答案
我认为最初的假设是错误的。父持久性是一个神话,因为应用程序始终应该考虑实体生命周期和加载的对象图的大小
请注意,Hibernate无法读取想法,因此,如果您知道特定操作需要一组特定的依赖项,则需要以某种方式表达您的休眠意图
从这个角度来看,明确表达这些意图(即2、4和7)的解决方案看起来是合理的,并且不存在缺乏透明度的问题