2012-01-18 62 views
0

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

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

问题的事实,一旦有异常抛出Hibernate的Session应该关闭并重新打开(从Session的documentation),这使得第5步无效,但我还是想封装在服务层这一逻辑(出现并没有它驻留在DAL或WS中)。

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

预先感谢

更新
溶液我想到如下:
重构阶段3到封装作用域服务具有单一ensureExists方法(使用泛型),它接受所述道这种类型和实体,并具有REQUIRES_NEW的传播。这个方法会尝试持久化,如果失败,当然会抛出一个将被原始服务捕获的异常,并且如果该异常被抛出,它将尝试持久化。
我很想谈谈如何以其他方式实现这一点。
如果没有人会在几天内另外提出建议,我会以代码示例的形式发布此答案并接受它。

+0

我会按照你的计划去做,除非我将步骤1到步骤4放在REQUIRES_NEW的服务中。 – 2012-01-20 07:12:58

+0

@JB Nizet为什么你认为步骤1,2,4需要进行交易?另外,在我看来,逻辑上只有第3步处于不同的抽象层次,所以有理由让它坐在不同的服务中。所有其他步骤都具有相同的抽象级别(我认为)。 – Ittai 2012-01-20 13:07:34

+0

我刚刚发现它有一个“getOrCreate”方法,它可以抛出异常,并且如果我想从外部重试,可以更清晰。它也将特定用例的重试逻辑(可以完全通用,提取给代理或拦截器)分离出来。而且它还允许使用创建的实体执行其他操作,而不仅仅是返回它。在你的系统中,你得到的实体被连接,如果被创建,则被分离。 – 2012-01-20 13:12:52

回答

0

要找到实体,您可以使用条件api + reflection来填充所有重要属性并按样本对象进行搜索。 要解决协调问题,请考虑悲观锁定。 当你完成加载时,只需在该对象上加锁,并在所有事务完成后释放此锁。 不知道这是否是最好的选择,但你永远不应该在这里例外。

+0

我可能是错的,但我认为在“find”步骤需要条件(索引列上的单列列除外)的情况下,您将无法使用悲观锁定。 – 2012-01-18 22:55:47

+0

谢谢你的回答。我其实不想使用悲观锁定,因为它会成为性能杀手。我认为这是一个乐观锁定的经典用例,但我只需要为该最终用例做好准备 – Ittai 2012-01-19 11:04:16