Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java .parallelStream() with spring annotated methods

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?

like image 724
VladS Avatar asked Apr 24 '14 10:04

VladS


2 Answers

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 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:

  • 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.

like image 67
Alexey Malev Avatar answered Oct 22 '22 21:10

Alexey Malev


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.

like image 31
Nadish Singla Avatar answered Oct 22 '22 21:10

Nadish Singla