4

I have a project on Spring boot and tried to use @Transactional and coroutines and got an error

org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException.

Is it possible to use @Transactional and coroutines now?

override suspend fun invoke() {
    val result = withContext(Dispatchers.IO) { deactivate() }
} 

@Transactional
private suspend fun deactivate(): Int {
    //data base call 1
    //data base call 2
    // ...
}

3 Answers 3

3

You can't start coroutines that do transactional work on a different thread during a @Transactional method call.

@Transactional leads to code being intercepted. Before and after deactivate(), the transaction-related code will be called for you. Because the coroutines could be launched on a different thread, they will be launched outside of these transaction calls.

Relevant StackOverflow topic: Spring - @Transactional - What happens in background?

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, very much. Is there some workaround if I need to use transactions and coroutines?
You can call a coroutine and wait for it until it is done in that function.
2

Since version 5.3.0, support for suspending functions annotated with @Transactional has been added

Release notes: https://github.com/spring-projects/spring-framework/releases/tag/v5.3.0

Commit:
https://github.com/spring-projects/spring-framework/commit/5429c7afebaa3255ea80197224023c29c7d552ec

And since version v6.1.0-M5, compatibility of suspending functions with Spring AOP has been added:

https://github.com/spring-projects/spring-framework/releases/tag/v6.1.0-M5

Commit:
https://github.com/spring-projects/spring-framework/commit/c8169e5cad0bd616e251aa9c004eb2cdca081a59

Issue:
https://github.com/spring-projects/spring-framework/issues/22462

Comments

0

The reason to wrap a method in a transaction is to ensure that the method is atomic at a database level, and when there is a failure the whole transaction is reverted as if it never happened.

By breaking out of the transaction, using coroutines, you break the atomicity of the method if you do any other database actions, and when there is a failure those actions of the coroutine will not be reverted.

I hope you will be careful when using this (anti-) pattern!

1 Comment

While I would agree that Spring has complicated support for @Transactional and coroutines (it's getting better), using coroutines for transactional operations is NOT an anti-pattern. So long as the same database connection continues to be used, coroutines aren't a problem. R2DBC already has great support for this concurrency model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.