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:
- You have session management policy as
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;- Because of first point, threads, started for
parallelStream()
has no session available (probably inThreadLocal
, 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:
- Remove all lazy loading and try
parallelStream()
again; - If that succeeds, you'll have to load the entities completely before performing
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 anyother 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.
来源:https://stackoverflow.com/questions/23266866/java-parallelstream-with-spring-annotated-methods