I am trying to analyze a situation where I have two classes. One class is ProcessImpl which is starting point and internally calls other child transactions.I dont know whats going wrong. The processImpl is importing some stuff and writing related data to database.
Specs
Spring-orm version : 3.2.18.RELEASE.
JDK version : 1.8.
Db : H2 (on any db same performance is recorded).
Issue
If I remove @Transactional
from ProcessImpl.processStage()
the process takes ~ 50 seconds
If I keep @Transactional
from ProcessImpl.processStage()
the process takes ~ 15 minutes.
Dont know why this is happening.
I have been trying to solve this issue since long but no luck. Please have a look at code below.
Requirement:
The complete processStage()
should complete or rollback completely, even if one of child transactions fail.
Fyi : I also get lot of messages like : "Participating in existing transaction". Tried to get over this by adding propagation=Propagation.NESTED
to processStage()
but did not work.
ProcessImpl Class.
public class ProcessImpl {
/*This is the big transaction that calls other transactional stuff from MyServiceImpl
* This is starting point you can say for the process...
*
* If we remove @Transactional from here the process is lightning fast
* With transactional : 15minutes
* Without transactional : 50 seconds
* */
@Transactional
public void processStage(){
MyServiceImpl mp = new MyServiceImpl();
//do some stuff
mp.doWork1();
//do more work
mp.doWork2();
}
}
MyServiceImpl Class
class MyServiceImpl{
@Transactional
public void doWork1(){
Object o = doChildWork();
// and more stuff
//calls other class services and dao layers
}
@Transactional
public void doWork2(){
//some stuff
doChildWork2();
doChildWork();
//more work
}
@Transactional
public Object doChildWork(){
return new Object(); //hypothetical, I am returning list and other collection stuff
}
@Transactional
public Object doChildWork2(){
return new Object(); //hypothetical, I am returning list and other collection stuff
}
}
Also, here will I get self invocation issue, which is not advisable in Transactional?
It is hard to guess what exactly is happening in your code, however these are the possible problems:
Lock on DB level.
This could happen when you update the same DB object within doWork1()
and doWork2()
. Since both of the methods are performed within one transaction the updates done inside doWork1()
will not be committed until doWork2()
is completed. Both the methods might try to lock the same DB object and wait for it. Technically it could be any DB object: row in a table, index, whole table, etc.
Analise your code and try to find what could be locked. You can also look into DB transaction log while the method is running. All popular DBs provide functionality that helps to find problematic places.
Slow down during Hibernate context refresh. In case when you update too many objects ORM engine (lets say Hibernate) has to sink them and keep them in memory. Literally Hibernate must have all old states and all new states of updated objects. Sometimes it does this not in an optimal way.
You can indicate this using debug. Try to find the slowest place and check what exactly is being invoked there. I might guess that it slows down when hibernate updates state of the cache.
One more issue. I see that you create MyServiceImpl
using constructor during processStage()
. I'd recommend you to replace this code by spring autowiring. First of all the way you're using it is not the way it was designed to be used, but theoretically that could also somehow influence on the execution.
will I get self invocation issue, which is not advisable in Transactional?
No, it will work just fine ignoring all annotations. Calls of doChildWork()
and doChildWork2()
inside doWork2()
will be treated as standard java calls (spring is not able to add any "magic" to them as long as you're invoking them directly).