Spring hibernate插入竞争条件

时间:2013-04-08 08:43:51

标签: spring hibernate postgresql transactions race-condition

我目前遇到Spring Hibernate的竞争问题(通过服务和daoImpl类的注释进行事务处理)。这是我遇到的:

表:

  • 设备类型:id(序列),名称
  • 设备:id(serial),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就可以把它拿起来,并且知道当第二个线程再次尝试插入时它就不需要了。但是,尽管我尝试了各种Propogation和Isolation模式,但这并没有发生。我必须遗漏一些非常基本的东西,请指出我如何解决这个问题的正确方向。提前感谢您的回复。如果需要/我要求,我会提供更多信息。

1 个答案:

答案 0 :(得分:1)

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

最佳解决方案是捕获唯一约束违规并重试(理想情况下是延迟)。您也可以将隔离级别设置为读取未提交,但这可能会创建其他竞争条件,我不建议这样做。