有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java按唯一名称查找实体,如果找不到,则创建,填充,然后保存。由于并发性,两个事务保存了两次

我偶然发现了一个问题,我们无法通过锁定策略和事务隔离来解决这个问题。我们有一个应用程序,它将消息推送到活动MQ。这个队列有一个常量侦听器

我们在这个消息中有一个状态报告,应该更新或创建它(如果没有)。报表是按唯一名称(“applicationId”)查询的,但这不是主键,也没有唯一约束

报告随后被填充/更新并保存到数据库中

如果找不到实体,我无法立即保存/持久化实体;如果找不到匹配的报告,我无法填充创建的实体。我必须坚持在用数据填充报告后保存报告。这是因为外部系统将每隔5分钟左右提取一次基础表,然后将其删除

问题是:我在几毫秒内收到了3条相同applicationId的传入消息。在前两条传入消息之后,数据库中有两个报告具有相同的applicationId,第三个更新请求失败,因为find查询需要一个结果

这是代码的摘录:

    @Override
    public Report saveReportinDB(APPLICATION application)
    {
        // check if already exists by key applicationId
        Report report =  this.reportRepository.findOneByApplicationID(application.getAppId());

        if (report == null)
        {
            report = new Report();
        }  

       /*this takes longer, so the next application is comming 
         in and does not find a report with the same applicationId
         within the db because the report which is filled 
         at the moment is not yet persisted*/

        fillReportWithData(application, report);

        report = ReportRepository.save(report);

有没有办法解决这个问题


共 (1) 个答案

  1. # 1 楼答案

    在“查找是否使用了应用程序id”和“完成保存应用程序id的工作”之间运行的代码需要是原子代码,即位于两台服务器共用的锁内

    就我个人而言,我会尝试让数据库服务于该功能(通过在“挂起”状态下写入应用程序记录),但如果你做不到这一点,那么在应用程序id上键入一个单独的锁记录似乎是合适的