Bolto Cavolta
Bolto Cavolta

Reputation: 443

Spring hibernate insert race condition

I am currently having a race issue with Spring Hibernate (transaction by annotation on service and daoImpl classes). Here is what I have encountered:

Tables:

Note device_identifier and device_type_id are together unique

Here is a snippet of what I have in a multi-thread process:

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

So what happens is that, I have a server that listens to devices via websockets (probably not important detail here) and the server would first try to determine if the device is already in the database and the device record is created if not already found.

Now the problem I have is that the server can process multiple messages from a device (a thread is created per message from a device) and therefore the race condition.

So imagine this:

Device A sends two messages one after the other:

    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)

Obviously when the device is to be inserted for the second time, the unique constraint will cause the failure. But I was thinking that when the first insert is completed, Spring would be able to just pick it up and know that when the second thread tries to insert again it wouldn't need to. But this didn't happen despite of various Propogation and Isolation modes that I tried. I must be missing something very fundamental and please point me to the right direction on how I can fix this. Thanks in advance for your replies. I will provide more info if needed/requested.

Upvotes: 2

Views: 2791

Answers (1)

Chris Travers
Chris Travers

Reputation: 26464

This is behavior by design. By default you are only going to see committed rows (READ COMMITTED isolation level). You can treat uncommitted rows as not yet present in the database for outside processes.

The best solution is to catch the unique constraint violation and retry (ideally with a delay). you could also set down the isolation level to read uncommitted, but this could create other race conditions and I would not recommend that.

Upvotes: 2

Related Questions