MyBatis SqlSession创建全链路解析:从工厂构建到执行器选择的深度剖析
「MyBatis SqlSession诞生记:SqlSessionFactoryBuilder构建流程+Executor选择策略+事务管理初始化全揭秘」
SqlSessionFactoryBuilder:MyBatis框架的启动引擎
在MyBatis的整体架构中,
SqlSessionFactoryBuilder
扮演着框架启动器的关键角色。它不仅仅是配置文件的解析器,更是整个MyBatis运行时环境的构建者。理解其工作机理,是掌握MyBatis框架运行机制的重要基础。
目录
[MyBatis SqlSession创建全链路解析:从工厂构建到执行器选择的深度剖析](#MyBatis SqlSession创建全链路解析:从工厂构建到执行器选择的深度剖析)
SqlSessionFactoryBuilder:MyBatis框架的启动引擎
DefaultSqlSessionFactory:SqlSession的制造工厂
openSessionFromDataSource:核心创建逻辑深度解析
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
免费获取源码。
更多内容敬请期待。如有需要可以联系作者免费送
更多源码定制,项目修改,项目二开可以联系作者
点击可以进行搜索(每人免费送一套代码):千套源码目录(点我)
2025元旦源码免费送(点我)
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
build()方法的完整执行链路
构建过程的层次化分析
SqlSessionFactoryBuilder.build()
方法采用了典型的建造者模式,将复杂的构建过程封装在简洁的API之后:
java
public class SqlSessionFactoryBuilder {
// 核心构建方法 - 承载多种重载版本的统一入口
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 阶段1:配置解析器初始化
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 阶段2:配置对象构建
Configuration config = parser.parse();
// 阶段3:SqlSessionFactory实例化
return build(config);
} catch (Exception e) {
// 异常处理与资源清理
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
closeInputStream(inputStream);
}
}
}
错误处理与上下文管理
MyBatis在构建过程中采用了精细的错误处理机制:
java
// ErrorContext采用ThreadLocal实现线程安全的错误上下文管理
public class ErrorContext {
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause;
public static ErrorContext instance() {
ErrorContext context = LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
}
}
这种设计确保了在多线程环境下,每个线程都能拥有独立的错误上下文,便于问题定位和诊断。
DefaultSqlSessionFactory:SqlSession的制造工厂
openSession方法族的多维度支持
DefaultSqlSessionFactory
通过方法重载提供了灵活的SqlSession创建选项,满足不同场景的需求:
java
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
// 基础版本 - 使用默认配置
@Override
public SqlSession openSession() {
return openSessionFromDataSource(
configuration.getDefaultExecutorType(),
null,
false
);
}
// 自动提交控制版本
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(
configuration.getDefaultExecutorType(),
null,
autoCommit
);
}
// 事务隔离级别指定版本
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return openSessionFromDataSource(
configuration.getDefaultExecutorType(),
level,
false
);
}
// 执行器类型指定版本
@Override
public SqlSession openSession(ExecutorType execType) {
return openSessionFromDataSource(execType, null, false);
}
// 连接参数指定版本
@Override
public SqlSession openSession(Connection conn) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), conn);
}
}
openSessionFromDataSource:核心创建逻辑深度解析
这是SqlSession创建过程中最核心的方法,包含了事务初始化、执行器选择等关键决策:
java
private SqlSession openSessionFromDataSource(ExecutorType execType,
TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
// 步骤1:环境配置获取
final Environment environment = configuration.getEnvironment();
if (environment == null) {
throw new ConfigurationException("Environment is required.");
}
// 步骤2:事务工厂实例化
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 步骤3:事务对象创建(关键时机点)
tx = transactionFactory.newTransaction(
environment.getDataSource(),
level,
autoCommit
);
// 步骤4:执行器创建与装饰
final Executor executor = configuration.newExecutor(tx, execType);
// 步骤5:SqlSession实例化
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// 异常处理:关闭已创建的事务
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
}
}
事务管理器的初始化时机与策略
事务工厂的选择机制
事务管理器的初始化发生在SqlSession创建流程的早期阶段,这体现了MyBatis对数据一致性的重视:
java
private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
// 环境未配置时的默认策略
if (environment == null || environment.getTransactionFactory() == null) {
if (log.isDebugEnabled()) {
log.debug("Using default transaction factory: ManagedTransactionFactory");
}
return new ManagedTransactionFactory();
}
// 返回配置的事务工厂
if (log.isDebugEnabled()) {
log.debug("Using configured transaction factory: " +
environment.getTransactionFactory().getClass().getSimpleName());
}
return environment.getTransactionFactory();
}
事务实例的创建过程分析
不同的事务工厂创建不同类型的事务管理器:
java
// JDBC事务工厂实现
public class JdbcTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(DataSource ds,
TransactionIsolationLevel level,
boolean autoCommit) {
if (log.isDebugEnabled()) {
log.debug("Creating new JDBC transaction with autoCommit: " + autoCommit);
}
return new JdbcTransaction(ds, level, autoCommit);
}
}
// 托管事务工厂实现
public class ManagedTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(DataSource ds,
TransactionIsolationLevel level,
boolean autoCommit) {
if (log.isDebugEnabled()) {
log.debug("Creating new Managed transaction");
}
return new ManagedTransaction(ds, level, autoCommit);
}
}
连接获取与事务属性设置
事务管理器在初始化时会立即获取数据库连接并设置事务属性:
java
public class JdbcTransaction implements Transaction {
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
// 获取数据库连接
connection = dataSource.getConnection();
// 设置事务隔离级别(如果指定)
if (level != null) {
int currentLevel = connection.getTransactionIsolation();
if (currentLevel != level.getLevel()) {
if (log.isDebugEnabled()) {
log.debug("Changing transaction isolation level from " +
currentLevel + " to " + level.getLevel());
}
connection.setTransactionIsolation(level.getLevel());
}
}
// 设置自动提交模式
setDesiredAutoCommit(autoCommit);
}
private void setDesiredAutoCommit(boolean desiredAutoCommit) {
boolean currentAutoCommit = connection.getAutoCommit();
if (currentAutoCommit != desiredAutoCommit) {
if (log.isDebugEnabled()) {
log.debug("Changing autocommit from " + currentAutoCommit +
" to " + desiredAutoCommit);
}
connection.setAutoCommit(desiredAutoCommit);
}
}
}
Executor类型的选择策略与执行机制
Executor体系的架构设计
MyBatis设计了灵活的Executor体系,通过配置化的方式支持不同的执行策略:
java
public class Configuration {
// 执行器创建的核心方法
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// 执行器类型推断逻辑
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
// 基于类型的执行器实例化
if (log.isDebugEnabled()) {
log.debug("Creating executor of type: " + executorType);
}
switch (executorType) {
case BATCH:
executor = new BatchExecutor(this, transaction);
break;
case REUSE:
executor = new ReuseExecutor(this, transaction);
break;
default:
executor = new SimpleExecutor(this, transaction);
}
// 二级缓存装饰(如果启用)
if (cacheEnabled) {
if (log.isDebugEnabled()) {
log.debug("Enabling cache for executor");
}
executor = new CachingExecutor(executor);
}
// 插件机制增强
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
}
各种Executor的性能特性对比
SimpleExecutor:标准执行器
java
public class SimpleExecutor extends BaseExecutor {
@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(
this, ms, parameter, rowBounds, resultHandler, boundSql);
// 每次执行都创建新的PreparedStatement
stmt = prepareStatement(handler);
return handler.query(stmt, resultHandler);
} finally {
// 执行完成后立即关闭Statement
closeStatement(stmt);
}
}
}
适用场景:通用查询场景,内存敏感环境
ReuseExecutor:语句重用执行器
java
public class ReuseExecutor extends BaseExecutor {
// 重用相同SQL的PreparedStatement
private final Map<String, PreparedStatement> statementMap = new HashMap<>();
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter,
RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(
this, ms, parameter, rowBounds, resultHandler, boundSql);
String sql = boundSql.getSql();
PreparedStatement stmt;
// 检查是否已存在相同SQL的PreparedStatement
if (hasStatementFor(sql)) {
if (log.isDebugEnabled()) {
log.debug("Reusing prepared statement for SQL: " + sql);
}
stmt = getStatement(sql);
} else {
// 创建新的PreparedStatement并缓存
stmt = prepareNewStatement(handler, sql);
}
handler.parameterize(stmt);
return handler.query(stmt, resultHandler);
}
}
适用场景:相同SQL频繁执行的OLTP系统
BatchExecutor:批量处理执行器
java
public class BatchExecutor extends BaseExecutor {
private final List<Statement> statementList = new ArrayList<>();
private final List<BatchResult> batchResultList = new ArrayList<>();
private String currentSql;
private MappedStatement currentStatement;
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
// 批量操作逻辑
if (isSameBatch(ms, parameter)) {
// 添加到当前批次
addToCurrentBatch(ms, parameter);
return BATCH_UPDATE_RETURN_VALUE;
} else {
// 执行当前批次并开始新批次
executeBatch();
startNewBatch(ms, parameter);
return BATCH_UPDATE_RETURN_VALUE;
}
}
@Override
public void commit(boolean required) throws SQLException {
// 提交时执行所有批量操作
executeBatch();
super.commit(required);
}
}
适用场景:大数据量批量插入、更新操作
CachingExecutor:缓存装饰器模式应用
通过装饰器模式为执行器添加二级缓存功能,体现了开闭原则的优雅应用:
java
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject,
RowBounds rowBounds, ResultHandler resultHandler,
CacheKey key, BoundSql boundSql) throws SQLException {
// 检查是否启用缓存
Cache cache = ms.getCache();
if (cache == null) {
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
// 缓存刷新检查
flushCacheIfRequired(ms);
// 缓存查询逻辑
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 缓存未命中,委托给底层执行器查询
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 将结果放入缓存
tcm.putObject(cache, key, list);
} else {
if (log.isDebugEnabled()) {
log.debug("Cache hit for key: " + key);
}
}
return list;
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
插件机制在SqlSession创建中的增强作用
拦截器链的构建与执行
MyBatis通过责任链模式实现插件机制,在SqlSession创建过程中对Executor进行增强:
java
public class InterceptorChain {
private final List<Interceptor> interceptors = new ArrayList<>();
public Object pluginAll(Object target) {
// 按顺序应用所有拦截器
for (Interceptor interceptor : interceptors) {
if (log.isDebugEnabled()) {
log.debug("Applying interceptor: " + interceptor.getClass().getSimpleName());
}
target = interceptor.plugin(target);
}
return target;
}
}
典型插件的执行时机分析
以分页插件为例,观察其在SqlSession创建过程中的介入时机:
java
@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class PageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 在Executor.query方法执行前后进行拦截
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
RowBounds rowBounds = (RowBounds) args[2];
// 分页逻辑处理
if (shouldPage(rowBounds)) {
return handlePagedQuery(invocation, ms, parameter, rowBounds);
}
// 继续执行原始逻辑
return invocation.proceed();
}
}
性能优化与实践建议
Executor选择的性能影响
根据实际业务场景选择合适的Executor类型:
-
SIMPLE执行器:
-
优点:内存占用小,无状态
-
缺点:频繁创建/销毁PreparedStatement
-
适用:查询多样性高的场景
-
-
REUSE执行器:
-
优点:减少PreparedStatement创建开销
-
缺点:内存占用较高,需要维护Statement缓存
-
适用:SQL模板化程度高的OLTP系统
-
-
BATCH执行器:
-
优点:批量操作性能极佳
-
缺点:编程模型复杂,内存占用大
-
适用:数据导入、批量更新场景
-
事务配置的最佳实践
XML
<!-- 生产环境推荐配置 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="false"/>
</transactionManager>
<!-- 开发环境便捷配置 -->
<transactionManager type="JDBC">
<property name="autoCommit" value="true"/>
</transactionManager>
连接池参数调优
XML
<dataSource type="POOLED">
<!-- 根据并发量调整连接数 -->
<property name="poolMaximumActiveConnections" value="50"/>
<property name="poolMaximumIdleConnections" value="10"/>
<property name="poolMaximumCheckoutTime" value="20000"/>
<!-- 根据网络状况调整超时时间 -->
<property name="poolTimeToWait" value="20000"/>
<!-- 连接有效性检查 -->
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="SELECT 1"/>
<property name="poolPingConnectionsNotUsedFor" value="3600000"/>
</dataSource>
总结与展望
SqlSession的创建过程是MyBatis框架初始化的核心环节,它完美体现了框架在设计上的诸多考量:
-
灵活性设计:通过多种openSession重载方法支持不同使用场景
-
性能优化:提供多种Executor实现满足不同性能需求
-
扩展性支持:通过插件机制允许功能增强
-
资源管理:完善的事务和连接生命周期管理
深入理解这一过程,不仅有助于我们更好地使用MyBatis,更能从中学习到优秀框架的设计思想和实现技巧,为我们的技术成长提供宝贵的参考。

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。文末有免费源码
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕网址:扣棣编程** ,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!**💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!
往期文章推荐:
基于Springboot + vue实现的学生宿舍信息管理系统
免费获取宠物商城源码--SpringBoot+Vue宠物商城网站系统
【2025小年源码免费送】