我正在编写一个系统,其中包含一个名为Voucher
的hibernate管理实体,该实体有一个名为serialNumber
的字段,该字段为唯一存在的有效保留唯一编号凭证实例的副本。数据库表中可能还有旧的无效副本,这意味着数据库字段可能不会被声明为唯一。
保存新的有效凭证实例(需要新的序列号)的操作首先在适当的实体上同步。此后整个过程被封装在一个事务中,新值由JPQL
SELECT MAX(serialNumber) + 1 FROM Voucher
该字段从查询中获取结果,此后保存实例,刷新会话,提交事务,代码最终离开同步块。
尽管如此,数据库有时(如果很少)最终会得到带有重复序列号的凭证。
我的问题是:考虑到我对同步和事务处理非常有信心,我是否应该知道我已经错过的hibernate,或者我应该回到另一个调试会话,尝试找到导致问题的其他原因?
运行保存过程的服务是在tomcat6上运行的Web应用程序,由Spring的HttpRequestHandlerServlet
管理。数据库连接由C3P0池化,运行非常基于默认的配置。
我很感激任何建议
由于
答案 0 :(得分:0)
您可以使用MultipleHiLoPerTableGenerator:它会在当前事务之外生成@Id
。
答案 1 :(得分:0)
您无需调试即可查找原因。在多线程环境中,它很可能会发生。您正在从表中选择最大值。因此,假设TX1读取最大值a
并插入序列号为a+1
的行;在此阶段,如果任何TX2读取DB,则最大值仍为a
,因为TX1尚未提交其数据。因此,TX2也可以插入序列号为a+1
的行。
要避免此问题,您可能决定更改数据库的隔离级别或更改获取序列号的方式(这完全取决于项目的环境)。但一般来说,我不建议更改隔离级别,因为这样的问题需要付出太多努力。