关闭 sessionFactory 将数据保存到 HSQL

Posted

技术标签:

【中文标题】关闭 sessionFactory 将数据保存到 HSQL【英文标题】:Closing of sessionFactory saves the data to HSQL 【发布时间】:2016-11-09 12:11:30 【问题描述】:

我使用 HSQL 作为数据库并使用 Hibernate 编写应用程序。找到以下应用程序。

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        <property name="hibernate.hbm2ddl.auto">create</property>

        <!-- Database Connection settings -->
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="connection.url">jdbc:hsqldb:file:employeeDb;shutdown=true;hsqldb.write_delay=false;</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>

        <!-- Enable the logging of all the generated SQL statements to the console -->
        <property name="show_sql">true</property>

        <!-- Format the generated SQL statement to make it more readable, -->
        <property name="format_sql">false</property>

        <!-- Hibernate will put comments inside all generated SQL statements to 
            hint what’s the generated SQL trying to do -->
        <property name="use_sql_comments">false</property>

        <!-- This property makes Hibernate generate the appropriate SQL for the 
            chosen database. -->
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property>

        <!-- mappings for annotated classes -->
        <mapping class="com.sample.Employee" />

    </session-factory>

</hibernate-configuration>

Employee.java

package com.sample;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Employee 
    @Id
    private int id;
    private String firstName;
    private String lastName;
    private String designation;
    private int age;
    private double salary;

    public Employee()

    

    public Employee(int id, String firstName, String lastName, String designation, int age, double salary) 
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.designation = designation;
        this.age = age;
        this.salary = salary;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getFirstName() 
        return firstName;
    

    public void setFirstName(String firstName) 
        this.firstName = firstName;
    

    public String getLastName() 
        return lastName;
    

    public void setLastName(String lastName) 
        this.lastName = lastName;
    

    public String getDesignation() 
        return designation;
    

    public void setDesignation(String designation) 
        this.designation = designation;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    

    public double getSalary() 
        return salary;
    

    public void setSalary(double salary) 
        this.salary = salary;
    


TestEmployee.java

package com.sample;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class TestEmployee 

    /* Step 1: Create session factory */
    private static SessionFactory getSessionFactory() 

        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();

        return sessionFactory;
    

    public static void main(String args[]) 
        Employee emp1 = new Employee(1, "Hari Krishna", "Gurram", "Senior Software Developer", 26, 80000);
        Employee emp2 = new Employee(2, "Shreyas", "Desai", "Team Manager", 35, 150000);
        Employee emp3 = new Employee(3, "Piyush", "Rai", "Senior Software Developer", 26, 100000);
        Employee emp4 = new Employee(4, "Maruti", "Borker", "Software Developer", 26, 60000);

        SessionFactory sessionFactory = getSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        session.save(emp1);
        session.save(emp2);
        session.save(emp3);
        session.save(emp4);
        session.flush();
        session.getTransaction().commit();

        session.close();
        //sessionFactory.close();

    

当我取消注释文件“TestEmployee.java”中的“sessionFactory.close()”行时,应用程序完美地保存了数据。但是当我评论“sessionFactory.close()”行时,我的数据没有得到保存。为什么我需要关闭 sessionFactory?有什么方法可以在不关闭 sessionFactory 的情况下保留数据?

查找堆栈跟踪

INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@a22cb6a] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table Employee (id integer not null, age integer not null, designation varchar(255), firstName varchar(255), lastName varchar(255), salary double not null, primary key (id))
Nov 09, 2016 6:22:08 PM org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl handleException
WARN: GenerationTarget encountered exception accepting command : Error executing DDL via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:524)
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:470)
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.createTable(AbstractSchemaMigrator.java:273)
    at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:71)
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:203)
    at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:110)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:177)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:66)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:309)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:445)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:710)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:726)
    at com.sample.TestEmployee.<clinit>(TestEmployee.java:8)
Caused by: java.sql.SQLException: Table already exists: EMPLOYEE in statement [create table Employee]
    at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.execute(Unknown Source)
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:54)
    ... 13 more

Hibernate: insert into Employee (age, designation, firstName, lastName, salary, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into Employee (age, designation, firstName, lastName, salary, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into Employee (age, designation, firstName, lastName, salary, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into Employee (age, designation, firstName, lastName, salary, id) values (?, ?, ?, ?, ?, ?)
Nov 09, 2016 6:22:08 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:hsqldb:file:employeeDb;shutdown=true;hsqldb.write_delay=false;]

【问题讨论】:

【参考方案1】:

正如您的 cmets 澄清的情况,这是 HSQLDB 的正常行为。它将所有从工作文件挂起的存储到持久日志文件(由于shutdown=true)。为了使其工作,您需要在应用程序终止之前关闭工厂。要自动化这个过程,只需像这样使用关闭挂钩Runtime.addShutdownHook(Thread)

Runtime.getRuntime().addShutdownHook(new Thread()
    public void run()

       //CLOSE SESSION FACTORY HERE
     
);

所以基本上,您的更改在您的情况下是持久的,但是您无法从应用程序外部看到它们,因为当您在不同的过程中再次启动 HSQLDB 时它们没有恢复(例如,从构建 db 查看器或 Eclipse IDE数据库工具)

【讨论】:

是的,更改存储到employeeDb.log 文件中,但在关闭sessionFactory 时它们将存储到employeeDb.script 文件中。感谢您的澄清 这正是 HSQLDB 的工作原理。过去一段时间我对此很感兴趣,并且在这几分钟里一直在挣扎,因为这不是很明显:) 我更新了属性 hibernate.hbm2ddl.auto 来更新,当我第二次用不同的数据运行时,update,仍然是试图创建表并失败。对此有任何想法 添加了堆栈跟踪 试试把属性的key改成hbm2ddl.auto【参考方案2】:

您不必close() 您的工厂,但您必须flush() 更改。关闭时自动完成刷新。

删除session.flush(),因为它在提交时被刷新。

在任何情况下都能正常工作的数据库操作的典型模板(除非您破坏了配置中的某些内容)如下:

典型的交易应该使用以下成语:

 Session sess = factory.openSession();
 Transaction tx;
 try 
     tx = sess.beginTransaction();
     //do some work
     ...
     tx.commit();
 
 catch (Exception e) 
     if (tx!=null) tx.rollback();
     throw e;
 
 finally 
     sess.close();
 

根据我的经验,我曾多次这样做,并且一直有效。 Hibernate 的文档也说明了这一点。不需要额外的冲洗等。试试看。

【讨论】:

感谢您的回复。我删除了flush语句。但我的问题是数据没有得到持久化。它存储在关闭 sessionFactory 它适用于 RDBMS 等数据库。但是 HSQLDB 是内存数据库,我不确定是否缺少一些配置。 jdbc:hsqldb:file:employeeDb;shutdown=true;hsqldb.write_delay=false; 啊,这是不同的。是的,我也有同样的问题来反映这些变化。 HSQDB 将在关闭时将更改(操作日志)存储到持久性日志文件(shutdown=true),因此当连接关闭时,当您关闭会话工厂时会发生这种情况:) 要修复它,请添加一个 Runtime#addShutdownHook 您将在的位置在 JVM 终止时关闭 SessionFactory :)

以上是关于关闭 sessionFactory 将数据保存到 HSQL的主要内容,如果未能解决你的问题,请参考以下文章

将对象从数组保存到数据库[关闭]

如何将数据持久保存从 PHP 到 Android [关闭]

将对象保存到数据库的良好做法 [关闭]

如何使用 javascript 或 jquery 将 html 表单数据保存到 sql db [关闭]

使用php将复选框值保存到数据库[关闭]

将 NSMutableArray 保存到 plist [关闭]