聲明轉載:文章受權轉載自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()提交。
但願對你有幫助。