声明转载:文章受权转载自yuimenu的blog,地址:http://lavasoft.blog.51cto.com/62575/238651 英文原文地址:http://viralpatel.net/blogs/batch-insert-in-java-jdbc/java
让咱们看看如何使用JDBC API在Java中执行批量插入。虽然你可能已经知道,但我会尽力解释基础到复杂的场景。mysql
我把它叫作简单批处理。要求很简单,执行批量插入列表,而不是为每一个INSERT语句每次提交数据库,咱们将使用JDBC批处理操做和优化性能。sql
String [] queries = {数据库
"insert into employee (name, city, phone) values ('A', 'X', '123')",apache
"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();ui
for (String query : queries) {
statemenet.execute(query);
}
statemenet.close();
connection.close();
这是糟糕的代码。它单独执行每一个查询,每一个INSERT语句的都提交一次数据库。考虑一下,若是你要插入1000条记录呢?这是否是一个好主意。
下面是执行批量插入的基本代码。来看看:
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注入安全批处理。
思考一下下面代码:
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)
这是由于你试图在一个批次添加全部语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案
这是一个简单的解决方案。考虑批量大小为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()提交。
但愿对你有帮助。