【问题标题】:Java Spring: How to efficiently read and save large amount of data from a CSV file?Java Spring:如何有效地从 CSV 文件中读取和保存大量数据?
【发布时间】:2017-12-09 17:18:40
【问题描述】:

我正在使用 Java Spring 开发一个 Web 应用程序,我希望用户能够从前端上传 CSV 文件,然后查看导入过程的实时进度,导入后他应该能够从导入的数据中搜索单个条目。

导入过程包括实际上传文件(通过 REST API POST 请求发送),然后读取文件并将其内容保存到数据库,以便用户能够从这些数据中进行搜索。

将数据保存到数据库中最快的方法是什么? 仅循环这些行并创建一个新的类对象并通过 JPARepository 为每一行保存它会花费太多时间。 10000 行大约需要 90 秒。我需要让它更快。我需要在合理的时间内添加 200k 行。

旁注:

我看到了使用 Reactor 的异步方法。这应该更快,因为它使用多个线程并且保存行的顺序基本上并不重要(尽管数据在 CSV 中有 ID)。

然后我也看到了 Spring Batch 作业,但是所有示例都使用 SQL。我正在使用存储库,所以我不确定我是否可以使用它或者它是否是最好的方法。

【问题讨论】:

  • 你有什么问题?标题要求实时进度,问题还要求在“合理”时间内以“最快”的方式保存到数据库。以及涉及 Spring Batch。这已经是3个问题了。听起来您对设计不清楚,这就是您的问题过于宽泛的原因。
  • 对不起,这是我的错。我开始描述我的整个情况,然后决定将我所有的问题分解为不同的问题。我的错误是我用错误的标题发布它。我会立即更改它。但我认为 Spring Batch 将是更快处理更多数据的一种选择,不是吗?

标签: java spring spring-mvc spring-boot spring-data-jpa


【解决方案1】:

This GitHub repo 比较了 5 种不同的批量插入数据的方法。会计。对他来说,使用JdbcTemplate 是最快的(他声称在 1.79 [+- 0.50] 秒内有 500000 条记录)。如果您将JdbcTemplate 与 Spring Data 一起使用,则需要创建一个自定义存储库;有关详细说明,请参阅文档中的 this 部分。

Spring Data CrudRepository 有一个采用Iterablesave 方法,因此您也可以使用它,尽管您必须花时间看看它对JdbcTemplate 的执行情况。使用 Spring Data,步骤如下(取自here,稍作修改)

  1. 在连接字符串的末尾添加:rewriteBatchedStatements=true
  2. 确保您在实体中使用支持批处理的生成器。例如

    @Id
    @GeneratedValue(generator = "generator")
    @GenericGenerator(name = "generator", strategy = "increment")
    
  3. 使用CrudRepository的:save(Iterable<S> entities)方法保存数据。

  4. 使用:hibernate.jdbc.batch_size 配置。

解决方案#2 的代码是here

至于使用多个线程,请记住,从多个线程写入数据库中的同一个表可能会产生表级争用并产生更糟糕的结果。您将不得不尝试并计时。如何使用项目 Reactor 编写多线程代码是一个完全独立的主题,超出了这里的范围。

HTH。

【讨论】:

  • 您好,我之前无法尝试您的建议。但我认为在使用save 方法之前,我必须从CSV 文件中读取行(我目前使用FileReader 进行读取,然后使用CSVFormat.parse 将行解析为Iterable<CSVRecord>)和然后遍历它们,为每个创建我的实体类对象,然后将它们添加到某种Iterable 以保存到数据库中?我的意思是,我的 CSV 文件读取、遍历行和创建类实例可能是耗时的部分。但我会先试试JdbcTemplate
  • 好的,我试了JdbcTemplate,效果很好。如果通过一个一个循环并保存到数据库,100 行大约需要 0.86 秒,1000 行需要 4.3 秒,10k 行需要 112 秒(我什至没有尝试更大的文件),那么现在我从该文件在 1.13 秒内保存到数据库,整个 200k 行文件耗时 9 秒。当然,它仍然比他的示例慢 4-5 倍(与他的 1 相比,我有一个具有 5 个属性的实体),但这对我来说已经足够了 :) 非常感谢!
【解决方案2】:

如果您使用 SQLServer,只需创建一个 SSiS 包来查找文件,当它出现时,只需抓取并加载它,然后重命名文件。这使它成为一次构建和一百万次执行,并且 SSIS 可以相当快地加载大量数据。 瑞克

【讨论】:

  • 抱歉,我目前正在创建一个简单的应用程序。我正在使用 JPA 存储库方法将数据保存到 H2 数据库。我看到可以将 SQLServer 与 Java Spring 一起使用,但是对于这样的问题,这个解决方案似乎有点太复杂了。我只想在用户上传文件后触发文件处理。目前,大数据 ETL 解决方案可能有点过头了。
猜你喜欢
  • 1970-01-01
  • 2015-01-29
  • 2012-08-30
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 2011-02-11
  • 2019-05-03
相关资源
最近更新 更多