【问题标题】:Thread and DB Transaction issue - make a check in Java db safe for multiple threads线程和数据库事务问题 - 检查 Java 数据库是否对多线程安全
【发布时间】:2023-01-07 17:25:05
【问题描述】:

语境:

  • 带有 Spring JPA 和 MS SQL DB 的 Spring Boot 应用程序。
  • 使用保险号的用户注册流程
  • insuranceNumber 在 DB 中不是唯一的,但仅针对特定状态(PROSPECTIVE、PARTICIPANT)
  • 服务中有一个重复检查来检查这个
    REST Controller -> 
            RegistrationService  (@Transactional)
                - do duplicate check (select * from customer where status in (PROSPECTIVE,PARTICIPANT) and insuranceNumber = XYZ -> no results good)
                - insert new customer to DB

问题:

  • 如果经过测试,重复检查有效,但有时我有重复的 insuranceNumber 处于 PROSPECTIVE 状态
  • 假设:
    • 由于短时间内有多个 REST 请求,我有多个线程(假设有 3 个)
    • 线程 1“重复检查”- 一切正常
    • 线程 2“重复检查”- 一切正常(线程 1 尚未提交)
    • 线程 1 插入 do DB,提交 TX
    • 线程 2 插入 do DB,提交 TX ## 问题,现在具有相同保险号的客户处于相同状态
    • 线程 3“重复检查”- 失败 - 正如预期的那样

可能的解决方案:

  • 前端:防止这种多重请求。超出范围。我想从后端确定
  • DB:在 DB 站点(数据库触发器)上创建一些东西以再次进行相同的重复检查。感觉不对,因为它重复了重复检查的逻辑。还会引发与已经在 J​​ava 中引发的异常不同的异常
  • Java 代码:带有同步方法的 RegistrationService。会减慢每个人的注册速度。对我来说,只允许一个保险号码进入注册方式就足够了。

在那里更多的想法?玩弄数据库的隔离级别? 如果一个线程已经进入了具有相同保险号的方法,则防止进入注册方法?

【问题讨论】:

    标签: java spring spring-data-jpa


    【解决方案1】:

    唯一可靠的方法防止数据库中的重复是创建唯一索引,在您的特定情况下应该是filtered唯一索引:

    CREATE UNIQUE NONCLUSTERED INDEX CUSTOMERS_UK  
    ON CUSTOMERS(insuranceNumber)  
    WHERE status IN ('PROSPECTIVE','PARTICIPANT')
    

    另一个选项是:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多