【问题标题】:Correct way to use hibernate to populate a table with data使用hibernate用数据填充表的正确方法
【发布时间】:2017-01-09 22:00:35
【问题描述】:

我有一个设备表,我正在尝试用数据填充它。该表有一个自增 id 和一个制造商列。

我将所有制造商数据存储在名为manufacturerList 的列表中。

然后我遍历整个列表并为每个条目创建一个带有该条目的新设备对象并存储在变量 temp 中。在同一个循环中,我尝试使用休眠会话将 temp 保存到我的表中。

但是,当我运行它时,我得到了这个错误

java.lang.IllegalStateException: Session/EntityManager 已关闭

在使用休眠时实现此循环的正确方法是什么?

    SessionFactory factory = new Configuration()
            .configure("hibernate.cfg.xml")
            .addAnnotatedClass(Equipment.class)
            .buildSessionFactory();

    Session session = factory.getCurrentSession();

            try{
                   List<String> manufacturerList = new List<String>();
                   //populate the list here
                   //...

                    for (String manufacturer:manufacturerList) {
                        System.out.println(manufacturer);
                        Equipment temp = new Equipment(manufacturer);
                        session.beginTransaction();
                        session.save(temp);
                        session.getTransaction().commit();
                    }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                factory.close();
            }

谢谢。

【问题讨论】:

    标签: java mysql hibernate


    【解决方案1】:

    在循环范围内插入和删除事物,我相信使用 Session 确保会话不会过早关闭的休眠的这个特定实现的正确排序如下:

            SessionFactory factory = new Configuration()
                   .configure("hibernate.cfg.xml")
                   .addAnnotatedClass(Equipment.class)
                   .buildSessionFactory();
    
            Session session = factory.getCurrentSession();
    
            try{
                   List<String> manufacturerList = new List<String>();
                   //populate the list here
                   //...
    
                    session.beginTransaction();
                    for (String manufacturer:manufacturerList) {
                        System.out.println(manufacturer);
                        Equipment temp = new Equipment(manufacturer);
                        session.save(temp);
                    }
                    session.getTransaction().commit();
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                factory.close();
            }
    

    应在将任何内容保存到会话之前启动事务。毕竟保存应该提交事务。

    改成这个后,程序运行无误。

    如果有什么我遗漏或可以优化的地方,请随时告诉我。

    【讨论】:

      【解决方案2】:

      您没有展示如何获得session 值。显然,您拥有的 session 已关闭,或者从未正确打开,但您的那部分代码未显示。此外,您显示了 factory 的关闭,但您显示的 sn-p 中不涉及该变量。

      通常您可以将EntityManagerFactory 保留很长时间,但EntityManager 实例的寿命应该相当短。不要为多个会话重用实体管理器(或Session);在每一个之后杀死它,并在需要时开始一个新的。这将更容易推断出什么是打开或关闭的,并且会防止臭名昭著的会话溢出。

      我们必须假设 Equipment 是一个正确声明和管理的实体类型,因为这里也没有显示它并且似乎与您的错误消息无关。

      因此,实现循环的正确方法是在具有循环的类中的某处初始化 EntityManager,将其用于循环,并在循环后一段时间关闭它,但将 EntityManagerFactory 留给自己的逻辑流程。

      此外,您不会使用 Hibernate 或任何 JPA 解决方案“填充表”。 Hibernate/JPA 适用于 object 模型,而不是表模型。将您的实体类型写为对象类型(没有人为的“ID”键字段!)。让 JPA 处理映射,而不是由您的代码来处理。想想对象,而不是表格。

      使用 JDBC 完成批量操作通常比使用 JPA 更好。 JPA 用于建模实体,而不是管理数据。

      【讨论】:

      • 感谢您的快速回复。我已经编辑了我的帖子以包括我的会话获取。但是由于我最初并没有在我的代码中使用 EntityManager,我可以对我现有的代码做些什么来修复它?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-27
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多