【问题标题】:Why is my data only flushed to the DB on read?为什么我的数据只在读取时刷新到数据库?
【发布时间】:2020-10-12 06:40:54
【问题描述】:

我有一个 Java Spring Boot 应用程序在本地 Oracle 19c 数据库中读取和写入数据。

我有以下CommandLineRunner

    @Override
    public void run(String... args) {
        final EntityManager em = entityManagerFactory.createEntityManager();
        final EntityTransaction transaction = em.getTransaction();
        transaction.begin();
        em.persist(customer());
//COMMENT1        em.flush();
/*COMMENT2
        Query q = em.createQuery("from " + Customer.class.getName() + " c");
        @SuppressWarnings("unchecked")
        final Iterator<Object> iterator = (Iterator<Object>) q.getResultList().iterator();
        while (iterator.hasNext()) {
            Object o = iterator.next();
            final Customer c = (Customer) o;
            log.info(c.getName());
        }
*/
        transaction.rollback();
    }

当我运行此代码时,使用数据包嗅探器监控应用程序和数据库之间的 TCP 流量,我看到了我的预期:对话中没有什么特别有趣的,因为 em.persist(customer()) 不会被刷新。

当我将代码包含在 COMMENT1 中时,我惊讶地发现对话看起来一样 - 连接握手后没有什么有趣的东西。

但是,当我将代码包含在 COMMENT2 中时,我会得到一个更完整的 TCP 对话。现在,捕获的数据包显示写入操作确实已刷新到数据库,并且我还可以看到读取操作的证据以列出其后的所有实体。

为什么只删除 COMMENT1 时,TCP 会话没有反映显式的flush()?为什么我需要包含 COMMENT2 才能看到在 TCP 连接中捕获的 insert into customer... 语句?

【问题讨论】:

  • 我想这可以回答你的问题:stackoverflow.com/questions/11048177/…
  • @JanosVinceller 它没有。我的问题是“为什么刷新实际上不刷新到数据库” - 在另一个问题中没有回答。
  • flush 方法的 javadoc 说它 - 将持久性上下文同步到底层数据库。 docs.oracle.com/javaee/7/api/javax/persistence/… 实际行为可能取决于实现。但是根据 API,您看到的内容还可以。此外,一旦你有了一个 EM,你应该通过 EM(仅)执行所有的数据库操作,这样你就有了最新的状态。 EM.flush() 根本不需要立即将更改推送到数据库以显示该状态,对吧?

标签: java database oracle jpa tcp


【解决方案1】:

对 flush() 的调用会将持久性上下文中的更改与数据库同步,但它可能不会立即提交事务。将其视为一种优化,以避免每次刷新时不必要的数据库写入。 当您取消注释第二个块时,您肯定会看到刷新被执行。发生这种情况是因为 EM 确保您的选择查询从 DB 中获取最新状态的所有结果。因此,它会提交刷新的更改(以及通过其他事务完成的任何其他更改,如果有的话)。

【讨论】:

    【解决方案2】:
    em.persist(客户()); persist 不直接将对象插入数据库: 它只是在持久性上下文(事务)中将其注册为新的。 em.flush(); 它刷新对数据库的更改但不提交事务。 如果数据库中预期发生更改(插入/更新/删除),则会触发查询 em.rollback 或 em.commit 将实际回滚或提交事务 所有这些情况都取决于刷新模式,我认为行为是 供应商依赖。假设 Hibernate,很可能 FlushMode 设置为 auto in 您的应用程序以及第二个场景中的预期结果。 自动模式:有时会在查询执行之前刷新会话,以确保 查询永远不会返回过时状态 https://docs.jboss.org/hibernate/orm/3.5/javadocs/org/hibernate/FlushMode.html 在春季启动中,我认为您可以将其设置为 spring.jpa.properties.org.hibernate.flushMode=AUTO

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-09
      • 1970-01-01
      • 2018-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多