【问题标题】:Tutorial about Using multi-threading in jdbc在 jdbc 中使用多线程的教程
【发布时间】:2011-08-25 07:31:28
【问题描述】:

我们公司有一个每天运行的批处理应用程序,它主要做一些与数据库相关的工作,例如从文件中将数据导入数据库表中。

该应用程序中定义了 20 多个任务,每个任务可能依赖于其他任务,也可能不依赖其他任务。 应用一个接一个地执行任务,整个应用运行在一个线程中。

完成所有任务需要 3~7 小时。我觉得它太长了,所以我想也许我可以通过多线程来提高性能。

我认为由于任务之间存在依赖关系,使任务并行运行并不好(或者不容易),但也许我可以使用多线程来提高任务内部的性能。

例如:我们有一个定义为“ImportBizData”的任务,它将数据从数据文件(通常包含 100,0000+ 行)复制到数据库表中。我想知道是否值得使用多线程?

由于我对多线程知之甚少,我希望有人提供一些关于这个主题的教程链接。

【问题讨论】:

  • 在此之前,你是不是已经在使用JDBC批量操作了?
  • 有些任务使用,有些没有
  • 您的直觉是对的,值得研究多线程。我曾经通过完全按照您的想法将八小时的批处理作业转换为 15-20 分钟的作业。
  • 我也有同样的情况。但我面临一个数据库表锁定问题,每次执行它时进程都会挂起。你遇到过这样的问题吗?如何解决?

标签: java multithreading jdbc


【解决方案1】:

多线程将提高您的性能,但您需要了解以下几点:

  1. 每个线程都需要自己的 JDBC 连接。连接不能在线程之间共享,因为每个连接也是一个事务。
  2. 不时以块和commit 的形式上传数据,以避免累积巨大的回滚/撤消表。
  3. 将任务分成几个工作单元,每个单元执行一项工作。

详细说明最后一点:目前,您有一个读取文件、解析文件、打开 JDBC 连接、进行一些计算、将数据发送到数据库等的任务。

你应该做什么:

  1. 一个(!)线程来读取文件并从中创建“作业”。每个工作都应该包含一个小但不太小的“工作单元”。将它们推入队列
  2. 下一个线程等待队列中的作业并进行计算。当第 1 步中的线程等待慢速硬盘返回新的数据行时,可能会发生这种情况。此转换步骤的结果进入下一个队列
  3. 一个或多个线程通过 JDBC 上传数据。

第一个和最后一个线程非常慢,因为它们受 I/O 限制(硬盘很慢,网络连接更差)。另外,在数据库中插入数据是一项非常复杂的任务(分配空间、更新索引、检查外键)

使用不同的工作线程有很多好处:

  1. 单独测试每个线程很容易。由于它们不共享数据,因此您不需要同步。队列会为您做到这一点
  2. 您可以快速更改每个步骤的线程数以调整性能

【讨论】:

    【解决方案2】:

    多线程可能会有所帮助,如果行不相关,您可以启动两个进程,一个读取偶数行,另一个读取不均匀行,然后从连接池 (dbcp) 获取数据库连接并分析性能。但首先我会调查 jdbc 是否是最好的方法,通常数据库对这样的导入有优化的解决方案。这些解决方案还可以暂时切换表的约束检查,稍后再将其重新打开,这对性能也很有好处。一如既往地取决于您的要求。

    您可能还想查看专为批处理而设计的 springbatch。

    【讨论】:

    • “通常数据库对这样的导入有优化的解决方案”是的,但是在那个任务中,我们需要在插入或更新之前做一些计算
    • @YAMaiDie:导出数据,进行计算并创建导入文件。
    【解决方案3】:

    据我所知,JDBC 桥使用同步方法来序列化对 ODBC 的所有调用,因此使用多线程不会给您带来任何性能提升,除非它提升了您的应用程序本身。

    【讨论】:

    • 哦,对了,我最近一直在使用 JDBC-ODCB 桥接器,以至于我几乎忘记了还有本地驱动程序实现 :)
    【解决方案4】:

    我对 JDBC 不是很熟悉,但是关于您的问题的多线程位,您应该记住的是,并行处理依赖于有效地将您的问题划分为彼此独立的位,并以某种方式将它们回到一起(他们的输出就是)。如果您不知道任务之间的底层依赖关系,您最终可能会在代码中遇到非常奇怪的错误/异常。更糟糕的是,它可能全部执行都没有任何问题,但结果可能与真实值不一致。多线程是一项棘手的工作,以一种有趣的方式学习(至少我是这么认为的),但是当事情向南时会让人头疼。

    这里有几个可能有用的链接:

    如果你真的想投入到多线程中,我可以推荐 GOETZ,BRIAN:JAVA CONCURRENCY,真的很棒的书..

    祝你好运

    【讨论】:

      【解决方案5】:

      我有一个类似的任务。但在我的情况下,所有表都彼此无关。

      第 1 步: 使用 SQL Loader(Oracle) 将数据上传到数据库(非常快)或任何类似的数据库批量更新工具。

      第 2 步: 在不同的线程(用于不相关的任务)和单个线程中为相关的任务运行每个上传过程。

      附:您可以在应用程序中识别不同的相互关联的工作,并将它们分组;并在不同的线程中运行每个组。

      助你一臂之力的链接:

      JAVA Threading 按照上面链接中的最后一个示例(示例:使用多个线程对大型任务进行分区)

      SQL Loader can dramatically improve performance

      【讨论】:

        【解决方案6】:

        我发现将大量记录插入 Oracle 的最快方法是使用数组操作。请参阅特定于 OraclePreparedStatement 的“setExecuteBatch”方法。它在此处的示例之一中进行了描述: http://betteratoracle.com/posts/25-array-batch-inserts-with-jdbc

        【讨论】:

          【解决方案7】:

          如果多线程会使您的工作复杂化,您可以使用异步消息传递。我不完全了解您的需求是什么,因此,以下是我目前所看到的。

          1. 创建一个文件阅读器java,其目的是读取biz文件并将消息放入服务器上的JMS队列中。这可能是带有 static void main() 的纯 Java
          2. 使用消息驱动 bean 中的 JMS 消息(您可以设置池中要创建的 bean 数量的限制,根据需要设置为 50 或 100)如果您有多个服务器,很好,您的工作现在拆分为多个服务器。
            1. 每行数据在 2 个服务器和每个服务器上的 50 个 bean 之间异步拆分。

          您不必在整个过程中处理线程,JMS 是理想的,因为您的数据在事务中,如果在您向服务器发送 ack 之前发生故障,消息将重新发送给消费者,负载将在服务器之间拆分,而无需您执行任何特殊操作,例如多线程。

          另外,spring 提供了 spring-batch 可以帮助你。 http://docs.spring.io/spring-batch/reference/html/spring-batch-intro.html#springBatchUsageScenarios

          【讨论】:

            猜你喜欢
            • 2023-01-06
            • 1970-01-01
            • 1970-01-01
            • 2010-09-21
            • 2018-06-12
            • 2014-12-10
            • 1970-01-01
            • 2018-02-23
            • 2013-03-16
            相关资源
            最近更新 更多