【问题标题】:Flushing the Hibernate Session is taking a very long time刷新休眠会话需要很长时间
【发布时间】:2017-02-23 13:10:35
【问题描述】:

我正在使用 Hibernate 5.2.8.Final 版本,我们需要从数据库中读取数百万个数据并通过一些业务逻辑更新数据,因为我的数据库很大,我想在达到批量大小后提交数据所以我写了下面的代码

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
Query<Object> query = session.createQuery(SQL, Object.class);
ScrollableResults scrollableResults = query.setCacheMode(CacheMode.IGNORE)
        .scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
while (scrollableResults.next())
{
    Object object = (Object) scrollableResults.get(0);
    process(object)
    session.update(object);
    if (++count % batchSizeDeclare== 0)
    {
        session.flush();
        session.clear();
        LOGGER.info("Updated batch records");
    }
}
session.getTransaction().commit();
LOGGER.info("commited in Hibernate ");
}

下面是我的hibernate.cfg.xml文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->
        <property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
        <property name="connection.url">jdbc:sqlserver://com;database=DEV</property>
        <property name="connection.username">user</property>
        <property name="connection.password">pass</property>

        <property name="hibernate.default_schema">schema</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">5</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.SQLServer2012Dialect</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> -->
        <!-- <property name="format_sql">true</property> -->

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <!-- org.hibernate.HibernateException: No CurrentSessionContext configured! -->
        <property name="hibernate.current_session_context_class">thread</property>

        <property name="hibernate.jdbc.batch_size">100</property>

        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_size">20</property>
        <property name="hibernate.c3p0.timeout">300</property>
        <property name="hibernate.c3p0.max_statements">50</property>
        <property name="hibernate.c3p0.idle_test_period">3000</property>

        <mapping class="com.beans.Object" />

    </session-factory>
</hibernate-configuration>

下面是我的Object.java

 public class Object implements Serializable
    {
        private static final long serialVersionUID = 1L;

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID", nullable = false, unique = true, updatable = false)
        private int id;
        private String filePath;

    private String fileName;
    private String mimeType;
    private double fileSize;
    // removed getters and setters

    }

一旦我的代码到达 session.flush(),即使等待 30 分钟,它也不会做任何事情。这是批量提交的正确方法吗?如何批量更新?

【问题讨论】:

  • batchSizeDeclare 的值是多少?
  • 100 是我的 batchSizeDeclare 值

标签: java hibernate orm batch-processing hibernate-batch-updates


【解决方案1】:

一旦我的代码到达 session.flush 它甚至什么都不做 等待 30 分钟后。

相反,数据库似乎做得太多了。只是您看不到任何进展,因为数据库正在努力应对您提交的大量工作。

这是批量提交的正确方法吗?

简短的回答是否。

您不必从数据库中获取数百万行。你有更好的选择:

  1. 您可以在数据库中进行处理,这样您就无需支付提取数据并通过网络发送数据的代价,只需使用 Java 进行处理。
  2. 如果您无法在 DB 中处理它,那么您需要使用一次只能获取小块数据的批处理器。这样,您甚至可以parallelize the batch processing,这应该会减少整体处理时间。

【讨论】:

  • 还有一个问题,我已将我的 batchSizeDeclare 变量设置为 100,这是 hibernate.cfg.xml 文件值中的批量更新大小。对于 100 条记录,它需要 30 多分钟,而且我认为将 id 值声明为序列是最好的。改变值是否有助于提高性能
  • 记录 SQL 查询并确保只执行了 100 个条目。检查数据库日志以了解那里发生的情况也很重要。
  • 在 SQL 查询中它只显示 100,在 db 日志中正在插入另一批数据,其中还包含插入块中的 1000 万条记录数据
  • 一批1000万条的数据有点解释为什么服务器卡住了,你不同意吗?
  • 我想我没有这样的例子。您可能想看看 Spring Integration。它提供了许多 EiP 结构来帮助您完成这项任务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-07
相关资源
最近更新 更多