I try using the parallelStream()
in DAO with Spring @Transactional
annotations and get so problem:
@Transactional
public void processCollection(Collection<Object> objects) {
objects.parallelStream()
.forEach(this::processOne); //throw exception
}
@Transactional
public void processOne(Object o) {
...
}
Works correct:
@Transactional
public void processCollection(Collection<Object> objects) {
objects.stream()
.forEach(this::processOne); //work correctly
}
@Transactional
public void processOne(Object o) {
...
}
Exception:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)
How can I use @Transactional
annotated methods by parallelStream()
?
Update Why this happen Spring transaction manager and multithreading But I hope spring 4 with java 8 support can provide some solution for this. Any ideas?
Well, I have a guess consists of several guesses:
session-per-thread
;Object
you wrote in example is in fact some entity that uses lazy loading;processOne()
method uses entity properties that are loaded lazily;parallelStream()
has no session available (probably in ThreadLocal
, don't remember how technically sessions are bound to threads);That altogether causing the problem you have. The behavior looks quite strange to me, so I suggest to do the following:
parallelStream()
again;parallelStream()
.Alternative way to go: detaching all list elements from session before doing parallelStream()
.
Although as Marko wrote in comments, Session
is not thread-safe, so that means you have to get rid of Session
usage either by removing lazy loading, or by detaching all entities from session.
The problem is not with parallel stream. In spring transaction is created using AOP.
When your processCollection method is executed spring create a proxy object of this and transaction is started.
Calling another method in same class, spring will not run that method in New transaction even if you specified @Transaction .
To get it run move that method process() to new service and then execute your problem. Your program will work fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With