摘要
在 MyBatis 中,Executor
是执行 SQL 语句的核心组件。SimpleExecutor
和 BatchExecutor
是 Executor
的两种重要实现方式:前者负责简单的 SQL 执行,后者支持批量 SQL 执行。本文将通过自定义实现 BatchExecutor
和 SimpleExecutor
,深入分析它们的工作机制,并理解它们在实际开发中的应用场景。
前言
Executor
是 MyBatis 中负责执行 SQL 语句的核心接口,它的不同实现类为不同场景提供了灵活的解决方案。SimpleExecutor
是最常用的执行器,适合简单的 SQL 操作,而 BatchExecutor
通过批量处理 SQL 语句来提高性能,适用于大批量的数据处理场景。本文将通过自定义实现这两个执行器,并对 MyBatis 源码进行详细解析,帮助读者理解它们的工作机制。
自定义实现:SimpleExecutor 与 BatchExecutor
目标与功能
我们将实现两个 Executor
类:
- SimpleExecutor:执行简单的增删改查操作,不做任何缓存管理。
- BatchExecutor:支持批量执行 SQL 操作,通过
addBatch
和executeBatch
方法处理多条 SQL 语句。
核心流程
- SimpleExecutor:每次执行 SQL 都会打开新的数据库连接,适合单条 SQL 语句的执行场景。
- BatchExecutor:通过批处理机制,在同一连接上执行多条 SQL 语句,提高大批量操作的执行效率。
实现过程
1. SimpleExecutor 实现
SimpleExecutor
类的功能是最基础的 SQL 执行,每次执行时都会创建新的数据库连接。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* SimpleExecutor 是 Executor 接口的简单实现。
* 它负责执行单条 SQL 操作,不支持批处理或缓存管理。
*/
public class SimpleExecutor implements Executor {
private final Connection connection;
public SimpleExecutor(Connection connection) {
this.connection = connection;
}
@Override
public <T> T query(String statement, Object parameter) {
try (PreparedStatement pstmt = connection.prepareStatement(statement)) {
pstmt.setObject(1, parameter);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
// 直接返回查询结果,简化处理
return (T) rs.getObject(1);
}
}
} catch (SQLException e) {
throw new RuntimeException("Error executing query", e);
}
return null;
}
@Override
public int update(String statement, Object parameter) {
try (PreparedStatement pstmt = connection.prepareStatement(statement)) {
pstmt.setObject(1, parameter);
return pstmt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException("Error executing update", e);
}
}
@Override
public void commit() {
try {
connection.commit();
} catch (SQLException e) {
throw new RuntimeException("Failed to commit transaction", e);
}
}
@Override
public void rollback() {
try {
connection.rollback();
} catch (SQLException e) {
throw new RuntimeException("Failed to rollback transaction", e);
}
}
@Override
public void close() {
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException("Failed to close connection", e);
}
}
}
query
:执行 SQL 查询操作,并返回结果集的第一列数据。update
:执行 SQL 更新操作,包括插入、更新和删除。commit
和rollback
:处理事务提交和回滚。close
:关闭数据库连接,释放资源。
2. BatchExecutor 实现
BatchExecutor
通过批量执行 SQL 语句提高执行效率,适合大批量数据操作的场景。
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* BatchExecutor 实现了 Executor 接口的批处理功能。
* 它将多条 SQL 语句批量执行,避免重复的数据库连接开销。
*/
public class BatchExecutor implements Executor {
private final Connection connection;
private final List<PreparedStatement> batchStatements = new ArrayList<>();
public BatchExecutor(Connection connection) {
this.connection = connection;
}
@Override
public <T> T query(String statement, Object parameter) {
throw new UnsupportedOperationException("BatchExecutor does not support query operation.");
}
@Override
public int update(String statement, Object parameter) {
try {
PreparedStatement pstmt = connection.prepareStatement(statement);
pstmt.setObject(1, parameter);
pstmt.addBatch();
batchStatements.add(pstmt); // 缓存每个 PreparedStatement
return 0;
} catch (SQLException e) {
throw new RuntimeException("Error adding statement to batch", e);
}
}
public int[] executeBatch() {
try {
int[] result = new int[batchStatements.size()];
for (PreparedStatement pstmt : batchStatements) {
result = pstmt.executeBatch(); // 执行批量操作
}
return result;
} catch (SQLException e) {
throw new RuntimeException("Error executing batch", e);
}
}
@Override
public void commit() {
try {
executeBatch(); // 提交之前执行批量操作
connection.commit();
} catch (SQLException e) {
throw new RuntimeException("Failed to commit batch transaction", e);
}
}
@Override
public void rollback() {
try {
connection.rollback();
} catch (SQLException e) {
throw new RuntimeException("Failed to rollback transaction", e);
}
}
@Override
public void close() {
try {
for (PreparedStatement pstmt : batchStatements) {
pstmt.close();
}
connection.close();
} catch (SQLException e) {
throw new RuntimeException("Failed to close connection", e);
}
}
}
update
:将 SQL 操作添加到批处理队列中,不会立即执行。executeBatch
:执行所有缓存的 SQL 操作。commit
和rollback
:批量提交或回滚所有操作。close
:关闭所有PreparedStatement
和数据库连接,释放资源。
3. 测试 SimpleExecutor 和 BatchExecutor
我们编写测试类来验证 SimpleExecutor
和 BatchExecutor
的功能。
import java.sql.Connection;
import java.sql.DriverManager;
public class ExecutorTest {
public static void main(String[] args) {
try {
// 模拟数据库连接
Connection connection = DriverManager.getConnection("jdbc:h2:mem:testdb", "sa", "");
// 测试 SimpleExecutor
SimpleExecutor simpleExecutor = new SimpleExecutor(connection);
simpleExecutor.update("INSERT INTO users (name, age) VALUES ('Alice', 25)", null);
Object result = simpleExecutor.query("SELECT age FROM users WHERE name = 'Alice'", null);
System.out.println("SimpleExecutor Query result: " + result);
simpleExecutor.commit();
// 测试 BatchExecutor
BatchExecutor batchExecutor = new BatchExecutor(connection);
batchExecutor.update("INSERT INTO users (name, age) VALUES ('Bob', 30)", null);
batchExecutor.update("INSERT INTO users (name, age) VALUES ('Charlie', 35)", null);
batchExecutor.executeBatch(); // 执行批处理
batchExecutor.commit();
// 关闭资源
simpleExecutor.close();
batchExecutor.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
自定义实现类图
代码解析流程图
源码解析:MyBatis 中的 SimpleExecutor 与 BatchExecutor
1. SimpleExecutor 的设计与实现
在 MyBatis 中,SimpleExecutor
是最基础的 Executor
实现类。每次执行 SQL 语句时,它会新建一个数据库连接,并且不涉及任何批量处理或缓存管理。SimpleExecutor
适合简单的 SQL 操作,例如单条数据的增删改查操作。
public class SimpleExecutor extends BaseExecutor {
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
// 其他方法...
}
doUpdate
:负责执行INSERT
、UPDATE
、DELETE
操作。doQuery
:执行SELECT
操作,并返回查询结果。
SimpleExecutor
是 BaseExecutor
的子类,BaseExecutor
提供了事务管理和资源关闭的基础功能。
2. BatchExecutor 的设计与实现
BatchExecutor
是 MyBatis 中用于批量处理的 Executor
实现。它的核心思想是通过 addBatch
和 executeBatch
来减少数据库的往返次数,从而提升大批量数据操作的执行效率。
public class BatchExecutor extends BaseExecutor {
private final List<Statement> statementList = new ArrayList<>();
private final List<BatchResult> batchResultList = new ArrayList<>();
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt;
BatchResult batchResult = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
stmt = prepareStatement(handler, ms.getStatementLog());
handler.parameterize(stmt); // 处理参数
// 获取缓存的 statement
batchResult = findBatchResult(ms, parameter, handler);
if (batchResult == null) {
stmt.addBatch();
batchResult = new BatchResult(ms, parameter);
batchResultList.add(batchResult);
statementList.add(stmt);
}
batchResult.addBatch(stmt);
return -1; // MyBatis 默认返回-1
} catch (SQLException e) {
throw new SQLException("Error executing batch update", e);
}
}
public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
List<BatchResult> results = new ArrayList<>();
try {
for (Statement stmt : statementList) {
stmt.executeBatch(); // 执行所有的批处理操作
}
return results;
} finally {
statementList.clear(); // 清空批量处理列表
}
}
// 其他方法...
}
doUpdate
:负责批量执行INSERT
、UPDATE
和DELETE
操作。doFlushStatements
:执行批量操作并返回执行结果,通常用于提交事务前。
3. 提交与回滚的事务管理
在 MyBatis 中,BatchExecutor
和 SimpleExecutor
的事务管理是通过 BaseExecutor
统一实现的。在 commit
和 rollback
时,BatchExecutor
会首先执行所有的批处理操作,然后再提交或回滚事务。
总结与互动
通过本文,我们详细探讨了 MyBatis 中 SimpleExecutor
和 BatchExecutor
的设计与实现,并通过自定义实现加深了对这两类执行器的理解。SimpleExecutor
适用于简单的 SQL 操作,而 BatchExecutor
通过批量处理提高了大规模数据操作的性能。掌握这些执行器的工作机制,有助于我们在实际项目中选择合适的执行策略,优化系统的性能。
如果您觉得这篇文章对您有帮助,请点赞、收藏并关注!此外,欢迎在评论区留言,与我们分享您的见解或提出疑问!