87

我倾向于将HibernateSpring框架结合使用,它具有声明性事务划分功能(例如,@Transactional)。

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


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

  1. 使关系不延迟加载(例如,fetchType=FetchType.EAGER)
    • 这违反了延迟加载的整个想法..
  2. 使用初始化集合Hibernate.initialize(proxyObj);
    • 这意味着与 DAO 的耦合度相对较高
    • 虽然我们可以用 定义一个接口initialize,但不保证其他实现提供任何等价物。
  3. 将事务行为添加到持久Model对象本身(使用动态代理@Transactional
    • 我没有尝试过动态代理方法,尽管我似乎从来没有让@Transactional 处理持久对象本身。可能是由于休眠是在代理上的操作。
    • 交易实际发生时失去控制
  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

4

3 回答 3

26

众所周知,hibernate 尽可能做到无创和透明

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

请注意,Hibernate 无法读取想法,因此如果您知道特定操作需要一组特定的依赖项,则需要以某种方式向 Hibernate 表达您的意图。

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

于 2011-02-17T09:44:45.753 回答
7

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

  • 对象foo被加载并放入地图;
  • 另一个线程从映射中获取这个对象并调用foo.getBar()(以前从未调用过并且被惰性评估的东西);
  • 繁荣!

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

  • 尽可能透明地包装会话(例如OpenSessionInViewFilter对于 webapps);
  • 具有用于线程/线程池的通用 API,其中 db 会话绑定/取消绑定在层次结构中的某个较高位置(包装在 中try/finally)完成,因此子类不必考虑它;
  • 在线程之间传递对象时,传递 ID 而不是对象本身。接收线程可以根据需要加载对象;
  • 缓存对象时,从不缓存对象,而是缓存它们的 id。当您知道 ID 时,在您的 DAO 或管理器类中有一个抽象方法可以从二级 Hibernate 缓存加载对象。从二级 Hibernate 缓存中检索对象的成本仍然比使用 DB 便宜得多。

如您所见,这确实与非侵入性和透明性相去甚远。但成本仍然是可以承受的,与我必须为急切加载支付的价格相比。后者的问题是,有时在加载单个引用对象时会导致蝴蝶效应,更不用说实体集合了。内存消耗、CPU 使用率和延迟至少要差得多,所以我想我可以忍受它。

于 2011-02-17T14:45:57.950 回答
3

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

如果您正在构建服务,我会在服务的公共方法上打开 TX,而不是在 DAO 上打开 TX,因为方法通常需要获取或更新多个实体。

这将解决任何“延迟加载异常”。如果您需要更高级的性能调整,我认为获取配置文件是要走的路。

于 2011-02-17T09:28:36.313 回答