如何基于具有并发用户的数据库寄存器创建序列号

时间:2015-03-05 19:40:33

标签: java oracle java-ee jpa concurrency

所有这些都发生在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在并发问题发生时进行新的插入。我相信在这种情况下有更好的方法来处理并发性,但我想不出另一种解决它的方法。

4 个答案:

答案 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)

您可以通过多种方式处理同步问题。

  1. 你的B序列取决于你给出的A id。因此,您的查询将类似于从B中选择max(B),其中B.A =?。
  2. 现在让我们说你有B10。将A的值放在某个集合上,可以是A和最大值为B的映射。使用同步从此映射中获取/添加值。
  3. 每当您想在地图中使用新的A-B组合时,请先检查它是否存在。如果有,请等待并在指定时间后重试,以确保您拥有更新的记录。
  4. 从第2点开始,在将B10作为当前值后,递增并插入对应A的B11并删除映射条目,因此下一个线程将查询并获取该A的B11。
  5. 希望有所帮助。

答案 3 :(得分:0)

如果它是使用另一列而不是PK的选项,您可以查看使用带有@OrderColumn注释的List:

  

保持对值的连续(非稀疏)排序   订单栏

虽然基于零,但它确实具有自动更新以反映任何插入,删除等的优势。

https://docs.oracle.com/javaee/6/api/javax/persistence/OrderColumn.html