JDBC批量提交SQL的幾點問題解答

1. 疑問

  • 問題一:Statement的executeBatch方法是否會執行commit操做,是否還須要再執行一次commit()?
  • 問題二:執行批量操做的過程當中,若是其中有部分命令執行失敗,其餘執行成功的命令是否會提交到數據庫?

2. 環境

    測試採用MySQL數據庫,建立以下表;java

CREATE TABLE `batch_test` (
`id`  int(11) NOT NULL ,
PRIMARY KEY (`id`)
)

3. 測試

3.1. 問題一測試

    測試代碼:mysql

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (2)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (3)");

    stmt.executeBatch();
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    結果:sql

mysql> select * from batch_test;
Empty set

    修改代碼,增長commit()數據庫

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (2)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (3)");

    stmt.executeBatch();

    // ************
    conn.commit();

} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    結果:app

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set

對比上面兩個測試,說明在執行executeBatch()後必須再執行commit(), executeBatch不會執行commit操做;測試

3.2. 問題二測試

    接着3.1的測試數據,目前表batch_test中已經有三條記錄,id字段是主鍵,而且已經存在三個值(1,2,3),我再依次添加4條insert命令,id值順序爲(4,5,1,6),當執行executeBatch時第三條記錄(id=1)應該會失敗,且拋出異常。spa

    代碼以下:code

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (4)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (5)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (6)");

    stmt.executeBatch();
    System.out.println("executeBatch");

    conn.commit();
    System.out.println("commit");

} catch (BatchUpdateException e) {
    e.printStackTrace();
    System.out.println("UpdateCounts -> " + Arrays.toString(e.getUpdateCounts()));
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    執行executeBatch()時拋異常BatchUpdateException,輸出:get

java.sql.BatchUpdateException: Duplicate entry '1' for key 'PRIMARY'
    at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1110)
    at com.tiza.test.db.BatchExecTest.main(BatchExecTest.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
UpdateCounts -> [1, 1, -3, 1]it

結果:

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set

    根據結果可知,批量操做當出現一條SQL命令失敗,會拋異常,而且UpdateCounts顯示,除了id=1的記錄執行失敗,其餘三條都成功了。 可是這裏拋異常後就沒有執行commit,那若是執行commit是否是三條成功的(id=4,id=5,id=6)就會提交到數據庫?

    進一步測試,在拋BatchUpdateException後依然作commit,代碼以下:

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (4)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (5)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (6)");

    stmt.executeBatch();
    System.out.println("executeBatch");

    conn.commit();
    System.out.println("commit");

} catch (BatchUpdateException e) {
    e.printStackTrace();
    System.out.println("UpdateCounts -> " + Arrays.toString(e.getUpdateCounts()));

    // **********************
    try {
        conn.commit();
    } catch (SQLException e1) {
        e1.printStackTrace();
    }
    // **********************

} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    輸出:

java.sql.BatchUpdateException: Duplicate entry '1' for key 'PRIMARY'
    at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1110)
    at com.tiza.test.db.BatchExecTest.main(BatchExecTest.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
UpdateCounts -> [1, 1, -3, 1]

    結果:

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
|  6 |
+----+
6 rows in set

至此問題二答案已經出來了,批量提交過程當中雖然在執行executeBatch時當部分命令出現異常,可是隻要繼續執行commit,其中成功執行的命令仍是會commit到數據庫的。

4. 總結

問題一:Statement的executeBatch方法是否會執行commit操做,是否還須要再執行一次commit()?

答: executeBatch不會執行commit,在執行完executeBatch後必須再執行commit;

 

問題二:執行批量操做的過程當中,若是其中有部分命令執行失敗,其餘執行成功的命令是否會提交到數據庫?

答: 批量操做執行executeBatch時部分命令執行失敗會拋BatchUpdateException異常,可是隻要繼續執行commit,其餘成功執行的命令依然會提交到數據庫,不然不關執行成功與否都不會提交到數據庫。

相關文章
相關標籤/搜索