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.


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).