gpt4 book ai didi

java - 插入新行,并通过简单计算增加最大值(并发问题)

转载 作者:行者123 更新时间:2023-11-30 06:57:45 25 4
gpt4 key购买 nike

在我的 java/spring/hibernate 应用程序中,我需要生成格式为 yyxxxxxxxx 的发票号码(yy - 当前年份,xxxxxxxx - 每年从 1 开始的编号序列,总共 10 位数字。)

例如,明年的第一个数字将为 1800000001。

我使用Oracle 11g Express版。该应用程序同时在 2 个 Tomcat 服务器上运行。

我不确定如何处理可能的重复项 - 或者更确切地说,违反唯一约束,因为 InvoiceNumber 列存在唯一约束。 (GenerateInvoiceNumbers 表中有 3 列 - ID(PK,自动递增)、InvoiceNumberCreatedOn。)

到目前为止,应用程序检索具有 max(ID) 的行,生成新的发票编号并插入新行。由于多个线程/服务器可能选择相同的 max(ID) 并因此生成/插入相同的发票编号,因此应用程序捕获 Spring 抛出的 DataIntegrityViolationException ,增加发票编号并保持尝试插入它直到成功(设置了一些max_attempts_limit)。它有效,但似乎不是一个干净的解决方案。

我考虑将发票编号生成逻辑放入存储过程中 - 应该可以对其加锁并一次只允许执行一次。但随后我将不得不处理一个不同的异常,这将使我达到现在的水平。

有没有更好的方法来解决这个问题?

编辑:虽然本质上我并不真正关心每个生成的数字。我只需要知道每年的最大发票数量即可生成下一个。我可以制作这样的结构:

ID, Year, LastNumber

如果当前年份行尚不存在,则执行INSERT,否则使用递增的LastNumberUPDATE - 这在并发环境中似乎更容易执行。

最佳答案

不要使用 max(id),创建 oracle 序列并从序列中获取下一个值 - select nextval。这是最可靠且不易出错的方法。即使您有 1 个应用程序,当多个线程尝试从数据库获取 max(id) 时,您也会发生竞争

或者,您可以对 1 个节点使用如下所示的内容:

synchonized (lock) {
long id = selectMaxFromDatabase(id);
id ++;
if (id % 2 != 0) {
id ++;
}
}

对于第二个节点:

synchonized (lock) {
long id = selectMaxFromDatabase(id);
id ++;
if (id % 2 == 0) {
id ++;
}
}

一个应用程序将插入奇数 ID,第二个应用程序将插入偶数 ID。

关于java - 插入新行,并通过简单计算增加最大值(并发问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41483993/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com