Java – Spring JPA atomic get or create method

Spring JPA atomic get or create method… here is a solution to the problem.

Spring JPA atomic get or create method

I’m using Spring Boot and JPA (with Hibernate).

I have a method (in my service) :

  • Check if a specific entity already exists in the database (e.g. me
    You need to check if there are already users. For this, I use a custom JPQL
    Query my JPA repository.
  • After this, if the previous step doesn’t produce any results, I’ll create an entry in the database (using the Save JPA repository method) while I also need to create another entity (for, for example, some user-related information stored in a separate table).
    So, in this case, I’ll have two create queries (one for the user table and one for the information user table).
  • If step 1 already has some results, I obviously need to skip the insert step.

Obviously, I need to guarantee the atomicity of this method.

I have to avoid the risk of creating duplicate entries in the database for separate transactions.

Additional note: I can’t add some unique constraints on the Users table because there are some different combinations of this (for example, if the state is at a certain value or something similar, I can create the same user again).

I

tried to use @Transactional comments only for my method, but I noticed that wasn’t enough (using some stress tests I was able to create multiple rows in the database).

So now I’m confused.

What are the best practices for having an atomic approach?
Do I need to change the transaction isolation level? Do I need to use some locks?

I’m not a Spring expert, but I think it’s a common problem, but I can’t understand what the right approach is.

Basically I’m looking for atomic GET_OR_CREATE methods that use JPA (and JPA repositories).

Solution

IN THIS CASE, YOU NEED TO SET THE TRANSACTION ISOLATION LEVEL TO SERIALIZABLE, THAT IS, ONLY ONE TRANSACTION CAN ACCESS THE DATABASE. This can be done using the isolation property of the Transactional annotation:

@Transactional(isolation = Isolation.SERIALIZABLE)
public void yourMethod(){
    // ...
}

Read more about the topic here: https://www.baeldung.com/spring-transactional-propagation-isolation

Related Problems and Solutions