關於jdbc批處理的一些小問題
阿新 • • 發佈:2018-11-20
一個專案實現過程中難免遇到一些批量執行sql語句的情況,例如執行1萬條插入語句,如果使用傳統的插入方式則需要建立1萬次連線,一次傳送一條sql語句,這樣是及其浪費效能的,接下來通過三種不同的方式模擬批量的插入語句,程式碼如下:
package com.lsm1998.shop.test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.Statement; public class JDBCTest { static { try { //com.mysql.jdbc.Driver與com.mysql.cj.jdbc.Driver有啥不同? //com.mysql.jdbc.Driver 是 mysql-connector-java 5中的, //com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6中的 Class.forName("com.mysql.cj.jdbc.Driver"); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&serverTimezone=UTC", "root", "123456"); //test1(connection); //test2(connection); test3(connection); } /** * 常規提交 * 耗時 31202ms * * @param connection * @throws Exception */ private static void test1(Connection connection) throws Exception { Statement statement = connection.createStatement(); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { String sql = "insert into v1(name) values('測試_" + i + "');"; statement.execute(sql); } long end = System.currentTimeMillis(); System.out.println("耗時=" + (end - start)); statement.close(); } /** * 採用事務提交 * 耗時 4182ms * * @param connection * @throws Exception */ private static void test2(Connection connection) throws Exception { connection.setAutoCommit(false); Statement statement = connection.createStatement(); long start = System.currentTimeMillis(); try { for (int i = 0; i < 10000; i++) { String sql = "insert into v1(name) values('測試_" + i + "');"; statement.execute(sql); } connection.commit(); statement.close(); } catch (Exception e) { connection.rollback(); } long end = System.currentTimeMillis(); System.out.println("耗時=" + (end - start)); } /** * 批處理提交 * 耗時 2634ms(預編譯) * * @param connection * @throws Exception */ private static void test3(Connection connection) throws Exception { connection.setAutoCommit(false); String sql = "insert into v1(name) values(?);"; PreparedStatement ps = connection.prepareStatement(sql); long start = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { ps.setString(1, "測試_" + i); ps.addBatch(); } ps.executeBatch(); connection.commit(); long end = System.currentTimeMillis(); System.out.println("耗時=" + (end - start)); } }
首先宣告一下筆者的配置:
- mysql5.5;
- jdk11;
- 驅動 mysql-connector-java-8.0.13.jar;
- CPU i5-6200U;
- 記憶體4G;
開始筆者犯了一個嚴重的錯誤,就算以為批處理會自動開啟事務,最後測試結果為27秒,對此差點懷疑是假的批處理,最後抱著試一試的態度加入事務相關程式碼,果然如此,僅耗時不到3秒,最後結果評測:常規方式31秒,批處理不到3秒,同一個事務內不進行批處理需要4秒,好在問題是解決了,得出重要結論:批處理也要宣告事務!