java - JPA:EntityManager 的get-use-close 和延迟加载

标签 java jpa persistence openjpa

IBM 建议使用 EntityManagers 的最佳实践是获取/使用/关闭。如果 EntityManager 没有关闭,同一个 EntityManager 可能被多个线程使用,这将导致以下错误:

<openjpa-2.1.2-SNAPSHOT-r422266:1179900 fatal general error> org.apache.openjpa.persistence.PersistenceException: Multiple concurrent threads attempted to access a single broker. By default brokers are not thread safe; if you require and/or intend a broker to be accessed by more than one thread, set the openjpa.Multithreaded property to true to override the default behavior. 

如果您加载一个对象,该对象的 OneToMany 集合映射为 fetch=LAZY,如下所示:

public T find(Object id) {
    T t = null;
    EntityManager em = getEm();
    t = em.find(type, id);
    em.close();
    return t;
}

EntityManager getEm() {
    if(this.em ==null || !this.em.isOpen()) {
        this.em = emf.createEntityManager();            
    }
    return this.em;
}

集合将始终为 null,因为当有人调用 getter 时,EntityManager 已关闭。该集合仅在 fetch 为 EAGER 时才加载,但这会导致每次都进行 SQL 连接,这很慢。

所以它要么是“多线程”错误,要么是 openjpa.Multithreaded=true ,这是一种不好的做法,或者它很慢,因为即使不需要收集,每次都进行 SQL 连接。有没有什么方法可以正确地做到这一点,既可以通过延迟获取快速完成,又可以仅使用最佳实践来完成?

最佳答案

好的,这是我对这个问题研究了两天后的结论。对于不能依赖于部署在 Java EE 服务器上并且不能保证单线程访问的应用程序(例如 tomcat 上的 Web 应用程序),最佳实践确实是在方法范围内打开、使用和关闭实体管理器DAO 对象。

这意味着延迟加载将无法在 DAO 之外工作。为了解决这个问题,在通过 id 查找一个实体的方法中,需要通过调用集合上的 size() 来获取所有集合,以在实体管理器关闭之前触发获取。这将使 find 方法返回一个完全加载的对象,即使 fetch 是惰性的。

对于返回对象集合的方法,如搜索,完全加载搜索结果中的每个实体会太慢,因此返回的结果没有子项。每当需要查看搜索结果中的实体之一时,就必须通过获取完全加载对象的方法单独加载它。

关于java - JPA:EntityManager 的get-use-close 和延迟加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12968370/

相关文章:

Java : How to achieve socket programming functionality with 3rd party API

grails - 在使用CRUD支架之前,无法保存域对象

persistence - 如何在g-wan中的http请求之间共享内存?

java - 两次模拟相同的语句

Java,解压缩文件名中包含德语字符的文件夹

java - Wildfly 未安装所需的服务 :\

mysql 两个FK在同一个表中

mysql - 同时更新依赖于实体属性的实体

java - 在运行时从头开始设置数据库

java - Azure 服务总线队列 - JMS 消息监听器调用程序设置因目标异常而失败