【问题标题】:Spring hibernate insert race condition春季休眠插入竞争条件
【发布时间】:2013-03-30 06:44:58
【问题描述】:

我目前遇到了 Spring Hibernate 的竞争问题(服务和 daoImpl 类上的注释事务)。这是我遇到的情况:

表格:

  • 设备类型:id(序列号)、名称
  • 设备:id(序列号)、device_identifier、device_type_id、ip_address

注意 device_identifier 和 device_type_id 是唯一的

这是我在多线程进程中的一个 sn-p:

    if(deviceDao.findByIdentifierAndTypeId(identifier, typeId) == null){
        Device newDevice = new Device();
        newDevice.setIdentifier(identifier);
        newDevice.setTypeId(typeId);
        deviceDao.add(newDevice);
    }

所以发生的情况是,我有一个服务器通过 websockets 监听设备(这里可能不是重要的细节),服务器会首先尝试确定设备是否已经在数据库中,如果没有,则创建设备记录已经找到了。

现在我遇到的问题是服务器可以处理来自设备的多条消息(每个来自设备的消息创建一个线程),因此是竞争条件。

所以想象一下:

设备A一个接一个地发送两条消息:

    Sends hello message              Sends "here is my ip" message
             |                                    |
             |                                    |
             |                                    |
    does not see device in DB                     |
        tries to insert                does not see device in DB
             |                              tries to insert
          Insert completed                        |
                                Failed to insert (Unique key constraints not met)

很明显,当第二次插入设备时,唯一性约束会导致失败。但我在想,当第一次插入完成时,Spring 将能够将其拾取并知道当第二个线程再次尝试插入时它不需要。但是,尽管我尝试了各种传播和隔离模式,但这并没有发生。我一定错过了一些非常基本的东西,请指出我如何解决这个问题的正确方向。提前感谢您的回复。如果需要/要求,我会提供更多信息。

【问题讨论】:

    标签: spring hibernate postgresql transactions race-condition


    【解决方案1】:

    这是设计行为。默认情况下,您只会看到已提交的行(READ COMMITTED 隔离级别)。对于外部进程,您可以将未提交的行视为尚未出现在数据库中

    最好的解决方案是捕获唯一约束违规并重试(最好有延迟)。您还可以将隔离级别设置为读取未提交,但这可能会产生其他竞争条件,我不建议这样做。

    【讨论】:

    • 谢谢,这就是我最终做的。起初它似乎不是一种优雅的处理方式,但当我仔细考虑它时,除了重试刷新唯一ID之外真的没有其他方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-14
    相关资源
    最近更新 更多