【问题标题】:Inserting 100000 record in DB using hibernate使用休眠在数据库中插入100000条记录
【发布时间】:2013-11-29 07:26:01
【问题描述】:

我正在使用 Hibernate 在 sybase DB 中插入 100000 条记录……但它需要一个多小时……使用休眠批处理仍然需要相同的时间……有什么方法可以提高性能……我想在 10 分钟内保存 100000 条记录...但无法实现这个目标。

已在配置文件中设置了 hibernate_batch_size。

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

是否可以使用休眠在数据库中插入 100000 条记录。我可以在 20 秒内使用 Ibatis 在 DB 中插入 20000 条记录,但休眠对我来说需要几个小时

【问题讨论】:

    标签: hibernate sybase


    【解决方案1】:

    使用无状态会话(没有持久性上下文缓存): 这样可以加快进程

    Session session = sessionFactory.openStatelessSession();
    Transaction tx = session.beginTransaction();
    for ( int i=0; i<100000; i++ ) {
       Item item = new Item(...);
       session.save(item);
       if ( i % 100 == 0 ) {
         session.flush();
         session.clear(); 
       }
    }
    tx.commit();
    session.close();
    

    希望对你有帮助

    【讨论】:

    • 谢谢,我会试试这个。知道如何在 java 中生成 id 并在 DB 中插入该 id。
    【解决方案2】:

    如果您在映射中使用 id 生成器,那么 Hibernate 会静默禁用 hibernate batch。更多信息here 和休眠文档第 4 章。

    我会选择带有休眠而不是对象的Work 和jdbc。至少这样你就可以对性能进行比较。

    您正在创建一个Customer 对象,然后当您将其持久化session.save() 时,它可能会到达数据库以获取ID。然后将客户添加到Hibernate session(一级缓存)。

    当您创建、持久化、添加到会话 20 个对象时,flush() 执行实际插入。然后清除缓存。这些引用设置为 null 并标记为收集。但是根据您的 heap 分布和 gc 设置,这些实例可能已经被提升到终身空间。即使不是,也会执行一次次要 gc。

    一种优化可以是在 java 代码中生成客户 ID。另一个优化是使用多线程,我会同时使用。

    在数据库外部生成 ID 以保存每个Customer 的连接的最简单方法是使用AtomicLong(必须根据customer 表中的 ID 列定义选择类型)。如果批处理不是一次性操作,则必须使用 DB 中的最高 ID 进行初始化:

    然后使用批处理触发ExecutorCompletionService,并在所有完成后提交(flush 和clear)。根据需要重复多次。

    一个天真的例子:

    select max(id) from custormer;
    

    将AtomicLong 初始化为该值,然后使用incrementAndGet()(它首先递增然后返回更新后的值)。

    使用AtomicLong 将使您的代码能够以多线程方式运行。

    生成 ID 和多线程并行执行也适用于上述jdbc discrete work。

    注意:并发执行在多核环境中发挥了优势,如果你的机器是单核的,你不会从多线程中获得太多收益。然后你可以使用一个简单的int 来生成 id,因为一切都是连续发生的。

    【讨论】:

    • 如何在java代码中生成客户id?我在配置文件中使用生成器类。
    • 嗨 @ssedano 老实说我对 Hibernate 很陌生。因此,如果您可以为上述任何内容分享一些链接,我将不胜感激。我应该同时使用 Work 并在 java 端创建 Id,还是一次只使用一个。
    • 工作用于离散 jdbc 执行(这是插入本身)。我将首先使用生成 ID 和多线程来采用您当前的方法。如果这对于您的需求仍然很慢,请尝试 jdbc 执行。但这只是我的拙见。
    • 在配置文件中,我将 id 列指向 DB 列。我在配置文件中使用生成器类。 我没有传递 id....我还需要在这个配置文件中进行更改吗..你能分享一个吗?如果您曾经实施过或有任何具体的联系。任何帮助将不胜感激
    【解决方案3】:

    加载这么多行是 DBA 类型的工作,最好使用命令行工具/命令来完成。我不熟悉 doth sybase,但是会有一个命令可以直接从 csv 文件加载到表中。

    Java/hibernate 可能是这项工作最糟糕的工具 - 内存和 CPU 很重,而且没有任何价值。

    【讨论】:

    • 我的要求是从 DB1 获取 10 亿条数据,并使用 java 程序将所有这些数据加载到其他 DB 中。我只需要为此使用 Hibernate。
    • @amiton2006 我可以相信您需要移动大量数据,但我不相信实现此我们部分要求的 方法,因为它太疯狂了.回到要求使用休眠的人并告诉他们这是一个愚蠢的想法,而任务(移动大量数据)显然是命令行工具的工作。它不仅激发速度更快,而且人力(即编程)的工作量可能减少了大约 100 倍。不费吹灰之力
    • QBohemian...如果数据需要某种处理...我不能使用命令行工具。 DB1中的数据——加载到java中——处理中——插入到其他DB中就是流程。
    • 不一定正确。你说的是哪种处理方式?
    • 是否可以使用休眠在数据库中插入 100000 条记录。我可以在 20 秒内使用 Ibatis 在 DB 中插入 20000 条记录,但休眠对我来说需要几个小时。
    猜你喜欢
    • 2013-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多