【问题标题】:Cannot reopen transaction using EntityManger无法使用 EntityManager 重新打开事务
【发布时间】:2017-02-01 09:48:10
【问题描述】:

我正在尝试使用一个 EntityManager 打开事务两次:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("HelloWorldPU");
        EntityManager em = emf.createEntityManager();

        Message message0 = new Message();
        message0.setText("Hi!!");
        em.getTransaction().begin();
        em.persist(message0);
        em.getTransaction().commit();
        em.close();
        
        Message message1 = new Message();
        message1.setText("Bye!!");

        System.out.println("i'm here");
        em.getTransaction().begin();
        em.persist(message1);
        em.getTransaction().commit();
        em.close();

并得到一个异常:

我来了

线程“main”java.lang.IllegalStateException 中的异常:org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl@31e4bb20 已关闭

我的猜测是:不可能从已关闭的 EntityManager 中获得另一笔交易。然而JPA Spec 说:

EntityManager.close 方法关闭实体管理器以释放其持久性上下文和其他资源。调用close 后,应用程序不得在EntityManager 实例上调用除getTransactionisOpen 之外的任何其他方法,否则将抛出IllegalStateException。如果在事务处于活动状态时调用 close 方法,则持久性上下文将保持受管理状态,直到事务完成。

谁能解释我错在哪里?调用getTransaction 的可能性不意味着我可以使用这个事务并调用事务的方法吗?

谢谢。

更新

感谢您的回答,这些对我最有帮助:

1:

在调用 close 之前,您可以使用 EntityManager,是的。没有 “重新打开”方法。创建 EntityManager 是一项廉价的操作——尼尔 斯托克顿 13 分钟前

2:

您可以调用 getTransaction 来检查事务是否处于活动状态。于 还可以关闭具有活动 tx 的 EntityManager(如文档 状态)并在关闭后提交)。因此,您可以致电 获取交易。 – M. Deinum 9 分钟前

【问题讨论】:

  • 文档很清楚.... 应用程序不能在 EntityManager 实例上调用任何其他方法,除了 getTransaction 和 isOpen,...您正在尝试坚持不允许使用封闭实体管理器的东西。您应该只在实体管理器上调用一次 close。
  • 好的,但我无法理解的是为什么我可以调用 getTransaction 然后不能使用它?
  • 你为什么要关闭 EntityManager 然后尝试调用它的任何方法?!更不用说稍后再尝试关闭它!
  • 所以这意味着我只能使用一次创建的EntityManager,并且在close()方法之后它不再可用,尽管有可能再次getTransaction,对吧?只是想正确理解这个概念。
  • 您可以使用 EntityManager 直到您调用 close,是的。没有“重新打开”的方法。创建 EntityManager 是一种廉价的操作

标签: java hibernate jpa


【解决方案1】:

这里的实际情况是,您的第一次 close() 调用是不必要的。您实际上想要实现的是拥有两个独立的事务 - 完全有效。有两种基本方法可以做到这一点。

1) 提交事务,在同一个实体管理器实例上启动一个新事务。我滥用缩进来显示实体管理器的寿命的示例:

EntityManager em = emf.createEntityManager();

        Message message0 = new Message();
        message0.setText("Hi!!");
        em.getTransaction().begin();
        em.persist(message0);
        em.getTransaction().commit();

        // no close here

        Message message1 = new Message();
        message1.setText("Bye!!");

        System.out.println("i'm here");
        em.getTransaction().begin();
        em.persist(message1);
        em.getTransaction().commit();

em.close();

2)关闭实体管理器并创建一个新的(如cmets中所说的很便宜)

EntityManager em = emf.createEntityManager();

        Message message0 = new Message();
        message0.setText("Hi!!");
        em.getTransaction().begin();
        em.persist(message0);
        em.getTransaction().commit();

em.close();


// create new EntityManager
em = emf.createEntityManager();

        Message message1 = new Message();
        message1.setText("Bye!!");

        System.out.println("i'm here");

        em.getTransaction().begin();
        em.persist(message1);
        em.getTransaction().commit();

em.close();

您选择哪个选项取决于应用程序功能的进一步设计;例如,选项 1) 对缓存更友好,并且可能会在事务之间维护第一级缓存。如果事务之间存在延迟并且数据源中的数据更改,这有缓存中的缓存实体变得陈旧的风险,事务之间对em.clear() 的调用可以解决。

当我实现事务批处理逻辑时,我倾向于选择选项 2),例如:文件导入逻辑,它会泵入大量记录,这些记录要以较小的块进行处理和提交。在任何其他情况下,选项 1) 通常都可以正常工作。

【讨论】:

    【解决方案2】:

    尝试对您的代码进行以下更改:

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("HelloWorldPU");
            EntityManager em = emf.createEntityManager();
    
        Message message0 = new Message();
        em.getTransaction().begin();
        message0.setText("Hi!!");
        em.persist(message0);
        em.getTransaction().commit();
        em.close();
    EntityManagerFactory emf1 = Persistence.createEntityManagerFactory("HelloWorldPU");
                EntityManager em1 = emf.createEntityManager();
        Message message1 = new Message();
        em1.getTransaction().begin();
        message1.setText("Bye!!");
    
        System.out.println("i'm here");
    
        em1.persist(message1);
        em1.getTransaction().commit();
        em1.close();
    

    尝试恢复!一旦 EM 关闭,您应该创建/打开一个新的。

    【讨论】:

    • 如果您多次创建 EMF,那么您的应用程序将运行非常缓慢!!!你也没有在那里关闭你的 EMF ...
    猜你喜欢
    • 2017-07-25
    • 2019-10-12
    • 1970-01-01
    • 2019-05-09
    • 2018-04-19
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2018-03-21
    相关资源
    最近更新 更多