【问题标题】:Why Hibernate doesn't save my object in database为什么 Hibernate 不将我的对象保存在数据库中
【发布时间】:2015-07-19 19:55:41
【问题描述】:

我正在使用带有 Java 8 的 Hibernate 4.3.10。

要更明确,请参见以下代码示例:

public static long createBlindStructure(BlindStructure pBlindStructure){
    Transaction tcx = null;
    SessionFactory factory = HibernateUtil.getSessionFactory();
    Session session = factory.openSession();
    int id = -1;
    try{
        tcx = session.beginTransaction();
        id = session.save(pBlindStructure);
        tcx.commit();
    }
    catch( Throwable e){
        tcx.rollback();
    }
    finally{
        session.close();
    }
    return id;
}

在我看来这个方法save()打开会话和事务,保存我的对象并关闭会话和事务。从save() 我试图取回javadoc 中描述的标识符。但它不起作用,我看到请求在我的日志中执行(感谢 Hibernate 调试模式)。

Hibernate: insert into PokerLeagueManager.blindStructure (structureJson) values (?)

但是当我尝试这个时:

public static long createBlindStructure(BlindStructure pBlindStructure){
    Transaction tcx = null;
    SessionFactory factory = HibernateUtil.getSessionFactory();
    Session session = factory.openSession();
    try{
        tcx = session.beginTransaction();
        session.save(pBlindStructure);
        tcx.commit();
    }
    catch( Throwable e){
        tcx.rollback();
    }
    finally{
        session.close();
    }
    return pBlindStructure.getIdBlindStructure();
}

它正确地保存了我的对象。

我再测试一个案例: 只需返回一个常量,不要像第一个示例那样将 Id 放入变量中,它可以工作。如果我直接使用session.save() 方法获取ID,似乎没有保存对象。

此外,我观察到一些有趣的事情。我使用其中一个有效的解决方案进行了第一次测试,它生成了一个 ID 为 117 的数据库数据。然后我更改了我的解决方案的代码,该解决方案无法正常工作并将其重新加载到 Tomcat 中,我进行了第二次尝试但没有成功。我再次更改了我的代码,成功生成的 id 是 120。它错过了 2nf id 号(我已经完成了第二次尝试??)

为了帮助您查看我的hibernate.cfg.xml 文件

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          '-//Hibernate/Hibernate Configuration DTD 3.0//EN'
          'http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd'>

<hibernate-configuration>
<session-factory>
    <!-- Database connection settings -->
    <property     name='connection.driver_class'>com.mysql.jdbc.Driver</property>
    <property name='connection.url'>jdbc:mysql://XXXXXX:XXXX/PokerLeagueManager</property>
    <property name='connection.username'>XXXXX</property>
    <property name='connection.password'>XXXXXX</property>
    <property name="show_sql">true</property>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    <property name="hibernate.c3p0.acquire_increment">1</property>
    <property name="hibernate.c3p0.idle_test_period">120</property>
    <property name="hibernate.c3p0.min_size">1</property>
    <property name="hibernate.c3p0.max_size">10</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.timeout">120</property>
    <property name="hibernate.c3p0.acquireRetryAttempts">1</property>
    <property name="hibernate.c3p0.acquireRetryDelay">250</property>
    <!--  Dev -->
    <property name="hibernate.c3p0.validate">true</property>

    <!-- SQL dialect -->
    <property name='dialect'>org.hibernate.dialect.MySQL5InnoDBDialect</property>

    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>
    <!-- Disable the second-level cache -->
    <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>


    <!-- Echo all executed SQL to stdout -->
    <property name='show_sql'>true</property>
    
    <mapping resource="mappings/BlindStructure.hbm.xml"/>
    <mapping resource="mappings/Tournament.hbm.xml"/>
    <mapping resource="mappings/LegalFee.hbm.xml"/>
</session-factory>

编辑:User3813463 回答部分问题。它解释了会话在默认情况下处于自动刷新模式,在某些情况下刷新会话,例如:

flush 默认发生在以下几点:

  • 在一些查询执行之前

  • 来自 org.hibernate.Transaction.commit()

  • 来自 Session.flush()

但我的观点(我可能错过了一些理解),我的第一个案例应该有效,因为我提交了我的交易。

其次,我需要建议选择冲洗模式。在我看来,提交模式是一种只在数据库中插入或读取数据的方法的好方法。

你同意我的观点吗,你有一些关于辩论的来源吗?

【问题讨论】:

  • 如果你不介意先回答我的问题,当行`return pBlindStructure.getIdBlindStructure();`被执行时,你在控制台/日志上看到了什么? :)
  • ...并发布您的休眠配置...
  • pBlindStructure.getIdBlindStructure() => 在我的第二种情况下,它返回生成的 Id 的值。我在主消息上进行了休眠配置
  • 在第一种情况下,你为什么不在transaction.commit() 之前尝试session.flush()
  • 没用。但我终于找到了为什么它不起作用。我返回一个 Integer 而不是 Long。我没有注意,也没有人通知我我没有任何记录器....实际上我的代码引发了异常。感谢您的所有建议:)

标签: java hibernate


【解决方案1】:

这就是FlushMode 的魔力阅读文档here

根据文档默认FlushModeAUTO 这意味着

Session 有时会在查询执行之前被刷新,以便 确保查询永远不会返回陈旧状态。

根据另一个文档(Here):

flush 默认出现在以下几点:

在一些查询执行之前

来自 org.hibernate.Transaction.commit()

来自 Session.flush()

所以当你说 pBlindStructure.getIdBlindStructure(); hibernate 实际上在当前会话上执行刷新,结果数据被保存在数据库中。

【讨论】:

  • 对不起,如果不回答,我今天晚些时候会研究你的答案,我昨天没有时间。
  • 抱歉延迟回答,我有很多想法要做 IRL ;)。它解释了为什么在我的第二种情况下我肯定会得到结果。但我的第一个案例是事务提交,它应该刷新当前会话?在那种情况下,为什么它根本不冲洗?在低并发应用中使用哪种flush模式更好?
【解决方案2】:

会话保存方法为生成器生成的 id 返回一个对象。您应该将此值强制转换为 Long

long id = -1;
try{
    tcx = session.beginTransaction();
    id = (Long) session.save(pBlindStructure);
    tcx.commit();
}
catch( Throwable e){
    tcx.rollback();
}
finally{
    session.close();
}
return id;

【讨论】:

  • 先生,但是为什么记录没有在方法 1 中保存呢?我认为这是因为 flushmode。我认为第二种方法是pBlindStructure.getIdBlindStructure(); 被执行会话被刷新以将记录写入(插入)数据库。
  • 对不起,我忘记了我的演员阵容,但我在测试期间的表现和你一模一样(日食不要让我选择)
  • 我没听懂你在说什么。
  • 我在我的例子中忘记了“session.save”的演员表,但我在测试期间得到了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多