Java.parallelStream() с spring аннотированными методами
Я пытаюсь использовать parallelStream()
в DAO с аннотациями Spring @Transactional
и получить такую проблему:
@Transactional
public void processCollection(Collection<Object> objects) {
objects.parallelStream()
.forEach(this::processOne); //throw exception
}
@Transactional
public void processOne(Object o) {
...
}
Правильно работает:
@Transactional
public void processCollection(Collection<Object> objects) {
objects.stream()
.forEach(this::processOne); //work correctly
}
@Transactional
public void processOne(Object o) {
...
}
Исключение:
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)
Как использовать @Transactional
аннотированные методы parallelStream()
?
Обновление
Почему это происходит Spring менеджер транзакций и многопоточность
Но я надеюсь, что Spring 4 с поддержкой java 8 может предоставить некоторое решение для этого. Любые идеи?
Ответы
Ответ 1
Ну, у меня есть предположение, состоящее из нескольких догадок:
- У вас политика управления сеансом как
session-per-thread
;
-
Object
, который вы написали в примере, на самом деле является некоторой сущностью, которая использует ленивую загрузку;
-
processOne()
метод использует свойства объекта, которые загружаются лениво;
- Из-за первой точки потоки, запущенные для
parallelStream()
, не имеют сеанса (возможно, в ThreadLocal
, не помните, как технически сеансы привязаны к потокам);
Это вызывает проблемы. Поведение выглядит довольно странно для меня, поэтому я предлагаю сделать следующее:
- Удалите всю ленивую загрузку и повторите попытку
parallelStream()
;
- Если это удастся, вам нужно будет полностью загрузить объекты перед выполнением
parallelStream()
.
Альтернативный способ: отделить все элементы списка от сеанса до выполнения parallelStream()
.
Хотя Marko писал в комментариях, Session
не является потокобезопасным, поэтому вы должны избавиться от использования Session
либо путем удаления ленивой загрузки, либо путем отсоединения всех сущностей от сеанса.