在Action Bean中使用Java 8 ParallelStream时出现随机休眠异常 [英] Random Hibernate Exception when using Java 8 ParallelStream in Action Bean

查看:206
本文介绍了在Action Bean中使用Java 8 ParallelStream时出现随机休眠异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Action Bean中,我从数据库中加载实体,使用这些实体中的数据通过Java 8 ParallelStream创建新的EntityObject,并将这些EntityObject存储在列表中,以供以后在网页上使用.

In my Action Bean I load Entities from a database, use data from those Entities to create new EntityObjects using Java 8 ParallelStream, and store those EntityObjects in a List for later use on a web page.

我使用以下内容通过Hibernate映射的实体创建这些对象:

I use the following to create these Objects using the Hibernate mapped Entities:

List<Entity> entities = dao.getEntities();
List<Object> entityObjects = new ArrayList<>();
entityObjects.addAll(
        entities.parallelStream()
                .map(EntityObject::new)
                .collect(Collectors.toList())
);

带有EntityObject构造函数,如下所示:

with a EntityObject constructor looking like:

public EntityObject(Entity entity) {...}

当尝试使用Action Bean加载页面时,出现了Hibernate Exception.每次我尝试加载页面时,它们都是不同的,但是都与共享引用有关,例如:

When Trying to load the page using the Action Bean I get Hibernate Exceptions. They are different every time I try to load the page, but all have to do with Shared References, such as:

... ERROR: Found shared references to a collection

... ERROR: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

我在做什么错了?

编辑:修正了代码.

推荐答案

parallelStream()将在多个线程上执行代码(有利于性能).但是,Hibernate Session对象不是线程安全的,以线程方式使用它可能会以神秘的方式失败. Bryan Pugh关于事务的另一个答案是相似的:在大多数情况下,事务保存在ThreadLocal变量中.执行parallelStream()意味着某些代码在不同(不相关)的线程上运行. 使用以下代码可以很容易地显示出来:

parallelStream() will execute the code on multiple threads (good for performance). However, the Hibernate Session object is not thread-safe and using it in a threaded fashion is likely to fail in mysterious ways. The other answer from Bryan Pugh regarding transactions is similar: in most cases the transaction is held in a ThreadLocal variable. Executing parallelStream() means some code runs on a different (unrelated) thread. This can be easily shown using this code:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class TestParallel {
    public static void main(String[] args) {
        // Keep a set of thread-ids that were used. Make sure this is thread-safe.
        Set<String> threadId = Collections.synchronizedSet(new HashSet<String>());

        // Create a long enough list such that spliterator will indeed use multiple threads.
        // If the collection is very small (1 or 2 entries) no multithreading will be done.
        Collection<Integer> numbers = new ArrayList<>();
        for(int i=0; i<10000; i++) {
            numbers.add(i);
        }

        // Now for each number in the list, see which thread is handling it by dumping the thread-name.
        numbers.parallelStream().forEach(n -> threadId.add(Thread.currentThread().toString()));

        // And give a summary of the total number of threads that were used in the parallelStream()
        System.out.println("Used threads: " + threadId.size());
    }
}

使用小列表(将10000更改为2)时,将使用一个线程.在我的机器上给定的常数下,使用12个线程.根据数据库中条目的数量以及所使用的性能和JDK版本,数量会有所不同,但通常来说:除非知道它的作用,否则请避免使用parallelStream().

When using a small list (change 10000 to 2) one thread will be used. With the given constant on my machine 12 threads are used. Depending on the number of entries in your database and the performance and JDK version you used, the numbers will vary but in general: avoid parallelStream() unless you know what it does.

这篇关于在Action Bean中使用Java 8 ParallelStream时出现随机休眠异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆