Hibernate JPA托管实体引发空指针异常

Hibernate JPA托管实体引发空指针异常,hibernate,jpa,nullpointerexception,thread-safety,Hibernate,Jpa,Nullpointerexception,Thread Safety,我将JPA2.0与SpringBoot一起用于我的一个项目。由于应用程序需要大量只读查询,我决定创建一个带有entityManager标记为 @PersistenceContext(type=PersistenceContextType.EXTENDED) 许多DAO(可能在多个线程中)依次使用扩展实体管理器的这个实例来执行只读请求。由于实体过去位于扩展持久性上下文中,因此对实体进行进一步细化(如果愿意的话)的调用从未给出LazyInitializationException。此外,由于实体一旦

我将JPA2.0与SpringBoot一起用于我的一个项目。由于应用程序需要大量只读查询,我决定创建一个带有entityManager标记为 @PersistenceContext(type=PersistenceContextType.EXTENDED)

许多DAO(可能在多个线程中)依次使用扩展实体管理器的这个实例来执行只读请求。由于实体过去位于扩展持久性上下文中,因此对实体进行进一步细化(如果愿意的话)的调用从未给出LazyInitializationException。此外,由于实体一旦加载,就始终存在于扩展持久性上下文的活动内存中,因此可以使用扩展持久性上下文来获得优异的性能

然而,随着时间的推移,在访问一个托管实体的某个字段时,我偶尔会出现NullPointerException。这种行为是不确定的

        // .. earlier code skipped for brevity
        Child child = refNode.getFirstChild();

        if (child != null) {
            // Print confirms that the object is managed. In fact, earlier merely 
            // inserting print statement would dissolve the error.
            System.out.printf ("Child ID = %s %s\n", child.getChildID(), childDAO.getContext(child));

            // NPE while accessing latestVersion attribute of 'Child'.
            // Values does exist in DB. 
            Unode un = child.getLatestVersion().getuNode();
            return un;
        }
“子”实体的相关部分如下:

    public class Child implements Serializable { 
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private int childID;
        ...
        @ManyToOne(cascade={CascadeType.ALL})
        @JoinColumn(name="latestVersionID")
        private Version latestVersion;
是的,我也很慷慨地收到了以下错误

    HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session
最近,我还收到了“ConcurrentModificationException”、不安全的线程访问,以及迄今为止代码中所有干净部分中的类似错误。我还尝试在所有访问中使用synchronized(mutex)使扩展上下文实体管理器线程安全,但没有任何帮助

我最担心的是一个托管实体(在扩展上下文中)会给出null-pointed异常。尽管这些异常看起来不确定,但它们通常集中在访问“Child”或“Child.LatestVersion”的位置

我试过了,懒散的加载,急切的加载等等,但是没有用。我的理解(到目前为止)是,向前实体被急切地加载,向后实体被惰性地加载,并且当实体被管理时(无论在哪个上下文中-扩展的还是事务的),都不会出现空点异常


任何帮助都将不胜感激

答案很简单:
EntityManager
不是线程安全的。例如,参见此处:


你应该做的是停止重复使用它。
EntityManager
的创建成本较低(与
EntityManager工厂相比)

克里兹,谢谢。扩展实体管理器仅用于只读查询,因为持久性上下文是一个优秀的缓存。使用扩展em不会执行更新/插入操作。此外,通过DI访问em应该使其线程安全(尽管只读请求不需要线程安全),不是吗?此外,不管是线程安全还是非线程安全,托管实体是否应该经历空指针异常?如果您使用的是来自多个线程的非线程安全对象,它将不会是线程安全的。我看不出DI应该如何解决这个问题。另外,线程安全是关于
EntityManager
的内部实现是否对线程敏感,与只读请求一起使用是否对线程安全是
Hibernate
人员的问题。最后,如果您以一种不应该的方式使用API,没有人能保证应该或不应该发生什么。另外,如果您有一个共享缓存用于通过读取检索的实体,您会意识到不“通过”该缓存的写入操作将使其失去同步吗?也许你应该考虑使用第二级缓存:再次感谢。在阅读之前的一篇文章时,我的印象是spring还保证了它的单例线程的安全性。不管怎样,我使用互斥体同步了em访问,但没有多少好处。是的,我同意只有Hibernate的人才能判断只读请求是否是线程安全的。是的,我知道如果数据从别处更新,缓存会变脏。我通过定期冲洗em来解决这个问题。第二级缓存(我使用的是ehcache)工作不太好,因为它序列化实体并从中重建java对象