Mari
Mari

Reputation: 213

Spring Boot JPA save() method trying to insert exisiting row

I have a simple kafka consumer that collects events and based on the data in them inserts or updates a record in the database - table has a unique ID constraint on ID column and also in the entity field.

Everything works fine when the table is pre-populated and inserts happen every now and then. However when i truncate the table and send a couple thousand events with limited number of ID (i was doing 50 unique ID within 3k events) then events are processed simultaneously and the save() method randomly fails with Unique constraint violation exception. I debugged it and the outcome is pretty simple.

event1={id = 1 ... //somedata} gets picked up, service method saveOrUpdateRecord() looks for the record by ID=1, finds none, inserts a new record.

event2={id = 1 ... //somedata} gets picked up almost at the same time, service method saveOrUpdateRecord() looks for the record by ID=1, finds none (previous one is mid-inserting), tries to insert and fails with constraint violation exception - should find this record and merge it with the input from the event based on my conditions.

How can i get the saveOrUpdateRecord() to run only when the previous one was fully executed to prevent such behaviour? I really dont want to slow kafka consumer down with poll size etc, i just want my service to execute one transaction at a time.

The service method:

    public void saveOrUpdateRecord(Object input) {
    Object output = repository.findById(input.getId));

    if (output == null) {
        repository.save(input);

    } else {
        mergeRecord(input, output);
        repository.save(output);

    }
}

Will @Transactional annotaion on method do the job?

Upvotes: 0

Views: 871

Answers (1)

krishnkant jaiswal
krishnkant jaiswal

Reputation: 591

Make your service thread safe. Use this:

    public synchronized void saveOrUpdateRecord(Object input) {
    Object output = repository.findById(input.getId));

    if (output == null) {
        repository.save(input);

    } else {
        mergeRecord(input, output);
        repository.save(output);

    }
}

Upvotes: 1

Related Questions