JDBC批處理

聲明轉載文章受權轉載自yuimenu的blog,地址:http://lavasoft.blog.51cto.com/62575/238651 英文原文地址:http://viralpatel.net/blogs/batch-insert-in-java-jdbc/java

 

 

 

讓咱們看看如何使用JDBC API在Java中執行批量插入。雖然你可能已經知道,但我會盡力解釋基礎到複雜的場景。mysql

 
在此筆記裏,咱們將看到咱們如何可使用像Statement和PreparedStatement JDBC API來批量在任何數據庫中插入數據。此外,咱們將努力探索一些場景,如在內存不足時正常運行,以及如何優化批量操做。
 
首先,使用Java JDBC基本的API批量插入數據到數據庫中。
 

Simple Batch - 簡單批處理

 我把它叫作簡單批處理。要求很簡單,執行批量插入列表,而不是爲每一個INSERT語句每次提交數據庫,咱們將使用JDBC批處理操做和優化性能。sql

 
想一想一下下面的代碼:

Bad Code

 

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條記錄呢?這是否是一個好主意。

 

下面是執行批量插入的基本代碼。來看看:

 

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()提交。

 但願對你有幫助。

相關文章
相關標籤/搜索