所有这些都发生在java Web应用程序中,在持久层中使用JPA。 我有实体A和B.A有很多B.
用户想要一个数字来识别Bs,这将有助于他们使用该系统。为此,我们使用了B的主键。 pk是一个简单的Oracle序列。 一段时间后,用户不喜欢生成的数字。他希望B的数字是连续的,但在A的每个例子中都是如此。
前:
A 1 B1
A 1 B2
A 1 B3
A 2 B1
A 2 B2
依旧......
我想到了这个(天真的)解决方案:
为新B的号码创建一个新的colunm
用B的新数字和A的FK创建一个唯一的子句。
- 创建B的新实例时,在给定A实例的情况下,检查数据库中最后一个B的数量。
- 由于多个用户可能会创建B的实例,因此在插入B时,请尝试捕获。如果多个用户插入具有相同编号的B(对于相同的A实例),则捕获从数据库抛出的异常。
- 如果抛出异常,请尝试再次插入新号码。
我的问题的原因是我发现这个解决方案非常笨拙,因为它依赖于try-catch在并发问题发生时进行新的插入。我相信在这种情况下有更好的方法来处理并发性,但我想不出另一种解决它的方法。
答案 0 :(得分:1)
@Transactional
public void createB(informations){
A a = informations.getA()
session.get(A.class, a.getId(), LockMode.READ) //BD Lock here, no cluster, no Java
//Only who got the lock first get here, anyone else waits for the lock release
Long lastSequential = bService.findLastSequential()
B newB = informations.getB()
newB.setSequential(lastSequential + 1)
session.persist(newB)
//The lock is released when the transaction finishes and then the next
//thread awaiting on the session.get may get a new lock and resume its
//execution. That way only one thread at time will be able to execute
//the critical area where the sequential is being created.
}
答案 1 :(得分:0)
你在这里处理一个相当独特的情况,我会说......
如果你真的需要这样做,尝试/ catch / retry似乎不是一个好的解决方案,因为根据并发用户的数量,单个重试可能会再次导致数据库失败并且你有再次重试,循环继续。
我想你可以尝试看一下代理键。这里描述的“查找表”方法似乎是您需要的一个很好的起点:https://dba.stackexchange.com/questions/6108/should-every-table-have-a-single-field-surrogate-artificial-primary-key
还有一些关于hibernate和代理键的文章/帖子: - Hibernate : Opinions in Composite PK vs Surrogate PK - http://richmurnane.blogspot.de/2007/09/hibernate-and-surrogate-keys.html
希望它有所帮助!
答案 2 :(得分:0)
您可以通过多种方式处理同步问题。
希望有所帮助。
答案 3 :(得分:0)
如果它是使用另一列而不是PK的选项,您可以查看使用带有@OrderColumn
注释的List:
保持对值的连续(非稀疏)排序 订单栏
虽然基于零,但它确实具有自动更新以反映任何插入,删除等的优势。
https://docs.oracle.com/javaee/6/api/javax/persistence/OrderColumn.html