相关文章推荐
潇洒的大海  ·  SQL ...·  3 年前    · 

本篇文章给大家带来的内容是关于Java多线程批量数据导入的方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

前言:当遇到大量数据导入时,为了提高处理的速度,可以选择使用多线程来批量处理这些处理。常见的场景有:大文件导入数据库(这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理)

数据同步(从第三方接口拉取数据处理后写入自己的数据库)

以上的场景有一个共性,这类数据导入的场景简单来说就是将数据从一个数据源移动到另外一个数据源,而其中必定可以分为两步数据读取:从数据源读取数据到内存

数据写入:将内存中的数据写入到另外一个数据源,可能存在数据处理

而且数据读取的速度一般会比数据写入的速度快很多,即读取快,写入慢。

由于场景的特点是读取快,写入慢,如果是使用多线程处理,建议是数据写入部分改造为多线程。而数据读取可以改造成批量读取数据。简单来说就是两个要点:批量读取数据

多线程写入数据

多线程批量处理最简单的方案是使用线程池来进行处理,下面会通过一个模拟批量读取和写入的服务,以及对这个服务的多线程写入调用作为示例,展示如何多线程批量数据导入。

模拟服务import java.util.concurrent.atomic.AtomicLong;

* 数据批量写入用的模拟服务

* @author RJH

* create at 2019-04-01

public class MockService {

* 可读取总数

private long canReadTotal;

* 写入总数

private AtomicLong writeTotal=new AtomicLong(0);

* 写入休眠时间(单位:毫秒)

private final long sleepTime;

* 构造方法

* @param canReadTotal

* @param sleepTime

public MockService(long canReadTotal, long sleepTime) {

this.canReadTotal = canReadTotal;

this.sleepTime = sleepTime;

* 批量读取数据接口

* @param num

* @return

public synchronized long readData(int num) {

long readNum;

if (canReadTotal >= num) {

canReadTotal -= num;

readNum = num;

} else {

readNum = canReadTotal;

canReadTotal = 0;

//System.out.println("read data size:" + readNum);

return readNum;

* 写入数据接口

public void writeData() {

try {

// 休眠一定时间模拟写入速度慢

Thread.sleep(sleepTime);

} catch (InterruptedException e) {

e.printStackTrace();

// 写入总数自增

System.out.println("thread:" + Thread.currentThread() + " write data:" + writeTotal.incrementAndGet());

* 获取写入的总数

* @return

public long getWriteTotal() {

return writeTotal.get();

批量数据处理器import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

* 基于线程池的多线程批量写入处理器

* @author RJH

* create at 2019-04-01

public class SimpleBatchHandler {

private ExecutorService executorService;

private MockService service;

* 每次批量读取的数据量

private int batch;

* 线程个数

private int threadNum;

public SimpleBatchHandler(MockService service, int batch,int threadNum) {

this.service = service;

this.batch = batch;

//使用固定数目的线程池

this.executorService = Executors.newFixedThreadPool(threadNum);

* 开始处理

public void startHandle() {

// 开始处理的时间

long startTime = System.currentTimeMillis();

System.out.println("start handle time:" + startTime);

long readData;

while ((readData = service.readData(batch)) != 0) {// 批量读取数据,知道读取不到数据才停止

for (long i = 0; i < readData; i++) {

executorService.execute(() -> service.writeData());

// 关闭线程池

executorService.shutdown();

while (!executorService.isTerminated()) {//等待线程池中的线程执行完

// 结束时间

long endTime = System.currentTimeMillis();

System.out.println("end handle time:" + endTime);

// 总耗时

System.out.println("total handle time:" + (endTime - startTime) + "ms");

// 写入总数

System.out.println("total write num:" + service.getWriteTotal());

测试类/**

* SimpleBatchHandler的测试类

* @author RJH

* create at 2019-04-01

public class SimpleBatchHandlerTest {

public static void main(String[] args) {

// 总数

long total=100000;

// 休眠时间

long sleepTime=100;

// 每次拉取的数量

int batch=100;

// 线程个数

int threadNum=16;

MockService mockService=new MockService(total,sleepTime);

SimpleBatchHandler handler=new SimpleBatchHandler(mockService,batch,threadNum);

handler.startHandle();

运行结果start handle time:1554298681755

thread:Thread[pool-1-thread-2,5,main] write data:1

thread:Thread[pool-1-thread-1,5,main] write data:2

...省略部分输出

thread:Thread[pool-1-thread-4,5,main] write data:100000

end handle time:1554299330202

total handle time:648447ms

total write num:100000

在单线程情况下的执行时间应该为total*sleepTime,即10000000ms,而改造为多线程后执行时间为648447ms。

【相关推荐:Java视频教程】

详细内容本篇文章给大家带来的内容是关于Java多线程批量数据导入的方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。前言:当遇到大量数据导入时,为了提高处理的速度,可以选择使用多线程来批量处理这些处理。常见的场景有:大文件导入数据库(这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理)数据同步(从第三方接口拉取数据处理后写入自己的数据库)以上的场景有一个共性...
Oracle SQL Hand-Oracle工具,是专为Oracle 数据 库开发人员及操作人员精心打造的一款Oracle开发工具(客户端工具)。 Oracle SQL Hand-Oracle工具特点如下: (1) 跨平台,能运行于平台 Windows(WIN7,XP...)、Linux 、Mac OS; (2) 不需要安装Oracle客户端,解压即用,通过提供的JDBC直接连接服务器; (3) 超智能的SQL编辑器,具有代码跟踪提示功能,弹出提示窗口列出关键字、关键字组合、函数名、列名、对象名、对象类型等,极大地提高SQL编辑效率; (4) 超方便实用的工作表用来显示和操作SELECT语句的查询结果,象操作Excel表格一样方便地选择行/列/单元格 数据 ,可以将工作表的 数据 修改 写入 数据 库表。另外,工作表还有单条记录操作、多功能拷贝、数值统计、查找替换等实用功能; (5) 能方便导出 XLS、 CSV 、INSERT Statement、HTML、XML等多种格式 数据 ; (6) 方便操作常用 数据 字典如表、视图、索引、过程、函数、触发器等(能显示和编辑编译PL/SQL代码); (7) 中英文双语界面并能随时切换,个性化界面设置,界面简洁清爽; (8) 运行语句“DESC tableName”清晰地显示表的所有逻辑结构信息,包括列信息、所有约束、索引、子表及触发器等; (9) 运行语句“SCHEMA objectName”显示表或视图的DDL源码; (10) 以缩进的阶梯格式清晰地显示SQL的解释计划; (11) 能运行和调试PL/SQL语句,能精确定位到错误所在的行列位置; (12) SQL格式美化,将杂乱的语句美化成缩进的美观格式; (13) 多线程 多连接,会话在运行中可以中断,或编辑,或创建新会话; (14) 监控 批量 SQL语句的运行,在运行中可暂停、更正等; (15) 连接配置简单,自动重新连接; (16) 占用系统资源极少,启动快,连接快,运行快; (17) 高效的语句块操作,高亮显示配对括号; (18) 功能实用,操作简便; 鼠标双击批处理 文件 start.bat 即可启动运行
平面 文件 读取:从平面 文件 读取(并 写入 数据 库) 跳过:跳过 CSV 文件 中格式错误的行,而不是崩溃 动态工作参数:将参数传递给工作伪像(例如,输入 文件 到项目阅读器) JDBC分页:使用分页从 数据 库中读取大型结果集 执行元 数据 :了解Spring Batch如何存储执行元 数据 以启用重新启动并简化监视 调度:使用Spring调度支持定期执行作业 项目处理器:将业务逻辑嵌入到ItemProcessor中 记录跳过的项目:使用跳过侦听器记录跳过的项目 文件 读取分区: 文件 的 多线程 读取和处理 文件 删除启动:FTP服务器上有新 文件 时启动作业 数据 库读取分区:从 数据 库读取分类的项目并将其 写入 文件 数据 组同事需要一个小工具帮组他们处理一些 数据 。首先他们的原 数据 是 csv 文件 的,需要我们把里面的 数据 和别的系统里面的 数据 逐条匹配完善后返回给他们一个 csv 文件 。原 数据 的 csv 一般3-5万条 数据 量(单列的)。 解决方案: 首先读取 csv 文件 ,生成待处理 数据 集合。然后把该 数据 集合分片,以使用 多线程 进行匹配处理。最后通过POI生成 csv 输出。(一开始同事没有使用 多线程 ,虽然 数据 量不算大,但是...
Service Mesh技术作为新一代微服务架构,有效的解决了当前微服务架构和治理过程中的痛点问题,一经推出便引起很大的反响,近两年持续成为架构领域的热点。特别是Google联合Lyft等公司推出的Istio,架构优雅,功能强大,迅速成为Service Mesh领域的明星项目。 什么是Service Mesh 作为Service Mesh技术探索和实践的先行者,全球第一个真正的Se...
相信小伙伴们在做后台开发的时候,经常要用到CRUD。经常用CRUD并不丢人,关键是怎么把CRUD用到更简洁、更极致,这样的一直下去的话,其实你慢慢的也成为了你眼中的那些大神们。我这里是用到了 JDK1.8的一些特性,不了解 JDK1.8的新特性的话,可以先简单了解一下。 好了,废话不多说,我直接上代码了。 二、代码实现 package com.riemann.springbootdemo... 目前需要将大量 数据 (存在少量的重复 数据 )初始化 写入 数据 库表(该表开始无 数据 ),在避免重复 数据 写入 如何保证 写入 速率? 网络上已有方案 网络上已有的方案大概分为两类: 通过SQL实现 1.先 写入 ,后去重。 2.insert ignore。insert ignore语法会忽略执行出错的行,因此 写入 数据 以第一条为准。 3.replace into和insert … on duplicate key update。这两种语句都是通过替换原有的重复 数据 来避免重复 数据 写入 的问题。 通过代码逻辑控制 1.通过try…