1. 概述
在使用Java和JDBC操作数据库时,我们经常需要将多个SQL语句作为单个操作执行。这能帮助我们提升应用性能、保证操作的原子性,或更有效地管理复杂工作流。
本教程将探讨在JDBC中执行多条SQL语句的多种方式。我们将通过使用Statement
对象、批处理和存储过程等示例,展示如何高效执行多个SQL查询。本教程使用MySQL作为数据库。
2. JDBC与数据库环境搭建
在深入代码前,我们先确保项目配置正确且数据库已就绪。
2.1. Maven依赖
首先在pom.xml
中添加MySQL JDBC驱动依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
2.2. 数据库配置
创建名为user_db
的MySQL数据库和users
表,后续将演示对表执行多条插入语句:
(此处应有数据库表结构示意图,展示users表的id、name、email字段)
完成数据库配置后,即可使用JDBC执行多条SQL语句。
3. 在Java中批量执行SQL语句
执行多语句前,必须确保数据库连接配置允许批量操作。对于MySQL,连接URL需添加allowMultiQueries=true
属性。首先设置连接:
public Connection getConnection() throws SQLException {
String url = "jdbc:mysql://localhost:3306/user_db?allowMultiQueries=true";
String username = "admin";
String password = "securepass";
return DriverManager.getConnection(url, username, password);
}
此配置确保MySQL接受用分号分隔的多条SQL语句。默认情况下,MySQL不允许多语句执行,除非连接字符串包含allowMultiQueries=true
。
在JDBC中执行多语句主要有三种方法:
3.1. 使用Statement对象
Statement
对象允许我们将多条SQL查询合并为用分号分隔的单个字符串执行。以下是向users
表插入多条记录的示例:
public boolean executeMultipleStatements() throws SQLException {
String sql = "INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');" +
"INSERT INTO users (name, email) VALUES ('Bob', '[email protected]');";
try (Statement statement = connection.createStatement()) {
statement.execute(sql);
return true;
}
}
验证功能的测试用例:
@Test
public void givenMultipleStatements_whenExecuting_thenRecordsAreInserted() throws SQLException {
boolean result = executeMultipleStatements(connection);
assertTrue(result, "语句应成功执行");
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT COUNT(*) AS count FROM users WHERE name IN ('Alice', 'Bob')");) {
resultSet.next();
int count = resultSet.getInt("count");
assertEquals(2, count, "应插入两条记录");
}
}
⚠️ 注意:在单次execute()
调用中执行多SQL语句的行为因数据库而异:
- ✅ MySQL:需添加
allowMultiQueries=true
- ✅ PostgreSQL/SQL Server:默认支持
- ❌ Oracle/H2:不支持,需逐条执行或使用批处理
3.2. 使用批处理
当多条语句不需要作为原子单元执行时,批处理是更高效的方案:
public int[] executeBatchProcessing() throws SQLException {
try (Statement statement = connection.createStatement()) {
connection.setAutoCommit(false);
statement.addBatch("INSERT INTO users (name, email) VALUES ('Charlie', '[email protected]')");
statement.addBatch("INSERT INTO users (name, email) VALUES ('Diana', '[email protected]')");
int[] updateCounts = statement.executeBatch();
connection.commit();
return updateCounts;
}
}
验证功能的测试用例:
@Test
public void givenBatchProcessing_whenExecuting_thenRecordsAreInserted() throws SQLException {
int[] updateCounts = executeBatchProcessing(connection);
assertEquals(2, updateCounts.length, "批处理应执行两条语句");
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT COUNT(*) AS count FROM users WHERE name IN ('Charlie', 'Diana')");) {
resultSet.next();
int count = resultSet.getInt("count");
assertEquals(2, count, "应通过批处理插入两条记录");
}
}
3.3. 处理存储过程
存储过程预编译SQL代码并存储在数据库中,允许单次调用执行多条语句。首先创建存储过程:
DELIMITER //
CREATE PROCEDURE InsertMultipleUsers()
BEGIN
INSERT INTO users (name, email) VALUES ('Eve', '[email protected]');
INSERT INTO users (name, email) VALUES ('Frank', '[email protected]');
END //
DELIMITER ;
调用存储过程的Java代码:
public boolean callStoredProcedure() throws SQLException {
try (CallableStatement callableStatement = connection.prepareCall("{CALL InsertMultipleUsers()}")) {
callableStatement.execute();
return true;
}
}
验证功能的测试用例:
@Test
public void givenStoredProcedure_whenCalling_thenRecordsAreInserted() throws SQLException {
boolean result = callStoredProcedure(connection);
assertTrue(result, "存储过程应成功执行");
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT COUNT(*) AS count FROM users WHERE name IN ('Eve', 'Frank')");) {
resultSet.next();
int count = resultSet.getInt("count");
assertEquals(2, count, "存储过程应插入两条记录");
}
}
3.4. 执行多条SELECT语句
前面展示了多条INSERT语句,现在演示如何执行多条SELECT语句。使用statement.getMoreResults()
方法遍历多个结果集:
public List<User> executeMultipleSelectStatements() throws SQLException {
String sql = "SELECT * FROM users WHERE email = '[email protected]';" +
"SELECT * FROM users WHERE email = '[email protected]';";
List<User> users = new ArrayList<>();
try (Statement statement = connection.createStatement()) {
statement.execute(sql); // 执行多条查询
do {
try (ResultSet resultSet = statement.getResultSet()) {
while (resultSet != null && resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
users.add(new User(id, name, email));
}
}
} while (statement.getMoreResults());
}
return users;
}
statement.getMoreResults()
方法将游标移动到下一个结果,返回true
表示下一个结果是ResultSet
,false
表示更新计数或无更多结果。
验证功能的测试用例:
@Test
public void givenMultipleSelectStatements_whenExecuting_thenCorrectUsersAreFetched()
throws SQLException {
MultipleSQLExecution execution = new MultipleSQLExecution(connection);
execution.executeMultipleStatements();
List<User> users = execution.executeMultipleSelectStatements();
// 验证获取了两个用户且名称匹配
assertThat(users)
.hasSize(2)
.extracting(User::getName)
.containsExactlyInAnyOrder("Alice", "Bob");
}
4. 总结
在单次JDBC调用中执行多条SQL语句能提升性能和代码可读性。我们探讨了三种实现方式:使用Statement
对象、批处理和存储过程。每种方法适用场景不同:
Statement
:简单粗暴的多语句执行- 批处理:高性能批量操作
- 存储过程:复杂业务逻辑封装
理解这些技术后,我们可以根据性能或可维护性需求,更合理地设计数据库操作结构,优化应用效率。