问题
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?
回答1:
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.
回答2:
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