提问者:小点点

Java带Spring注释的方法


我尝试在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)

如何使用parallelStream()注释的事务方法?

更新为什么会发生这种情况Spring事务管理器和多线程,但我希望支持java 8的Spring 4能够提供一些解决方案。有什么想法吗?


共2个答案

匿名用户

嗯,我有一个猜测包括几个猜测:

  • 您的会话管理策略为每线程会话
  • 您在示例中编写的对象实际上是某个使用延迟加载的实体;
  • Process One()方法使用延迟加载的实体属性;
  • 因为第一点,为并行流()启动的线程没有可用的会话(可能在线程本地中,不记得会话在技术上是如何绑定到线程的);

这就造成了你的问题。这种行为在我看来很奇怪,因此我建议采取以下措施:

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

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

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

匿名用户

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