java大批量数据导入(MySQL)

? 版权声明:本文为博主原创文章,转载请注明出处

最近同事碰到大批量数据导入问题,因此也关注了一下。大批量数据导入主要存在两点问题:内存溢出和导入速率慢。

内存溢出:将文件中的数据全部取出放在集合中,当数据过多时就出现Java内存溢出,此时可通过调大JVM的最大可用内存(Xmx)解决,

        但终究不是王道。

        MySQL支持一条SQL语句插入多条记录的操作,并且效率比单条插入快的不是一点点;但是MySQL一次可接受的数据包大小

        也是有限制的,当一次插入过多时也可能造成数据包内存溢出,此时可通过调大MySQL的max_allowed_packet 解决,

        但也不是王道。

导入速率慢:单条插入就不用考虑了,因此考虑一条SQL语句插入多条记录,

        根据上述所说还应控制好一条插入的数据大小不能超过max_allowed_packet 的配置。

下面比较了用PreparedStatement和直接拼接SQL两种批量插入的方式的速率(一次插入1w条)

package org.javaio.CSV;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.mysql.jdbc.Connection;

/**
 * 导入大批量CSV文件
 *
 */
public class Test {

	/**
	 * jdbc所属,暂不使用
	 */
	private final static String url = "jdbc:mysql://localhost:3306/demo_test?useSSL=true&characterEncoding=utf8";
	private final static String name = "root";
	private final static String pwd = "20121221";
	private static Connection conn;
	private static PreparedStatement ps;

	/**
	 * 解析csv文件并插入到数据库中,暂不使用(jdbc)
	 *
	 * @param args
	 *
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {

		Test test = new Test();

		// psBatch 时间统计 - 开始
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String startTime = sdf.format(new Date());
		System.out.println("psBatch 开始时间为:" + startTime);
		System.out.println("psBatch 开始执行...");

		// 使用PreparedStatement批量插入
		int idx = test.psBatch();

		// 统计时间 - 结束
		System.out.println("psBatch 执行完成,共插入" + idx + "条数据");
		String endTime = sdf.format(new Date());
		System.out.println("psBatch 结束时间为:" + endTime);

		System.out.println();

		// 时间统计 - 开始
		startTime = sdf.format(new Date());
		System.out.println("sqlBatch 开始时间为:" + startTime);
		System.out.println("sqlBatch 开始执行...");

		// 使用SQL语句批量插入
		idx = test.sqlBatch();

		// 统计时间 - 结束
		System.out.println("sqlBatch 执行完成,共插入" + idx + "条数据");
		endTime = sdf.format(new Date());
		System.out.println("sqlBatch 结束时间为:" + endTime);

	}

	/**
	 * 使用PreparedStatement批量插入
	 *
	 * @return
	 *
	 * @throws Exception
	 */
	private int psBatch() throws Exception {

		int idx = 0;// 行数

		try {
			// 读取CSV文件
			FileInputStream fis = new FileInputStream("C:/Users/chen/Desktop/data/ceshi .csv");
			InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
			BufferedReader br = new BufferedReader(isr);

			String line;// 行数据
			String[] column = new String[4];// 列数据

			// 获取数据库连接
			conn = getConnection();
			// 设置不自动提交
			conn.setAutoCommit(false);

			// SQL
			String sql = "insert into test (name, `desc`, column1, column2, column3, column4) "
					+ "values (?, ?, ?, ?, ?, ?)";
			ps = conn.prepareStatement(sql);

			while ((line = br.readLine()) != null) {// 循环读取每一行
				idx++;// 计数
				column = line.split(",");
				ps.setString(1, column[0]);
				if (column.length >= 2 && column[1] != null) {
					ps.setString(2, column[1]);
				} else {
					ps.setString(2, "");
				}
				if (column.length >= 3 && column[2] != null) {
					ps.setString(3, column[2]);
				} else {
					ps.setString(3, "");
				}
				if (column.length >= 4 && column[3] != null) {
					ps.setString(4, column[3]);
				} else {
					ps.setString(4, "");
				}
				ps.setString(5, "type");
				ps.setString(6, "1");
				ps.addBatch();
				if (idx % 10000 == 0) {
					ps.executeBatch();
					conn.commit();
					ps.clearBatch();
				}
			}
			if (idx % 10000 != 0) {
				ps.executeBatch();
				conn.commit();
				ps.clearBatch();
			}
		} catch (Exception e) {
			System.out.println("第" + idx + "前一万条数据插入出错...");
		} finally {
			try {
				if (ps != null) {
					// 关闭连接
					ps.close();
				}
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}

		return idx;

	}

	/**
	 * 使用sql语句批量插入
	 *
	 * @return
	 *
	 * @throws Exception
	 */
	private int sqlBatch() {

		int idx = 0;// 行数

		try {

			// 读取CSV文件
			FileInputStream fis = new FileInputStream("C:/Users/chen/Desktop/data/ceshi .csv");
			InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
			BufferedReader br = new BufferedReader(isr);

			String line;// 行数据
			String[] column = new String[4];// 列数据

			// 获取数据库连接
			conn = getConnection();

			// SQL
			StringBuffer sql = new StringBuffer("insert into test (name, `desc`, column1, column2, column3, column4) "
					+ "values ");

			while ((line = br.readLine()) != null) {// 循环读取每一行
				idx++;// 计数
				column = line.split(",");
				sql.append("(‘" + column[0] + "‘, ‘");
				if (column.length >= 2 && column[1] != null) {
					sql.append(column[1] + "‘, ‘");
				} else {
					sql.append("‘, ‘");
				}
				if (column.length >= 3 && column[2] != null) {
					sql.append(column[2] + "‘, ‘");
				} else {
					sql.append("‘, ‘");
				}
				if (column.length >= 4 && column[3] != null) {
					sql.append(column[3] + "‘, ‘");
				} else {
					sql.append("‘, ‘");
				}
				sql.append("type‘, ‘1‘),");
				if (idx % 10000 == 0) {
					String executeSql = sql.toString().substring(0, sql.toString().lastIndexOf(","));
					ps = conn.prepareStatement(executeSql);
					ps.executeUpdate();
					sql = new StringBuffer("insert into test (name, `desc`, column1, column2, column3, column4) "
							+ "values ");
				}
			}
			if (idx % 10000 != 0) {
				String executeSql = sql.toString().substring(0, sql.toString().lastIndexOf(","));
				ps = conn.prepareStatement(executeSql);
				ps.executeUpdate();
			}
		} catch (Exception e) {
			System.out.println("第" + idx + "前一万条数据插入出错...");
		} finally {
			try {
				if (ps != null) {
					// 关闭连接
					ps.close();
				}
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}

		return idx;

	}

	/**
	 * 获取数据库连接
	 *
	 * @param sql
	 * 				SQL语句
	 */
	private Connection getConnection() throws Exception {

		Class.forName("com.mysql.jdbc.Driver");
		conn = (Connection) DriverManager.getConnection(url, name, pwd);
		return conn;

	}

}

速率比较:为了排除其他影响,两次次都是在空表的情况下进行导入的

  用SQL拼接批量插入用时大概3-4分钟

  用PreparedStatement批量插入用时大概10分钟

时间: 2024-10-06 07:13:04

java大批量数据导入(MySQL)的相关文章

将Excel数据导入mysql数据库的几种方法

将Excel数据导入mysql数据库的几种方法 “我的面试感悟”有奖征文大赛结果揭晓! 前几天需要将Excel表格中的数据导入到mysql数据库中,在网上查了半天,研究了半天,总结出以下几种方法,下面和大家分享一下: 一.用java来将Excel表格中的数据转到mysql中 这是我们用的第一种方法,就是在java找你感谢个类,然后这个类会将Excel表格中的数据存储到内存里,然后再从内存中读出来插入到数据库中,但是要 注意了,这里是存储到String[ ]数组里面,所以取出来的数据也是Strin

SQL Server 数据导入Mysql详细教程

SQL Server 数据导入Mysql详细教程 SQL Server数据库和Mysql 数据库都是关系型数据库,虽然很多数据库都对SQL语句进行了再开发和扩展,使得在不同的数据库中执行的方法或用法不一,但是 SQL Server,Mysql ,Access等都采用了SQL语言标准,不同的数据库中的数据是可以导入的.对于大数据的导入是有相当大的意义. 今天,我和大家一起分享一下,我用的便捷的"sql server 数据导入mysql 中的方法",希望能给大家的项目开发中"sq

[Python]将Excel文件中的数据导入MySQL

Github Link 需求 现有2000+文件夹,每个文件夹下有若干excel文件,现在要将这些excel文件中的数据导入mysql. 每个excel文件的第一行是无效数据. 除了excel文件中已有的数据,还要添加一列,名为“at_company”,值为821. 流程 (1)获取excel文件列表,并根据excel文件名确定之后需要创建的table名: (2)连接mysql (3)创建table (4)插入数据 (5)断开连接 依赖模块 1. xlrd # to read excel fil

Excel连接到MySQL,将Excel数据导入MySql,MySQL for Excel,,

Excel连接到MySQL 即使当今时代我们拥有了类似微软水晶报表之类的强大报表工具和其他一些灵活的客户管 理应用工具,众多企业在分析诸如销售统计和收入信息的时候,微软的Excel依然是最常用的工具.这当然不是没有理由的:Excel以其强大丰富的各种功 能,已经成为办公环境中不可或缺的工具. 然而,现在公司正在逐渐地将数据开始存储在远程数据库中,这样可以供企业员工从不同的地方来阅读和修改数据.但是,以前固有的工作流程习惯是很难打破的.当你的老板需要从远端使用Excel以饼图的形势来看一下最近的销

使用MySQL Migration Toolkit快速将Oracle数据导入MySQL[转]

使用MySQL Migration Toolkit快速将Oracle数据导入MySQL上来先说点废话本人最近在学习一些数据库方面的知识,之前接触过Oracle和MySQL,最近又很流行MongoDB非关系型数据库,所以干脆一起研究一下,对比学习中找不同,首先说一下本人使用的数据库版本和可视化工具Oracle10G—PL/SQL Developer9MySQL5.5.29—MySQL Workbench6.0MongoDB2.4.9(32bit最大2G)—Robomongo0.8.4为了保持数据的

postgresql大批量数据导入方法

一直没有好好关注这个功能,昨天看了一下,数据库插入有瓶颈,今天研究了一下: 主要有以下方案: 1.使用copy从文件导入: copy table_001(a, b, "f", d, c, "e") from 'd:/data1.txt' (delimiter ','); 速度极快: 不带索引: 查询成功: 共计 69971 行受到影响,耗时: 4351 毫秒(ms).        查询成功: 共计 69971 行受到影响,耗时: 4971 毫秒(ms).     

使用MySQLMigrationToolkit快速将Oracle数据导入MySQL

使用MySQL Migration Toolkit快速将Oracle数据导入MySQL 上来先说点废话 本人最近在学习一些数据库方面的知识,之前接触过Oracle和MySQL,最近又很流行MongoDB非关系型数据库,所以干脆一起研究一下,对比学习中找不同,首先说一下本人使用的数据库版本和可视化工具 Oracle10G—PL/SQL Developer9 MySQL5.5.29—MySQL Workbench6.0 MongoDB2.4.9(32bit最大2G)—Robomongo0.8.4 为

大批量数据导入

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Med

将Excel数据导入MySQL

去年的投资统计月报数据量庞大,原始表格是xls格式(还是EXECL2003的),单个sheet最大只能放几万行,但数据总量有10万行以上,于是只能存成两个sheet.EXECL2010格式倒是单个sheet可以放得下,可是居然不能将数据完整的从一个sheet复制粘贴到另一个sheet(可能是因为行数太多).正好想学习一下execl数据导入MySQL数据库的方法,于是开始尝试. 一开始使用的是MySQL for Execl功能,在安装MySQL的时候安装此控件,在Excel的数据菜单下可以直接调用