JDBC 批处理


批处理,是指一次执行多个SQL。

Statement 批处理

示例:

package demo;

import java.sql.*;
import java.util.Arrays;

/**
 * 使用 Statement executeBatch 进行批处理
 */
public class StatementExecuteBatch {

    private static final String USER = "root";
    private static final String PASSWORD = "123456";

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/bank";

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName(JDBC_DRIVER);
        Connection conn =  DriverManager.getConnection(DB_URL, USER, PASSWORD);
        Statement stmt = null;
        try {
            stmt = conn.createStatement();
            stmt.addBatch("INSERT INTO user_balance(name, balance) VALUES('letian', 1000)");
            stmt.addBatch("INSERT INTO user_balance(name, balance) VALUES('xiaosi', 1001)");
            int[] affectRowsArray = stmt.executeBatch();
            System.out.println("影响的行数:" + Arrays.toString(affectRowsArray));
        } finally {
            if (stmt != null) {
                stmt.close();
            }
            conn.close();
        }
    }
}

执行结果:

影响的行数:[1, 1]

addBatch 添加一个SQL。executeBatch 执行批处理。executeBatch 返回一个int数组,对应每个SQL执行影响的行数。

PreparedStatement 批处理

示例:

package demo;

import java.sql.*;
import java.util.Arrays;

/**
 * 使用 PreparedStatement executeBatch 进行批处理
 */
public class PreparedStatementExecuteBatch {

    private static final String USER = "root";
    private static final String PASSWORD = "123456";

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/bank";

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName(JDBC_DRIVER);
        Connection conn =  DriverManager.getConnection(DB_URL, USER, PASSWORD);
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement("INSERT INTO user_balance(name, balance) VALUES(?, ?)");
            pstmt.setString(1, "letian");
            pstmt.setLong(2, 1000L);
            pstmt.addBatch();
            pstmt.setString(1, "xiaosi");
            pstmt.setLong(2, 1001L);
            pstmt.addBatch();
            int[] affectRowsArray = pstmt.executeBatch();
            System.out.println("影响的行数:" + Arrays.toString(affectRowsArray));
        } finally {
            if (pstmt != null) {
                pstmt.close();
            }
            conn.close();
        }
    }
}

addBatch 添加一个SQL。executeBatch 执行批处理。executeBatch 返回一个int数组,对应每个SQL执行影响的行数。

关于 executeBatch 的返回值

executeBatch 返回的是 int[] 数组,和批处理中的执行的SQL一一对应,值代表影响的行数。

executeBatch 的源码注释如此阐述:

  1. 若值为0或者大于0,代表影响的行数。
  2. 若为 SUCCESS_NO_INFO(-2),代表执行成功,但无法获取影响的行数。
  3. 若其中一个SQL执行失败,会抛出 BatchUpdateException 异常。遇到一个SQL执行失败,那么剩下的SQL要不要继续执行?这个看JDBC的实现。如果剩下的SQL继续执行,那么影响的行数数组放在 BatchUpdateException.getUpdateCounts 中。EXECUTE_FAILED(-3) 代表执行失败。

我们看下 JDBC MySQL 实现中批处理出现异常,会如何表现:

package demo;

import java.sql.*;
import java.util.Arrays;

/**
 * 使用 Statement executeBatch 进行批处理
 */
public class StatementExecuteBatchFail {

    private static final String USER = "root";
    private static final String PASSWORD = "123456";

    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/bank";

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName(JDBC_DRIVER);
        Connection conn =  DriverManager.getConnection(DB_URL, USER, PASSWORD);
        Statement stmt = null;
        try {
            stmt = conn.createStatement();
            stmt.addBatch("INSERT INTO user_balance(name, balance) VALUES('letian', 1000)");
            stmt.addBatch("INSERT INTO user_balance(name, balance) VALUES"); // 这是个错误的SQL
            stmt.addBatch("INSERT INTO user_balance(name, balance) VALUES('xiaosi', 1001)");

            int[] affectRowsArray = stmt.executeBatch();
            System.out.println("影响的行数:" + Arrays.toString(affectRowsArray));
        } catch (BatchUpdateException ex) {
            System.out.println("批处理出现异常,影响的行数:" + Arrays.toString(ex.getLargeUpdateCounts()));
        }finally {
            if (stmt != null) {
                stmt.close();
            }
            conn.close();
        }
    }
}

运行结果如下:

批处理出现异常,影响的行数:[1, -3, 1]

结论: JDBC MySQL 实现中批处理中,若有部分SQL出错,会继续执行剩下的SQL,最终抛出 BatchUpdateException 异常。



(本文完)


JDBC 教程