Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using @Transactional for thread safety

I have a question about how @Transactional annotation alone manages code and transactions execution. Given a correctly setup Spring application and the following code:

@Transactional
public void withdraw(int amount) {
    if(isEnoughFunds(amount)) {
        decreaseFunds(amount);
    }
}

Is it possible for the following scenario to occur:

  • funds == 100; amount == 100
  • thread A enters withdraw / transaction A starts
  • thread A executes isEnoughFunds which evaluates to true
  • thread B enters withdraw / transaction B starts
  • thread B executes isEnoughFunds which evaluates to true
  • thread A executes decreaseFunds / thread A locks db record
  • thread B waits for thread A to commit transaction and release write lock
  • thread A exits withdraw / transaction A commits
  • thread B executes decreaseFunds / thread B locks db record
  • thread B exits withdraw / transaction B commits
  • funds == -100

If this is possible how would you prevent that?

like image 751
user1700598 Avatar asked Sep 26 '12 14:09

user1700598


People also ask

Is @transactional thread safe?

Spring uses the underlying database implementation for transactions, so they are as thread safe as the underlying database can be. Transaction isolation is a different issue from thread-safety.

What is @transactional annotation used for?

The @Transactional annotation is the metadata that specifies the semantics of the transactions on a method. We have two ways to rollback a transaction: declarative and programmatic. In the declarative approach, we annotate the methods with the @Transactional annotation.

Can we use @transactional on private methods?

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings.

Can we use @transactional in repository?

The usage of the @Repository annotation or @Transactional . @Repository is not needed at all as the interface you declare will be backed by a proxy the Spring Data infrastructure creates and activates exception translation for anyway.


1 Answers

Yes, it is possible, depending on the isolation level. To prevent it, you can explicitly obtain a read lock from the database before calling ifEnoughFunds(). The lock will be released at the end of the transaction. In this scenario, thread B will always wait for thread's A transaction to commit before checking.

like image 60
Assen Kolov Avatar answered Oct 14 '22 03:10

Assen Kolov