【问题标题】:Java .parallelStream() with spring annotated methods带有 spring 注释方法的 Java .parallelStream()
【发布时间】:2014-06-09 14:50:24
【问题描述】:

我尝试在带有 Spring @Transactional 注释的 DAO 中使用 parallelStream() 并遇到问题:

@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 transaction manager and multithreading 但我希望支持 java 8 的 spring 4 可以为此提供一些解决方案。有什么想法吗?

【问题讨论】:

  • 一个小问题,但是如果你使用stream().parallel(),你会得到同样的错误吗?
  • 是的,我对 stream().parallel() 也有同样的问题
  • 谢谢 Evgeni,我明白为什么会这样。解决这个问题很有趣。
  • 我想知道当你想并行运行它时,为什么要在 processCollection 上使用@Transactional。

标签: java multithreading spring java-8 java-stream


【解决方案1】:

问题不在于并行流。在 Spring 中,事务是使用 AOP 创建的。
当您的 processCollection 方法执行时,sp​​ring 创建一个代理对象并启动事务。 在同一个类中调用另一个方法,即使您指定了 @Transaction ,spring 也不会在 New transaction 中运行该方法。 要让它运行,将该方法 process() 移动到新服务,然后执行您的问题。您的程序将正常运行。

【讨论】:

    【解决方案2】:

    嗯,我的猜测由几个猜测组成:

    • 您的会话管理策略为session-per-thread
    • Object你在例子中写的其实是一些使用延迟加载的实体;
    • processOne() 方法使用延迟加载的实体属性;
    • 由于第一点,为parallelStream() 启动的线程没有可用的会话(可能在ThreadLocal,不记得从技术上讲会话是如何绑定到线程的);

    这完全导致了您遇到的问题。这种行为对我来说看起来很奇怪,所以我建议执行以下操作:

    • 删除所有延迟加载并再次尝试parallelStream()
    • 如果成功,您必须在执行parallelStream() 之前完全加载实体。

    另一种方法:在执行parallelStream()之前从会话中分离所有列表元素。

    尽管正如 Marko 在 cmets 中所写,Session 不是线程安全的,因此这意味着您必须通过删除延迟加载或从会话中分离所有实体来摆脱 Session 的使用。

    【讨论】:

    • Hibernate 的会话不是线程安全的。唯一的选择是分离。
    • @MarkoTopolnik 谢谢 Marko,不知道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 2011-12-10
    • 1970-01-01
    • 2014-05-09
    • 2018-12-30
    相关资源
    最近更新 更多