jdbc批處理原理分析
需要向資料庫傳送多條sql語句時, 為了提升執行效率, 可以考慮採用JDBC的批處理機制.
JDBC的批處理機制主要涉及Statement或PreparedStatement物件的以下方法:
|--addBatch(String sql) :Statement類的方法, 多次呼叫該方法可以將多條sql語句新增到Statement物件的命令列表中.
執行批處理時將一次性的把這些sql語句發送給資料庫進行處理.
|--addBatch(): PreparedStatement類的方法, 多次呼叫該方法可以將多條預編譯的sql語句新增到PreparedStatement物件的命令列表中.
執行批處理時將一次性的把這些sql語句
|--executeBatch():把Statement物件或PreparedStatement物件命令列表中的所有sql語句傳送給資料庫進行處理.
|--clearBatch(): 清空當前sql命令列表.
/* * create table batch_test(id int primary key auto_increment, name varchar(40), age int); */ public class BatchTest { @Test public void statementBatch() { Connection conn = null; Statement st = null; String sql_1 = "insert into batch_test(name, age) values('coolxing', 24)"; String sql_2 = "insert into batch_test(name, age) values('coolmin', 22)"; String sql_3 = "insert into batch_test(name, age) values('yong', 21)"; String sql_4 = "update batch_test set name='java' where id=1"; try { conn = JdbcUtils.getConnection(); st = conn.createStatement(); st.addBatch(sql_1); st.addBatch(sql_2); st.addBatch(sql_3); st.addBatch(sql_4); st.executeBatch(); st.clearBatch(); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(null, st, conn); } } @Test public void preparedStatementBatch() { Connection conn = null; PreparedStatement st = null; String sql = "insert into batch_test(name, age) values(?, ?)"; try { conn = JdbcUtils.getConnection();
//通過只打開一個連線 st = conn.prepareStatement(sql); for (int i = 0; i < 10002; i++) { st.setString(1, "coolxing_" + i); st.setInt(2, i); st.addBatch(); // 需要防止Preparedstatement物件中的命令列表包含過多的待處理sql語句, 而造成outOfMemory錯誤 if (i % 500 == 0) { st.executeBatch(); st.clearBatch(); } } // 將剩下的未處理命令傳送給資料庫 st.executeBatch(); } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(null, st, conn); } } }
總結: 採用Statement.addBatch(sql)方式實現批處理可以向資料庫傳送不同型別的sql語句, 但是這些sql語句沒有進行預編譯, 執行效率不高. 且需要列出每一個sql語句. 而PreparedStatement.addBatch()只能應用在型別相同引數不同的sql語句中, 此種形式的批處理經常用於在同一個表中批量插入資料, 或批量更新表的資料.
注意不要一次性向命令列表中新增數量過多的sql語句, 防止出現outOfMemory錯誤.
原理分析:
前期的程式碼在與資料庫進行通訊時,都是先建立連線,建立連線花費的成本是最高的,然後發一個SQL語句,執行完後就關閉了連線。還有一個問題是傳送的SQL語句都是通過網路傳送的,比起本地呼叫來說,網路傳輸的成本也是高很多的。如果要插入或者更新一批資料進資料庫,還是採用前期的方法,花費的時間會很多,給使用者的感受會很慢。但是如果採用批處理,則在兩個方便都會節約大部分成本,速度會更快。下面是批處理的示例程式碼:
static void createBatch() throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "insert into user(name,birthday, money) values (?, ?, ?) ";
ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
for (int i = 0; i < 100; i++) {
ps.setString(1, "batch name" + i);
ps.setDate(2, new Date(System.currentTimeMillis()));
ps.setFloat(3, 100f + i);
ps.addBatch();
}
int[] is = ps.executeBatch();
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
如果不用批處理語句打包,則需要呼叫以前的create方法一百次,完成一百次資料庫的連線和網路通訊。用批處理的方式,可以將100次插入打成一個包,然後一次性發給資料庫,資料庫執行完畢,返回結果。如果在兩種方法呼叫上加上時間,就能夠區分兩者的速度差距了。但是並不是說用了批處理就一定比不用批處理要快,這根資料的版本、驅動的版本等都有很大關係。所以實際要用的時候,應該在環境上先測試一下兩者的效果。