无法使用EntityManger重新打开事务

时间:2017-02-01 09:48:10

标签: java hibernate jpa

我尝试使用一个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后,除EntityManagergetTransaction外,应用程序不得在isOpen实例上调用任何其他方法,否则将引发IllegalStateException。如果在事务处于活动状态时调用close方法,则持久性上下文将保持受管状态,直到事务完成。

有人可以解释我错在哪里吗?没有调用getTransaction的可能性意味着我可以使用此交易和ivoke交易的方法吗?

谢谢。

更新

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

1:

  

您可以使用EntityManager,直到您调用close,是。没有   "重新打开"方法。创建一个EntityManager是一个廉价的操作 - 尼尔   斯托克顿13分钟前

2:

  

您可以调用getTransaction来检查事务是否处于活动状态。宇   也可以关闭带有活动tx的EntityManager(作为文档   状态)并在收盘后提交)。因此你可以打电话   getTransaction。 - M. Deinum 9分钟前

2 个答案:

答案 0 :(得分: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)关闭实体经理并创建一个新的(正如评论中所说的那样便宜)

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)通常都可以正常工作。

答案 1 :(得分:-1)

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

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关闭后,您应该创建/打开一个新的。