批处理,是指一次执行多个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 的源码注释如此阐述:
- 若值为0或者大于0,代表影响的行数。
- 若为
SUCCESS_NO_INFO
(-2),代表执行成功,但无法获取影响的行数。 - 若其中一个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 异常。