Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot , Spring data JPA concurrent access

I am trying to create a Restful API with Spring boot and Spring data JPA to do the CRUD operations. The database will be Oracle relational database.Now for concurrent access , If we only use spring transactions using @Transactional, will that serve our purpose of concurrent CRUD operations.

I see there are JPA Optimistic and pessimistic locking strategy version column. My specific question is , for concurrent CRUD operations do we need both Spring transactions and JPA locking strategy? OR only configuring Spring transactions accordingly will be sufficient?

like image 864
adiCool Avatar asked Jan 25 '23 14:01

adiCool


2 Answers

Optimistic lock is default strategy of JPA. Optimistic locking is can be used for most of the applications. Optimistic lock is much more easier and efficient. Pessimistic lock need to be used in cases like, where you need to know Collision before committing your transaction.

So you do not need to configure a locking strategy.

like image 26
Ahmet Amasyalı Avatar answered Jan 28 '23 03:01

Ahmet Amasyalı


Try to start with the following simple approach that IMO will be suitable in many cases: Optimistic locking with Spring Retry.

1) Add version property annotated with @Version to your entities (you can do it in base abstract entity class, for example, to simplify the process):

@Entity
public class MyEntity {

    @Id
    @GeneratedValue
    private Long id;

    @Version
    private Long version;

    // other stuff
}

In this case when you, for example, will update your entity then Hibernate will use the current value of version property in condition clause of update query, and increment this value to store the entity with it. For example this code of some service:

@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
    return myEntityRepository
           .findById(id)
           .map(target -> mapper.updateEntity(source, target));
}

will generate the following SQL queries:

1. select * from my_entities where id = ?; 
2. update my_entities set ..., version = <version value from query #1> + 1 where id = ? and version = <version value from query #1>;

So if another concurrent process manages to update this entity first, then your method fails with an exception (OptimisticLockException).

2) To manage to exceptions in that method, add @Retryable annotation to it (and @EnableRetry annotation on your config or application class):

@Retryable(maxAttempts = 2)
@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
    // ...
}

In this case, if an exception rises in that method it will be called again in a new transaction to repeat the operation.

Additional info:

  • Optimistic Locking in JPA
  • Guide to Spring Retry
  • My Spring Retry demo
like image 131
Cepr0 Avatar answered Jan 28 '23 03:01

Cepr0