文档章节

Java不写文件,LOAD DATA LOCAL INFILE大批量导入数据到MySQL的实现

重生的记忆
 重生的记忆
发布于 2016/03/22 17:07
字数 608
阅读 62
收藏 1

大家都知道当插入大批量数据MySQL的时候,
MySQL使用load data local infile 从文件中导入数据比insert语句要快,MySQL文档上说要快20倍左右。
但是这个方法有个缺点,就是导入数据之前,必须要有文件,也就是说从文件中导入。这样就需要去写文件,
以及文件删除等维护。某些情况下,比如数据源并发的话,还会出现写文件并发问题,很难处理。
那么有没有什么办法,可以达到同样的效率,直接从内存(IO流中)中导入数据,而不需要写文件呢?
前段时间,去MySQL社区的时候发现了这样一个方法:setLocalInfileInputStream(),此方法位于com.mysql.jdbc.PreparedStatement 类中

下面是具体实现:

通过使用 MySQL JDBC 的setLocalInfileInputStream 方法实现从java InputStream中load data local infile 到MySQL数据库中。

 

准备测试表 
SQL如下:

use test;
CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `a` int(11) NOT NULL,
  `b` bigint(20) unsigned NOT NULL,
  `c` bigint(20) unsigned NOT NULL,
  `d` int(10) unsigned NOT NULL,
  `e` int(10) unsigned NOT NULL,
  `f` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `a_b` (`a`,`b`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

 Java代码如下:

package com.dbTools.DBTools;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

import org.apache.log4j.Logger;


public class BulkLoadData2MySQL {

	private static final Logger logger = Logger.getLogger(BulkLoadData2MySQL.class);
	private JdbcTemplate jdbcTemplate;
	private Connection conn = null;

	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	public static InputStream getTestDataInputStream() {
		StringBuilder builder = new StringBuilder();
		for (int i = 1; i <= 10; i++) {
			for (int j = 0; j <= 10000; j++) {

				builder.append(4);
				builder.append("\t");
				builder.append(4 + 1);
				builder.append("\t");
				builder.append(4 + 2);
				builder.append("\t");
				builder.append(4 + 3);
				builder.append("\t");
				builder.append(4 + 4);
				builder.append("\t");
				builder.append(4 + 5);
				builder.append("\n");
			}
		}
		byte[] bytes = builder.toString().getBytes();
		InputStream is = new ByteArrayInputStream(bytes);
		return is;
	}

	/**
	 * 
	 * load bulk data from InputStream to MySQL
	 */
	public int bulkLoadFromInputStream(String loadDataSql,
			InputStream dataStream) throws SQLException {
		if(dataStream==null){
			logger.info("InputStream is null ,No data is imported");
			return 0;
		}
		conn = jdbcTemplate.getDataSource().getConnection();
		PreparedStatement statement = conn.prepareStatement(loadDataSql);

		int result = 0;

		if (statement.isWrapperFor(com.mysql.jdbc.Statement.class)) {

			com.mysql.jdbc.PreparedStatement mysqlStatement = statement
					.unwrap(com.mysql.jdbc.PreparedStatement.class);

			mysqlStatement.setLocalInfileInputStream(dataStream);
			result = mysqlStatement.executeUpdate();
		}
		return result;
	}

	public static void main(String[] args) {
		String testSql = "LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE test.test (a,b,c,d,e,f)";
		InputStream dataStream = getTestDataInputStream();
		BulkLoadData2MySQL dao = new BulkLoadData2MySQL();
		try {
			long beginTime=System.currentTimeMillis();
			int rows=dao.bulkLoadFromInputStream(testSql, dataStream);
			long endTime=System.currentTimeMillis();
			logger.info("importing "+rows+" rows data into mysql and cost "+(endTime-beginTime)+" ms!");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		System.exit(1);
	}

}

 提示:

 String testSql ="LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE test.test (a,b,c,d,e,f)";
 使用setLocalInfileInputStream方法,会直接忽略掉文件名称,而直接将IO流导入到数据库中。
 
参考:
http://assets.en.oreilly.com/1/event/21/Connector_J%20Performance%20Gems%20Presentation.pdf
http://jeffrick.com/2010/03/23/bulk-insert-into-a-mysql-database/

© 著作权归作者所有

重生的记忆
粉丝 1
博文 12
码字总数 17685
作品 0
石景山
高级程序员
私信 提问
在Hibernate中用PostgreSQL的COPY API

PostgreSQL有一个用于高速导入导出数据的COPY 命令,使用JDBC可以调用,但是在Hibernate中调用要麻烦一些,这是Hibernate4.1下用c3p0连接池时的调用方法: public CopyManager getCopyManage...

SunLee
2012/11/26
0
2
shell脚本中使用sqlldr导入数据失败

使用java从远程数据库中导出数据,再导入生产库中,如果直接使用jdbc导入的话,太慢了,需要时间很长,所以想到用sqlldr工具, 由于涉及多个表,所以使用多条命令分别对每个表的数据进行导入...

天涯明月稻
2013/12/16
2.1K
3
phpMyAdmin LOAD DATA INFILE 任意文件读取漏洞

转载自:phpMyAdmin LOAD DATA INFILE 任意文件读取漏洞 有许多文章指出一个恶意的 MySQL 服务器可以利用LOAD DATA LOCAL命令来读取MYSQL客户端的任意文件。根据这篇公开的文章 (phpMyAdmin开...

ambulong2
2018/12/15
0
0
Centos 7.5 + solr 7.4 (jetty启动)+MySQL 5.7

1. 安装jdk 1.8 环境 1.1 下载jdk 1.8 安装包jdk-8u181-linux-x64.rpm 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 1.2 安装 rpm -ivh......

lrtao2010
2018/07/24
0
0
MySql批量数据导入Load data infile解决方案

有时候我们需要将大量数据批量写入数据库,直接使用程序语言和Sql写入往往很耗时间,其中有一种方案就是使用MySql Load data infile导入文件的形式导入数据,这样可大大缩短数据导入时间。 ...

小小人故事
2015/11/25
130
0

没有更多内容

加载失败,请刷新页面

加载更多

Nginx源码安装和调优技巧

本文内容 Nginx与apache的对比 实战1:在“腾讯云主机”上源码编译安装Nginx 实战2:Nginx调优之隐藏版本信息防止黑客扫描识别漏洞 实战3:设置网页缓存 实验环境: 使用RHEL6.5/centos6.5 6...

寰宇01
6分钟前
0
0
买卖股票的最佳时机-LeetCode

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 注意你不能在买入股票前卖...

事儿爹
10分钟前
0
0
mysql根据分隔符进行字段拆分

虽然已经有很多类似的写法,我这里还是自己写一写,有些分隔符分出的列数是不固定的,这时候怎么根据分隔符拆分出多列呢 insert into tpems.sp_questions_bank (id, title, option_a, option...

无知的小狼
19分钟前
0
0
vue+antdesign模态框实现父子组件之间传值

vue中实现父子组件间单向数据流传递比较方便,子组件通过prop接收父组件传递过来的值,父组件通过监听子组件emit出的函数接收子组件传递的值。 1、父组件向子组件传值(prop) 父组件先绑定值...

苇草66083
21分钟前
4
0
JDBC直接读取properties,连接数据库的util类

完整代码如下:拼凑的代码,源代码不知道从哪来的了。见谅! 使用的话直接在自己的service或dao注入 package com.javafast.util;import com.alibaba.druid.pool.DruidDataSource;import co...

S三少S
34分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部