在此笔记里,我们将看到我们如何可以使用像Statement和PreparedStatement JDBC API来批量在任何数据库中插入数据。此外,我们将努力探索一些场景,如在内存不足时正常运行,以及如何优化批量操作。

首先,使用Java JDBC基本的API批量插入数据到数据库中。

Simple Batch - 简单批处理
    我把它叫做简单批处理。要求很简单,执行批量插入列表,而不是为每个INSERT语句每次提交数据库,我们将使用JDBC批处理操作和优化性能。

想想一下下面的代码:

Bad Code
String [] queries = {
"insert into employee (name, city, phone) values ('A', 'X', '123')",
"insert into employee (name, city, phone) values ('B', 'Y', '234')",
"insert into employee (name, city, phone) values ('C', 'Z', '345')",
};
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.execute(query);
}
statemenet.close();
connection.close();

这是糟糕的代码。它单独执行每个查询,每个INSERT语句的都提交一次数据库。考虑一下,如果你要插入1000条记录呢?这是不是一个好主意。

下面是执行批量插入的基本代码。来看看:

Good Code

Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (String query : queries) {
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();

请注意我们如何使用addBatch()方法,而不是直接执行查询。然后,加入所有的查询,我们使用statement.executeBatch()方法一次执行他们。没有什么花哨,只是一个简单的批量插入。

请注意,我们已经从一个String数组构建了查询。现在,你可能会想,使其动态化。例如:

import java.sql.Connection;
import java.sql.Statement;
//...
Connection connection = new getConnection();
Statement statemenet = connection.createStatement();
for (Employee employee: employees) {
String query = "insert into employee (name, city) values('"
+ employee.getName() + "','" + employee.getCity + "')";
statemenet.addBatch(query);
}
statemenet.executeBatch();
statemenet.close();
connection.close();

请注意我们是如何从Employee对象中的数据动态创建查询并在批处理中添加,插入一气呵成。完美!是不是?

等等......你必须思考什么关于SQL注入?这样动态创建的查询SQL注入是很容易的。并且每个插入查询每次都被编译。

为什么不使用PreparedStatement而不是简单的声明。是的,这是个解决方案。下面是SQL注入安全批处理。

SQL Injection Safe Batch - SQL注入安全批处理
思考一下下面代码:

import java.sql.Connection;
import java.sql.PreparedStatement;
//...
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
}
ps.executeBatch();
ps.close();
connection.close();

看看上面的代码。漂亮。我们使用的java.sql.PreparedStatement和在批处理中添加INSERT查询。这是你必须实现批量插入逻辑的解决方案,而不是上述Statement那个。

这一解决方案仍然存在一个问题。考虑这样一个场景,在您想要插入到数据库使用批处理上万条记录。嗯,可能产生的OutOfMemoryError:

java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)

这是因为你试图在一个批次添加所有语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案

Smart Insert: Batch within Batch - 智能插入:将整批分批
这是一个简单的解决方案。考虑批量大小为1000,每1000个查询语句为一批插入提交。

String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
final int batchSize = 1000;
int count = 0;
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
if(++count % batchSize == 0) {
ps.executeBatch();
}
}
ps.executeBatch(); // insert remaining records
ps.close();
connection.close();

这才是理想的解决方案,它避免了SQL注入和内存不足的问题。看看我们如何递增计数器计数,一旦BATCHSIZE 达到 1000,我们调用executeBatch()提交。

Java JDBC批处理插入数据操作(转)的更多相关文章

  1. Java JDBC批处理插入数据操作

    在此笔记里,我们将看到我们如何可以使用像Statement和PreparedStatement JDBC API来批量在任何数据库中插入数据.此外,我们将努力探索一些场景,如在内存不足时正常运行,以及 ...

  2. JDBC批量插入数据优化,使用addBatch和executeBatch

    JDBC批量插入数据优化,使用addBatch和executeBatch SQL的批量插入的问题,如果来个for循环,执行上万次,肯定会很慢,那么,如何去优化呢? 解决方案:用 preparedSta ...

  3. JDBC批量插入数据效率分析

    对于需要批量插入数据库操作JDBC有多重方式,本利从三个角度对Statement和PreparedStatement两种执行方式进行分析,总结较优的方案. 当前实现由如下条件: 执行数据库:Mysql ...

  4. MySQL:JDBC批量插入数据的效率

    平时使用mysql插入.查询数据都没有注意过效率,今天在for循环中使用JDBC插入1000条数据居然等待了一会儿 就来探索一下JDBC的批量插入语句对效率的提高 首先进行建表 create tabl ...

  5. Java API —— IO流(数据操作流 & 内存操作流 & 打印流 & 标准输入输出流 & 随机访问流 & 合并流 & 序列化流 & Properties & NIO)

    1.操作基本数据类型的流     1) 操作基本数据类型 · DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型.应用程序可以使用数据输出 ...

  6. Java -- JDBC 批处理

    两种批处理方式: 采用Statement.addBatch(sql)方式实现批处理: •优点:可以向数据库发送多条不同的SQL语句. •缺点: •SQL语句没有预编译. •当向数据库发送多条语句相同, ...

  7. mysql创建表及插入数据操作步骤及注意要点

    环境:mysql workbench 1.创建新的表,注意,指定要存放的数据库 列名可以加单引号(键盘上1左边的引号),也可以不加 2.插入数据 注意:如果数据是字符型,必须使用单引号或者双引号,如: ...

  8. JDBC基础学习(五)—批处理插入数据

    一.批处理介绍      当需要成批插入或者更新记录时.可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理.通常情况下比单独提交处理更有效率. JDBC的批量处理语句包括下 ...

  9. JDBC连接数据库:单线程、多线程、批处理插入数据的对比

    一.单线程(单条循环)插入50000条记录: 每执行一次就要访问一次数据库 import java.sql.Connection; import java.sql.DriverManager; imp ...

随机推荐

  1. nginx处理静态资源的配置

    修改nginx.conf文件,用于nginx处理静态资源. 主要配置如下(在server配置中加入location配置即可): server { listen 80; server_name 123. ...

  2. ThinkPHP3.1快速入门(3)查询语言

    http://www.thinkphp.cn/info/115.html 介绍 ThinkPHP内置了非常灵活的查询方法,可以快速的进行数据查询操作,查询条件可以用于读取.更新和删除等操作,主要涉及到 ...

  3. 完美卸载SQL Server 2008的方案

    转自完美卸载SQL Server 2008的方案 针对SQL数据库卸载不完全的现象,做了如下总结:   1,控制面板 卸载   首先,打开控制面板,按照"安装时间"进行排序,卸载S ...

  4. Desert King

    poj2728:http://poj.org/problem?id=2728 题意:给你n的点,每一个点会有一个坐标(x,y),然后还有一个z值,现在上你求一棵生成树,是的这棵生成树的所有边的费用/所 ...

  5. 标准MD5加密算法

    标准MD5加密算法: public class Md5 { public static String getMd5(String s) { char hexDigits[] = { '0', '1', ...

  6. java学习之线程

    一.线程总述: 线程是java当中一个重要的内容,如果想说线程的话,那我们应该先来讲一下什么是进程. 进程:那么什么是进程呢,进程从字面上来理解就是,正在进行的程序.就比如说我们在windows当中打 ...

  7. [FJSC2014]滑行

    [题目描述] 首长NOI惨跪,于是去念文化课了.现在,他面对一道物理题. 现在有一个小滑块可以在地面上滑行,地面上被划分成不同的区域,使得小滑块在不同的区域内部有一个不同的速度上限. 小滑块在(0,0 ...

  8. WordPress Complete Gallery Manager插件‘upload-images.php’任意文件上传漏洞

    漏洞名称: WordPress Complete Gallery Manager插件‘upload-images.php’任意文件上传漏洞 CNNVD编号: CNNVD-201309-377 发布时间 ...

  9. Scala:(3)数组

    要点: (1)长度固定使用Array,长度变化的则使用ArrayBuffer. (2)提供初始值时,不使用new. (3)用()访问元素 val a= new Array[String](10)//初 ...

  10. 【转】Android中intent传递对象和Bundle的用法

    原文网址:http://blog.csdn.net/lixiang0522/article/details/8642202 android中的组件间传递的对象一般实现Parcelable接口,当然也可 ...