Mannualky
Mannualky

Reputation: 3

How can I prevent Race Condition

How can I prevent Race Condition in this method:

@Lock
 public boolean delete(int id) {
    someEntity byId = someRepository.findById(id).orElseThrow(() -> new NotFoundException());
    someRepository.delete(byId);
    return true;
}

I have done @Lock

@Aspect
@Component
@EnableAspectJAutoProxy
public class LockAspect {
    private final ReentrantLock reentrantLock;

public LockAspect() {
    reentrantLock = new ReentrantLock();
}

@Around("@annotation(com.example.aspect.Lock)")
public void aroundDelete(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    reentrantLock.lock();
    try {
        proceedingJoinPoint.proceed();
    } finally {
        reentrantLock.unlock();
    }
}

But this lock only blocks the app not really solves the problem the same with

Also I was thing about @Transactional(isolation=Isolation.REPEATABLE_READ) or @Transactional(isolation= Isolation.SERIALIZABLE) annotation above the delete method but I'm not sure if that will solve the problem. It is spring app.

Upvotes: 0

Views: 451

Answers (1)

Stanislav Bashkyrtsev
Stanislav Bashkyrtsev

Reputation: 15308

There are several ways of solving this, popular options are:

  1. Don't do a separate SELECT, just issue a DELETE. And if you get OptimisticLockException from Hibernate, then you know for sure the record didn't exist. It looks like you're using Spring Data, you can either create a @Modifying method for this or just use repo.getOne() instead of repo.findXxx().
  2. Use Repeatable Read isolation level - the database should return an error if another transaction updated the record concurrently. Eg. here are PostgreSQL docs (technically in PG this is a Snapshot isolation level though).
  3. Use pessimistic locking with select .. for update, this will not allow DML operations to proceed with the row until it's unlocked (transaction is finished).

Upvotes: 2

Related Questions