How to handle Spring transactions inside coroutines? - spring

It is known that Spring transactions are tied to threads: there are thread locals specific for an ongoing transaction. And transactions know nothing about coroutine context. So what if I would like to call a #Transactional method from inside a coroutine: is it safe?
Imagine we have a method inside JobProcessor bean processing a job list. Each job is processed inside async{}. And I would like to update DB after every successful or failed processing using #Transactional methods of bean JobService.
class JobProcessor {
fun process(jobs: List<MyJob>) =
jobs.map { job ->
async {
try {
....//processing
jobService.success(job)
} catch (t: Throwable) {
jobService.failure(job)
}
}
}
class JobService {
#Transactional
fun success(job: MyJob) {...}
#Transactional
fun failure(job: MyJob) {...}
}

First, please keep in mind that annotating bean methods with #Transactional will not suffice - make sure you enabled declarative transaction handling, e.g. by adding #EnableTransactionManagement to a #Configuration class or by using <tx-annotation-driven /> in XML config.
Regarding your question: There will only be a transactional context while executing Spring bean methods annotated with #Transactional when they are being invoked from a Spring bean outside of their containing class! Declarative transactions in Spring rely on AOP proxy classes being created for the #Transactional annotated classes by Spring. At runtime if a Spring bean A calls a #Transactional method on a Spring bean B, the call will be intercepted by an AOP proxy that transparently spawns a transaction, calls the original method of Spring bean B and commits or rollbacks this transaction afterwards.
Remember: Only external method calls that come in through the proxy will be intercepted – any self-invocation calls, as in your example this.process() calling #Transactional methods this.success() or this.failure() will not start any transaction – even if the method is annotated with #Transactional.

Related

Spring Boot - A bean referencing itself to trigger AOP #Async within the same class, not working

I want to within my own Bean call a method within itself which has its own #Async and #Transactional proxies but it isnt working.
public class MyClass {
private MyClass _selfWithProxy;
#PostConstruct
public void postContruct() {
_selfWithProxy = applicationContext.getBean(MyClass.class);
}
void myMethodA() {
_selfWithProxy.myMethodB()
}
#Async
#Transactinal
void myMethodB() {
//do stuff
}
However when I call myMethodA from another Bean the call to myMethodB does not intercept with an Async interceptor. I can see _selfWithProxy is a proxy bean, and the proxy activates but there are is no Async interceptor in the chain.
When I call myMethodB from another bean the #Async works, so I know it is setup correctly
Self invocation won't work for #Async. I believe that is because the proxy (your code + AOP advice) object calls your methodA on the target object (just your code) which then calls it's own methodB which isn't advised by AOP. In general I would not advise having spring bean methods call other methods of the same bean.
"#Async has two limitations:
It must be applied to public methods only.
Self-invocation — calling the async method from within the same class — won't work.
The reasons are simple: The method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly."
https://www.baeldung.com/spring-async

Whether and When Spring Lock Table if Method Annotated with Transactional

This question comes from that, if I have a methodA, and methodB in classA like below
public class classA {
public void methodA() {
// some code
...
// time to deal with db
methodB();
}
#Transactional
public void methodB() {
// insert a record
throw new RuntimeException("testing");
}
}
In classB Directly call methodA, there will be no transactional effect on methodB(this is to say spring will not rollback the insert operation even RuntimeException occurred).
When I move the #Transactional from methodB to methodA, and call methodA again, the #Transactional annotation works.
However, if I have really a lot of work to do in methodA, will spring lock the table during the total execution time?
Well, I will add a new class(i.e. classC) and move methodB(annotated with Transactional) to the new class as workaround.
It is the limitation of Springs AOP that #Transactional will not have effect if the method is called within the same class.
Refer to #Transactional method called from another method doesn't obtain a transaction
Spring doesn't handle transaction by itself. #Transactional annotation lets Spring's proxy class to inject transaction begin and commit/rollback methods around your original method.
Proxy wrapper will only be called if you invoke annotated method from outside the classes. Local method call will not use proxy class. So, call from method A to method B will not use transactional features.
Secondly, Spring will simply delegate the transaction handling to underlying database driver. Whether your table acquires a lock or not will be determined by your driver documentation and (atomicity and isolation level) settings.

#Transactional in a service class with no call to database

When a service class has no implementation of Jpa repository ,My understanding is that it is wrong to annotate it with Transactional, for example this service class with should not have #Transactional
#Service
public class BillingAddressServiceImpl implements BillingAddressService {
public BillingAddress setByUserBilling(UserBilling userBilling, BillingAddress billingAddress) throws DataAccessException
{
billingAddress.setBillingAddressName(userBilling.getUserBillingName());
billingAddress.setBillingAddressStreet1(userBilling.getUserBillingStreet1());
billingAddress.setBillingAddressStreet2(userBilling.getUserBillingStreet2());
billingAddress.setBillingAddressCity(userBilling.getUserBillingCity());
billingAddress.setBillingAddressState(userBilling.getUserBillingState());
billingAddress.setBillingAddressCountry(userBilling.getUserBillingCountry());
billingAddress.setBillingAddressZipCode(userBilling.getUserBillingZipCode());
return billingAddress;
}
}
The Transactional annotation stands for declaring the database transaction handling of Spring bean methods.
Since your service method is not working with the database it makes no sense to declare a transaction handling.
Transactional annotations are only used with method or classes that makes calls to database,one of the uses of transactional annotation is rollback - which means when we make call to a database there would be a recording of the intermidiate state between the successful call and its original state, this is so that in the case of a failed call the system does not crash but is able to return to its original state

Spring managed transactions #Transactional annotation

Propagation setting is REQUIRED.
#Transactional(propagation = Propagation.REQUIRED)
Transaction is read/write.
In which scenario those are used? Please give me explain with example
Spring transaction default is
#Transactional(propagation = Propagation.REQUIRED)
So you do not need to specify the propagation property.
So, What does it mean by #Transactional annotation for a spring component ?
Spring framework will start a new transaction and executes all the method and finally commit the transaction.
But If no transaction is exists in the application context then spring container will start a new transaction.
If more than one method configured as Propagation.REQUIRED then transactional behavior assigned in a nested way to each method in logically but they are all under the same physical transaction.
So, What is the result ?
The result is if any nested transaction fail, then the whole transaction will fail and rolled back (do not insert any value in db) instead of commit.
Example:
#Service
public class ServiceA{
#Transactional(propagation = Propagation.REQUIRED)
public void foo(){
fooB();
}
#Transactional(propagation = Propagation.REQUIRED)
public void fooB(){
//some operation
}
}
Explanation :
In this example foo() method assigned a transactional behavior and inside foo() another method fooB() called which is also transactional.
Here the fooB() act as nested transaction in terms of foo(). If fooB() fails for any reason then foo() also failed to commit. Rather it roll back.
This annotation is just to help the Spring framework to manage your database transaction.
Lets say you have a service bean that writes to your database and you want to make sure that the writing is done within a transaction then you use
#Transactional(propagation = Propagation.REQUIRED)
Here is a small example of a Spring service bean.
#Service
class MyService {
#Transactional(propagation = Propagation.REQUIRED)
public void writeStuff() {
// write something to your database
}
}
The Transactional annotation tells Spring that:
This service method requires to be executed within a transaction.
If an exception gets thrown while executing the service method, Spring will rollback the transaction and no data is written to the database.

Use Spring #Transactional in Scala

We have a mixed Java and Scala project, which uses Spring transaction management. We are using the Spring aspects to weave the files with #Transactional annotated methods.
The problem is, that the Scala classes aren't woven with the Spring transaction aspects. How can I configure Spring to regard the transaction in Scala?
Spring needs your transaction boundary to begin with Spring-managed beans, so this precludes #Transactional Scala classes.
It sounds like the simple solution is to make service facades which are #Transactional Java classes instantiated as Spring beans. These can delegate to your Scala service/core code.
A Scala-only solution is to use Eberhard Wolff's closure that creates a manual transaction. Usage:
transactional() {
// do stuff in transaction
}
https://github.com/ewolff/scala-spring/blob/master/src/main/scala/de/adesso/scalaspring/tx/TransactionManagement.scala
https://github.com/ewolff/scala-spring/blob/master/src/main/scala/de/adesso/scalaspring/tx/TransactionAttributeWithRollbackRules.scala
Found here: http://www.slideshare.net/ewolff/scala-and-spring (slide 41)
License: Apache
There is nothing special about Spring's #Transactional support in Scala and you can use it without any Java code. Just make sure that you have "pure" traits for beans, which implementations would use #Transactional annotation. You should also declare a bean with PlatformTransactionManager type (if you are using .xml-based Spring configuration, you should use "transactionManager" for bean name, see EnableTransactionManagement's JavaDoc for details). Also, if you are using annotation-based configuration classes, be sure that these classes are placed in their own dedicated files, i.e. don't place any other classes (companion object is OK) in the same file. Here is simple working example:
SomeService.scala:
trait SomeService {
def someMethod()
}
// it is safe to place impl in the same file, but still avoid doing it
class SomeServiceImpl extends SomeService {
#Transactional
def someMethod() {
// method body will be executed in transactional context
}
}
AppConfiguration.scala:
#Configuration
#EnableTransactionManagement
class AppConfiguration {
#Bean
def transactionManager(): PlatformTransactionManager = {
// bean with PlatformTransactionManager type is required
}
#Bean
def someService(): SomeService = {
// someService bean will be proxied with transaction support
new SomeServiceImpl
}
}
// companion object is OK here
object AppConfiguration {
// maybe some helper methods
}
// but DO NOT place any other trait/class/object in this file, otherwise Spring will behave incorrectly!

Resources