Java 如何使用JPA会话实现并发GetOrCreate?

Java 如何使用JPA会话实现并发GetOrCreate?,java,spring,session,jpa,transactions,Java,Spring,Session,Jpa,Transactions,我需要在spring jpa(hibernate)驱动的web应用程序中实现实体的GetOrCreate(我称之为ensureExists)。 我有一个分层的应用程序(WS/Services/DAL/Datastore),我想在服务层(spring驱动)实现这个功能。 基本思想是: 查找实体 如果找到了,请退回 否则将持久化实体 如果一切正常,请退回 如果发生唯一约束冲突,请尝试再次查找实体并返回它 问题产生于这样一个事实:一旦抛出异常,hibernate会话应该关闭并重新打开(从会话中),这使

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

  • 查找实体
  • 如果找到了,请退回
  • 否则将持久化实体
  • 如果一切正常,请退回
  • 如果发生唯一约束冲突,请尝试再次查找实体并返回它 问题产生于这样一个事实:一旦抛出异常,hibernate会话应该关闭并重新打开(从会话中),这使得步骤5无效,但我仍然希望将此逻辑封装在服务层中(而不是让它驻留在DAL或WS中)

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

    提前谢谢

    更新
    我想到的解决办法如下:
    将阶段3重构为包范围的服务,该服务具有单个ensureExists方法(带有泛型),该方法接受该类型的Dao和实体,并具有
    REQUIRES\u NEW
    的传播。此方法将尝试持久化,如果失败,当然会抛出一个异常,该异常将在原始服务中捕获,如果抛出该异常,它将尝试持久化。
    我希望得到一些反馈,了解如何以其他方式实现此功能。

    如果几天内没有人提出其他建议,我将用代码示例将其作为答案发布并接受。

    要查找实体,您可以使用criteria api+reflection填充所有重要属性并按示例对象搜索。 为了解决一致性问题,考虑悲观锁定。 加载时,只需在该对象上设置锁,并在所有事务完成后释放该锁。
    不确定这是否是性能方面的最佳选择,但您不应该在这里遇到例外情况。

    我可能错了,但我认为如果“查找”步骤需要条件(索引列上的单列条件除外),您将无法使用悲观锁定。感谢您的回答。实际上,我不想使用悲观锁定,因为它将是性能杀手。我认为这是乐观锁定的经典用例,但我只需要为最终用例做准备,我会按照您的计划做,除了我会将步骤1到4放在带有REQUIRES_NEW的服务中。@JB Nizet为什么您认为步骤1、2、4需要放在事务中?此外,在我看来,逻辑上只有步骤3处于不同的抽象级别,因此有理由让它位于不同的服务中。所有其他步骤都是相同的抽象级别(我想),我只是发现更清楚的是有一个“getOrCreate”方法,它可以抛出异常,如果我想的话,我可以从外部重试。它还将重试逻辑(可以完全通用,提取到代理或拦截器)与特定用例分离。它还允许对创建的实体执行其他操作,而不仅仅是返回它。在您的系统中,将找到您获得的实体,如果创建了实体,将其分离。