2

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

表:

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

注意 device_identifier 和 device_type_id 一起是唯一的

这是我在多线程进程中的一个片段:

    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 将能够将其拾取并知道当第二个线程再次尝试插入时它不需要。但是,尽管我尝试了各种传播和隔离模式,但这并没有发生。我一定错过了一些非常基本的东西,请指出我如何解决这个问题的正确方向。提前感谢您的回复。如果需要/要求,我将提供更多信息。

4

1 回答 1

2

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

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

于 2013-05-15T01:02:10.920 回答