【问题标题】:How to implement Concurrent GetOrCreate with JPA session?如何使用 JPA 会话实现并发 GetOrCreate?
【发布时间】:2012-01-20 14:22:26
【问题描述】:

我需要在 spring-jpa(休眠)驱动的 Web 应用程序中实现实体的 GetOrCreate(我称之为 ensureExists)。
我有一个分层应用程序(WS/Services/DAL/Datastore),我想在服务层(弹簧驱动)中实现此功能。
基本思路是:

  1. 查找实体
  2. 如果发现返回。
  3. 否则持久化实体。
  4. 如果一切正常,请退回。
  5. 如果发生唯一约束违规,请尝试再次查找实体并返回它。

问题源于这样一个事实,即一旦抛出异常,休眠会话应该关闭并重新打开(来自 Session 的documentation),这使得第 5 步无效,但我仍然想将此逻辑封装在服务层中(并且不要让它驻留在 DAL 或 WS 中)。

我很想听听有关如何解决这个问题的建议,我有一个想法,但我想在发布之前听到一些意见,以免答案倾向于它。

提前致谢

更新
我想到的解决方案如下:
将第 3 阶段重构为包范围服务,该服务具有单个 ensureExists 方法(带有泛型),该方法接受该类型的 Dao 和实体并具有REQUIRES_NEW 的传播。此方法将尝试持续存在,如果失败当然会抛出异常,该异常将在原始服务中捕获,如果已抛出异常,它将尝试持续存在。
我希望得到一些关于如何以其他方式实施的反馈。
如果几天后没有人提出其他建议,我会将此作为答案与代码示例一起发布并接受。

【问题讨论】:

  • 我会按照你的计划去做,只是我会将步骤 1 到 4 放在一个带有 REQUIRES_NEW 的服务中。
  • @JB Nizet 为什么您认为第 1、2、4 步需要在事务中?此外,在我看来,逻辑上只有第 3 步处于不同的抽象级别,因此有一些理由将其置于不同的服务中。所有其他步骤都具有相同的抽象级别(我认为)。
  • 我只是发现有一个“getOrCreate”方法更清楚,它可以抛出异常,如果我愿意,我可以从外部重试。它还将重试逻辑(可以完全通用,提取到代理或拦截器)与特定用例分离。它还允许对创建的实体执行其他操作,而不仅仅是返回它。使用您的系统,您获得的实体会被找到,如果创建则分离。

标签: java spring session jpa transactions


【解决方案1】:

要查找实体,您可以使用标准 api + 反射来填充所有重要属性并按示例对象进行搜索。 要解决并发问题,请考虑悲观锁定。 当您加载时,只需在该对象上加锁并在所有事务完成后释放此锁。 不确定这是否是性能方面的最佳选择,但您永远不应该在这里遇到异常。

【讨论】:

  • 我可能错了,但我认为如果“查找”步骤需要条件(索引列上的单列除外),您将无法使用悲观锁定。
  • 感谢您的回答。我实际上不想使用悲观锁定,因为它会成为性能杀手。我认为这是乐观锁定的经典用例,但我只需要为最终用例做准备
猜你喜欢
  • 2018-11-01
  • 1970-01-01
  • 2018-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 2011-01-30
相关资源
最近更新 更多