【源码解读之 Mybatis】【基础篇】-- 第3篇:SqlSession的创建与生命周期

SqlSession的创建与生命周期

1. 学习目标确认

1.0 第2篇思考题解答

在深入学习SqlSession之前,让我们先回顾并解答第2篇中提出的思考题,这将帮助我们更好地理解SqlSession在整个架构中的作用。

思考题1:为什么MyBatis要设计如此复杂的配置系统?

答案要点:

统一管理:所有配置项集中管理https://www.naquan.com/,避免配置分散和重复

灵活性:支持XML、注解、代码三种配置方式,满足不同场景需求

可扩展性:通过插件系统和自定义配置支持功能扩展

性能优化:配置缓存、懒加载等机制提升性能

类型安全:强类型配置减少运行时错误

SqlSession的作用:SqlSession作为配置系统的使用者,通过Configuration获取所有必要的配置信息。

思考题2:配置系统的扩展性体现在哪些方面?

答案要点:

插件扩展:Interceptor接口支持功能扩展

类型处理器扩展:TypeHandler接口支持自定义类型转换

对象工厂扩展:ObjectFactory接口支持自定义对象创建

数据源扩展:DataSource接口支持自定义数据源

事务管理扩展:TransactionFactory接口支持自定义事务管理

SqlSession的扩展性:SqlSession通过Executor、StatementHandler等组件实现功能扩展。

思考题3:如何优化配置解析的性能?

答案要点:

缓存机制:解析后的配置对象缓存,避免重复解析

懒加载:非必需配置延迟加载,减少启动时间

批量处理:相关配置项批量解析,提高效率

内存优化:优化配置对象的内存使用,减少GC压力

SqlSession的性能:SqlSession通过Executor缓存、连接池等技术优化性能。

思考题4:基于配置系统的理解,应该从哪个组件开始深入源码分析?

推荐顺序:SqlSession → Executor → StatementHandler → ParameterHandler + ResultSetHandler

从SqlSession开始的原因:

SqlSession是配置系统的直接使用者

理解SqlSession有助于理解整个执行流程

为后续学习Executor等组件奠定基础

1.1 SqlSession概述(基于MyBatis 3.5.x)

SqlSession是MyBatis的核心接口,代表与数据库的一次会话。它是MyBatis架构中接口层的重要组成部分,为用户提供了简洁的API来执行数据库操作。

SqlSession的核心职责:

数据库操作:提供CRUD操作的统一接口

事务管理:管理数据库事务的提交和回滚

Mapper管理:获取Mapper接口的动态代理对象

会话管理:管理会话的生命周期和资源释放

重要提示:理解SqlSession的设计和实现是深入MyBatis源码的关键,后续的Executor、StatementHandler等组件都围绕SqlSession展开。

2. SqlSession接口设计分析

2.1 SqlSession接口结构

让我们深入分析SqlSession接口的设计:

package org.apache.ibatis.session;

import java.io.Closeable;

import java.sql.Connection;

import java.util.List;

import java.util.Map;

import org.apache.ibatis.cursor.Cursor;

import org.apache.ibatis.executor.BatchResult;

import org.apache.ibatis.executor.result.ResultHandler;

public interface SqlSession extends Closeable {

    // 查询操作

    <T> T selectOne(String statement);

    <T> T selectOne(String statement, Object parameter);

    <E> List<E> selectList(String statement);

    <E> List<E> selectList(String statement, Object parameter);

    <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);


    // Map查询操作

    <K, V> Map<K, V> selectMap(String statement, String mapKey);

    <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

    <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);


    // 游标查询

    <T> Cursor<T> selectCursor(String statement);

    <T> Cursor<T> selectCursor(String statement, Object parameter);

    <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);


    // 自定义结果处理(流式结果)

    void select(String statement, Object parameter, ResultHandler handler);

    void select(String statement, ResultHandler handler);

    void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);


    // 更新操作

    int insert(String statement);

    int insert(String statement, Object parameter);

    int update(String statement);

    int update(String statement, Object parameter);

    int delete(String statement);

    int delete(String statement, Object parameter);


    // 事务管理

    void commit();

    void commit(boolean force);

    void rollback();

    void rollback(boolean force);


    // 批量操作

    List<BatchResult> flushStatements();


    // Mapper获取

    <T> T getMapper(Class<T> type);


    // 连接管理

    Connection getConnection();


    // 配置获取

    Configuration getConfiguration();


    // 缓存管理

    void clearCache();

}

2.2 接口设计特点分析

2.2.1 泛型设计

// 泛型设计提供了类型安全

<T> T selectOne(String statement, Object parameter);

<E> List<E> selectList(String statement, Object parameter);

优势:

类型安全:编译时类型检查,避免运行时类型转换错误

代码简洁:无需手动类型转换

IDE支持:更好的代码提示和重构支持

2.2.2 ResultHandler自定义结果处理

// 支持自定义结果处理,适用于流式结果处理

void select(String statement, Object parameter, ResultHandler handler);

void select(String statement, ResultHandler handler);

void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

使用场景:

流式处理:处理大量数据时避免内存溢出

自定义转换:对结果进行自定义处理

实时处理:边查询边处理结果

示例用法:

// 流式处理大量数据

session.select("selectAllUsers", null, new ResultHandler<User>() {

    @Override

    public void handleResult(ResultContext<? extends User> resultContext) {

        User user = resultContext.getResultObject();

        // 实时处理每个用户数据

        processUser(user);

    }

});

2.2.3 方法重载设计

// 支持不同参数组合

<T> T selectOne(String statement);

<T> T selectOne(String statement, Object parameter);

<E> List<E> selectList(String statement, Object parameter);

<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

优势:

使用灵活:支持不同使用场景

向后兼容:保持API的向后兼容性

渐进式学习:从简单到复杂的使用方式

2.2.4 资源管理设计

public interface SqlSession extends Closeable {

    // 继承Closeable接口,支持try-with-resources语法

}

优势:

自动资源管理:支持try-with-resources语法

防止资源泄漏:确保资源正确释放

代码简洁:减少样板代码

3. SqlSessionFactory工厂模式分析

3.1 SqlSessionFactory接口设计

SqlSessionFactory是创建SqlSession的工厂接口,采用工厂模式设计:

package org.apache.ibatis.session;

import java.sql.Connection;

public interface SqlSessionFactory {

    // 基本创建方法

    SqlSession openSession();

    SqlSession openSession(boolean autoCommit);

    SqlSession openSession(Connection connection);


    // 执行器类型指定

    SqlSession openSession(ExecutorType execType);

    SqlSession openSession(ExecutorType execType, boolean autoCommit);

    SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);

    SqlSession openSession(ExecutorType execType, Connection connection);


    // 事务隔离级别指定

    SqlSession openSession(TransactionIsolationLevel level);


    // 配置获取

    Configuration getConfiguration();

}

3.2 DefaultSqlSessionFactory实现分析

DefaultSqlSessionFactory是SqlSessionFactory的默认实现,让我们深入分析其源码:

package org.apache.ibatis.session.defaults;

import org.apache.ibatis.executor.Executor;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.ExecutorType;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.TransactionIsolationLevel;

import org.apache.ibatis.transaction.Transaction;

import org.apache.ibatis.transaction.TransactionFactory;

import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.exceptions.ExceptionFactory;

import org.apache.ibatis.executor.ErrorContext;

public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private final Configuration configuration;


    public DefaultSqlSessionFactory(Configuration configuration) {

        this.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(ExecutorType execType) {

        return openSessionFromDataSource(execType, null, false);

    }


    // 核心创建方法

    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {

        Transaction tx = null;

        try {

            // 1. 获取环境配置

            final Environment environment = configuration.getEnvironment();


            // 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 createSqlSession(configuration, executor, autoCommit);

        } catch (Exception e) {

            closeTransaction(tx);

            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);

        } finally {

            ErrorContext.instance().reset();

        }

    }


    protected SqlSession createSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {

        return new DefaultSqlSession(configuration, executor, autoCommit);

    }

}

3.3 工厂模式的优势

3.3.1 封装复杂性

// 用户只需要调用简单的方法

SqlSession session = sqlSessionFactory.openSession();

// 内部复杂的创建过程被封装

// 1. 环境配置获取

// 2. 事务工厂创建

// 3. 事务对象创建

// 4. 执行器创建

// 5. SqlSession创建

3.3.2 参数灵活性

// 支持多种参数组合

SqlSession session1 = sqlSessionFactory.openSession(); // 默认配置

SqlSession session2 = sqlSessionFactory.openSession(true); // 自动提交

SqlSession session3 = sqlSessionFactory.openSession(ExecutorType.BATCH); // 批处理执行器

3.3.3 配置驱动

// 基于Configuration配置创建SqlSession

final Executor executor = configuration.newExecutor(tx, execType);

4. SqlSession生命周期管理

4.1 生命周期阶段

SqlSession的生命周期可以分为以下几个阶段:

openSession

commit/rollback

close

Environment

Transaction

Executor

select/update

getMapper

操作完成

结束事务

executor.close

tx.close

clearCache

🔄 创建阶段

⚡ 使用阶段

🔒 事务管理阶段

🧹 资源释放阶段

📋 获取配置

🏗️ 创建事务

⚙️ 创建执行器

🎯 创建SqlSession

💾 执行SQL

📊 结果处理

🔗 Mapper调用

🚀 事务开始

✅ 提交/回滚

🏁 事务结束

🔧 关闭执行器

🔐 关闭事务

🔌 关闭连接

🗑️ 清理缓存

4.2 创建阶段详细分析

4.2.1 配置获取

// 从Configuration获取环境配置

final Environment environment = configuration.getEnvironment();

Environment包含:

DataSource:数据源配置

TransactionFactory:事务工厂配置

Id:环境标识

4.2.2 事务创建

// 创建事务对象

final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

事务创建过程:

获取事务工厂:从环境配置获取TransactionFactory

创建事务对象:使用DataSource和参数创建Transaction

设置事务属性:隔离级别、自动提交等

4.2.3 执行器创建

// 创建执行器

final Executor executor = configuration.newExecutor(tx, execType);

执行器创建过程:

执行器类型选择:根据ExecutorType选择具体实现

缓存包装:如果启用缓存,用CachingExecutor包装

插件应用:应用所有配置的插件

4.2.4 SqlSession创建

// 创建SqlSession对象

return new DefaultSqlSession(configuration, executor, autoCommit);

4.3 使用阶段分析

4.3.1 SQL执行流程

// 用户调用

User user = session.selectOne("selectUser", 1);

// 内部执行流程

public <T> T selectOne(String statement, Object parameter) {

    List<T> list = this.selectList(statement, parameter);

    if (list.size() == 1) {

        return list.get(0);

    }

    if (list.size() > 1) {

        throw new TooManyResultsException("Expected one result...");

    } else {

        return null;

    }

}

4.3.2 Mapper获取流程

// 用户调用

UserMapper mapper = session.getMapper(UserMapper.class);

// 内部实现

@Override

public <T> T getMapper(Class<T> type) {

    return configuration.getMapper(type, this);

}

4.4 资源释放阶段

4.4.1 手动关闭

// 手动关闭SqlSession

session.close();

// 内部关闭流程

@Override

public void close() {

    try {

        executor.close(isCommitOrRollbackRequired(false));

    } catch (SQLException e) {

        throw ExceptionFactory.wrapException("Error closing SqlSession.  Cause: " + e, e);

    } finally {

        // 清理资源

        dirty = false;

        executor = null;

        configuration = null;

    }

}

4.4.2 自动关闭

// 使用try-with-resources语法

try (SqlSession session = sqlSessionFactory.openSession()) {

    User user = session.selectOne("selectUser", 1);

    // 自动关闭

}

5. DefaultSqlSession实现分析

5.1 DefaultSqlSession类结构

public class DefaultSqlSession implements SqlSession {

    private final Configuration configuration;

    private final Executor executor;

    private final boolean autoCommit;

    private boolean dirty;

    private List<Cursor<?>> cursorList;


    public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {

        this.configuration = configuration;

        this.executor = executor;

        this.dirty = false;

        this.autoCommit = autoCommit;

    }

}

5.2 核心方法实现分析

5.2.1 selectOne方法实现

@Override

public <T> T selectOne(String statement, Object parameter) {

    // 调用selectList获取结果

    List<T> list = this.selectList(statement, parameter);


    // 结果数量验证

    if (list.size() == 1) {

        return list.get(0);

    }

    if (list.size() > 1) {

        throw new TooManyResultsException(

            "Expected one result (or null) to be returned by selectOne(), but found: " + list.size());

    } else {

        return null;

    }

}

设计亮点:

复用selectList:避免代码重复

结果验证:确保返回单个结果

异常处理:结果过多时抛出异常

5.2.2 selectList方法实现

@Override

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {

    try {

        // 1. 获取MappedStatement

        MappedStatement ms = configuration.getMappedStatement(statement);


        // 2. 委托给Executor执行

        return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

    } catch (Exception e) {

        throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);

    } finally {

        ErrorContext.instance().reset();

    }

}

执行流程:

获取映射语句:从Configuration获取MappedStatement

参数包装:处理集合参数

委托执行:委托给Executor执行查询

异常处理:统一异常处理

资源清理:重置错误上下文

5.2.3 update方法实现

@Override

public int update(String statement, Object parameter) {

    try {

        // 1. 标记为脏数据

        dirty = true;


        // 2. 获取MappedStatement

        MappedStatement ms = configuration.getMappedStatement(statement);


        // 3. 委托给Executor执行

        return executor.update(ms, wrapCollection(parameter));

    } catch (Exception e) {

        throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);

    } finally {

        ErrorContext.instance().reset();

    }

}

设计特点:

脏数据标记:标记SqlSession为脏状态

统一处理:insert、update、delete都使用相同逻辑

5.2.4 事务管理方法

@Override

public void commit() {

    commit(false);

}

@Override

public void commit(boolean force) {

    try {

        executor.commit(isCommitOrRollbackRequired(force));

        dirty = false;

    } catch (Exception e) {

        throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);

    } finally {

        ErrorContext.instance().reset();

    }

}

@Override

public void rollback() {

    rollback(false);

}

@Override

public void rollback(boolean force) {

    try {

        executor.rollback(isCommitOrRollbackRequired(force));

        dirty = false;

    } catch (Exception e) {

        throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);

    } finally {

        ErrorContext.instance().reset();

    }

}

事务管理特点:

条件提交:根据dirty状态决定是否需要提交

强制选项:支持强制提交/回滚

状态重置:提交/回滚后重置dirty状态

6. Executor执行器体系分析

6.1 Executor接口设计

Executor是MyBatis执行器的核心接口,其继承关系如下:

«interface»

Executor

+update()

+query()

+queryCursor()

+flushStatements()

+commit()

+rollback()

+createCacheKey()

+clearLocalCache()

«abstract»

BaseExecutor

#doQuery()

#doUpdate()

#doFlushStatements()

SimpleExecutor

+doQuery()

+doUpdate()

ReuseExecutor

-Map<String,Statement> statementMap

+doQuery()

+doUpdate()

BatchExecutor

-List<Statement> statementList

-List<BatchResult> batchResultList

+doQuery()

+doUpdate()

CachingExecutor

-Executor delegate

-TransactionalCacheManager tcm

+query()

+update()

Executor是MyBatis执行器的核心接口:

public interface Executor {

    // 查询操作

    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

    <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

    <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;


    // 更新操作

    int update(MappedStatement ms, Object parameter) throws SQLException;


    // 事务管理

    void commit(boolean required) throws SQLException;

    void rollback(boolean required) throws SQLException;


    // 缓存管理

    CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

    boolean isCached(MappedStatement ms, CacheKey key);

    void clearLocalCache();


    // 延迟加载

    void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);


    // 批量操作

    List<BatchResult> flushStatements() throws SQLException;


    // 资源管理

    Transaction getTransaction();

    void close(boolean forceRollback);

    boolean isClosed();

}

6.2 BaseExecutor抽象基类

BaseExecutor是Executor的抽象基类,实现了模板方法模式:

public abstract class BaseExecutor implements Executor {

    protected Transaction transaction;

    protected Executor wrapper;

    protected PerpetualCache localCache;

    protected PerpetualCache localOutputParameterCache;

    protected Configuration configuration;

    protected int queryStack;

    private boolean closed;


    // 模板方法:查询操作

    @Override

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {

        BoundSql boundSql = ms.getBoundSql(parameter);

        CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);

        return query(ms, parameter, rowBounds, resultHandler, key, boundSql);

    }


    @Override

    public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException {

        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());

        if (closed) {

            throw new ExecutorException("Executor was closed.");

        }

        if (queryStack == 0 && ms.isFlushCacheRequired()) {

            clearLocalCache();

        }

        List<E> list;

        try {

            queryStack++;

            list = resultHandler == null ? (List<E>) localCache.getObject(cacheKey) : null;

            if (list != null) {

                handleLocallyCachedOutputParameters(ms, cacheKey, parameter, boundSql);

            } else {

                list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);

            }

        } finally {

            queryStack--;

        }

        if (queryStack == 0) {

            for (DeferredLoad deferredLoad : deferredLoads) {

                deferredLoad.load();

            }

            deferredLoads.clear();

            if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {

                clearLocalCache();

            }

        }

        return list;

    }


    // 抽象方法:子类实现具体的数据库查询

    protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;


    // 模板方法:更新操作

    @Override

    public int update(MappedStatement ms, Object parameter) throws SQLException {

        ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());

        if (closed) {

            throw new ExecutorException("Executor was closed.");

        }

        clearLocalCache();

        return doUpdate(ms, parameter);

    }


    // 抽象方法:子类实现具体的数据库更新

    protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

}

6.3 具体执行器实现

6.3.1 SimpleExecutor

public class SimpleExecutor extends BaseExecutor {


    public SimpleExecutor(Configuration configuration, Transaction transaction) {

        super(configuration, transaction);

    }


    @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);

        }

    }


    @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);

        }

    }


    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

        Statement stmt;

        Connection connection = getConnection(statementLog);

        stmt = handler.prepare(connection, transaction.getTimeout());

        handler.parameterize(stmt);

        return stmt;

    }

}

特点:

简单实现:每次执行都创建新的Statement

资源管理:及时关闭Statement和Connection

性能考虑:适合单次执行场景

6.3.2 ReuseExecutor

public class ReuseExecutor extends BaseExecutor {

    private final Map<String, Statement> 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(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

        Statement stmt = prepareStatement(handler, ms.getStatementLog());

        return handler.query(stmt, resultHandler);

    }


    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {

        Statement stmt;

        BoundSql boundSql = handler.getBoundSql();

        String sql = boundSql.getSql();

        if (hasStatementFor(sql)) {

            stmt = getStatement(sql);

            applyTransactionTimeout(stmt);

        } else {

            Connection connection = getConnection(statementLog);

            stmt = handler.prepare(connection, transaction.getTimeout());

            putStatement(sql, stmt);

        }

        handler.parameterize(stmt);

        return stmt;

    }


    private boolean hasStatementFor(String sql) {

        return statementMap.containsKey(sql);

    }


    private Statement getStatement(String sql) {

        return statementMap.get(sql);

    }


    private void putStatement(String sql, Statement stmt) {

        statementMap.put(sql, stmt);

    }

}

特点:

Statement重用:相同SQL重用Statement对象

性能优化:减少Statement创建开销

内存管理:需要管理Statement缓存

6.3.3 BatchExecutor

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 {

        final Configuration configuration = ms.getConfiguration();

        final StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

        final BoundSql boundSql = handler.getBoundSql();

        final String sql = boundSql.getSql();

        final StatementType statementType = ms.getStatementType();


        if (sql.equals(currentSql) && statementType == currentStatement.getStatementType()) {

            // 相同SQL,重用Statement

            final Statement stmt = statementList.get(statementList.size() - 1);

            applyTransactionTimeout(stmt);

            handler.parameterize(stmt);

            BatchResult batchResult = batchResultList.get(batchResultList.size() - 1);

            batchResult.addParameterObject(parameter);

            return BATCH_UPDATE_RETURN_VALUE;

        } else {

            // 不同SQL,创建新Statement

            final Statement stmt;

            if (sql.equals(currentSql) && ms.getStatementType() == currentStatement.getStatementType()) {

                int last = statementList.size() - 1;

                stmt = statementList.get(last);

                applyTransactionTimeout(stmt);

                handler.parameterize(stmt);

                BatchResult batchResult = batchResultList.get(last);

                batchResult.addParameterObject(parameter);

            } else {

                Connection connection = getConnection(ms.getStatementLog());

                stmt = handler.prepare(connection, transaction.getTimeout());

                handler.parameterize(stmt);

                currentSql = sql;

                currentStatement = ms;

                statementList.add(stmt);

                batchResultList.add(new BatchResult(ms, sql, parameter));

            }

            handler.batch(stmt);

            return BATCH_UPDATE_RETURN_VALUE;

        }

    }

}

特点:

批量执行:收集多个SQL语句批量执行

性能优化:减少数据库交互次数

结果管理:管理批量执行的结果

6.4 CachingExecutor缓存装饰器

public class CachingExecutor implements Executor {

    private final Executor delegate;

    private final TransactionalCacheManager tcm = new TransactionalCacheManager();


    public CachingExecutor(Executor delegate) {

        this.delegate = delegate;

        delegate.setExecutorWrapper(this);

    }


    @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) {

            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);

                }

                return list;

            }

        }

        return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

    }


    @Override

    public int update(MappedStatement ms, Object parameterObject) throws SQLException {

        flushCacheIfRequired(ms);

        return delegate.update(ms, parameterObject);

    }


    private void flushCacheIfRequired(MappedStatement ms) {

        Cache cache = ms.getCache();

        if (cache != null && ms.isFlushCacheRequired()) {

            tcm.clear(cache);

        }

    }

}

特点:

装饰器模式:包装其他执行器,添加缓存功能

二级缓存:支持跨SqlSession的缓存

缓存管理:自动管理缓存的刷新和清理

6.4 Executor类型总结

执行器类型 特点 适用场景 性能特点

SimpleExecutor 每次执行创建新Statement 单次执行、简单查询 简单直接,适合轻量级操作

ReuseExecutor 重用相同SQL的Statement 重复执行相同SQL 减少Statement创建开销

BatchExecutor 批量执行多个SQL 批量插入、更新、删除 大幅减少数据库交互次数

CachingExecutor 装饰器模式,添加缓存 需要缓存的查询场景 避免重复查询,提升性能

选择建议:

默认场景:使用SimpleExecutor,简单可靠

重复SQL:使用ReuseExecutor,提升性能

批量操作:使用BatchExecutor,大幅提升批量操作性能

缓存需求:配合CachingExecutor,提升查询性能

7. 实践案例

7.1 跟踪SqlSession创建流程

让我们通过一个完整的例子来跟踪SqlSession的创建流程:

7.1.1 mybatis-config.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration

        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <environments default="development">

        <environment id="development">

            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">

                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>

                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_test"/>

                <property name="username" value="root"/>

                <property name="password" value="password"/>

            </dataSource>

        </environment>

    </environments>


    <mappers>

        <mapper resource="UserMapper.xml"/>

    </mappers>

</configuration>

7.1.2 UserMapper.java接口

package com.example.mapper;

import com.example.model.User;

import java.util.List;

public interface UserMapper {

    User selectUser(int id);

    List<User> selectAllUsers();

    int insertUser(User user);

    int updateUser(User user);

    int deleteUser(int id);

}

7.1.3 SqlSession创建示例

package com.example;

import com.example.mapper.UserMapper;

import com.example.model.User;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

import java.io.InputStream;

public class SqlSessionCreationExample {

    public static void main(String[] args) throws IOException {

        // 1. 创建SqlSessionFactoryBuilder

        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();


        // 2. 解析配置文件,创建SqlSessionFactory

        String resource = "mybatis-config.xml";

        InputStream inputStream = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = builder.build(inputStream);


        // 3. 创建SqlSession

        SqlSession session = sqlSessionFactory.openSession();


        // 4. 使用SqlSession

        User user = session.selectOne("selectUser", 1);

        System.out.println("查询结果: " + user);


        // 5. 使用Mapper接口

        UserMapper userMapper = session.getMapper(UserMapper.class);

        User user2 = userMapper.selectUser(1);

        System.out.println("Mapper查询结果: " + user2);


        // 6. 关闭SqlSession

        session.close();

    }

}

执行流程分析:

SqlSessionFactoryBuilder.build():

创建XMLConfigBuilder

解析配置文件

创建Configuration对象

创建DefaultSqlSessionFactory

DefaultSqlSessionFactory.openSession():

调用openSessionFromDataSource()

获取Environment配置

创建TransactionFactory

创建Transaction对象

创建Executor

创建DefaultSqlSession

DefaultSqlSession使用:

调用selectOne()方法

内部调用selectList()

委托给Executor执行

返回查询结果

资源释放:

调用session.close()

关闭Executor

关闭Transaction

关闭Connection

7.2 分析不同Executor类型的使用场景

public class ExecutorTypeExample {

    public static void main(String[] args) {

        SqlSessionFactory sqlSessionFactory = createSqlSessionFactory();


        // 1. 使用SimpleExecutor(默认)

        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.SIMPLE)) {

            System.out.println("使用SimpleExecutor执行查询");

            User user = session.selectOne("selectUser", 1);

            System.out.println("查询结果: " + user);

        }


        // 2. 使用ReuseExecutor

        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.REUSE)) {

            System.out.println("使用ReuseExecutor执行查询");

            User user = session.selectOne("selectUser", 1);

            System.out.println("查询结果: " + user);

        }


        // 3. 使用BatchExecutor

        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {

            System.out.println("使用BatchExecutor执行批量更新");


            // 批量插入

            for (int i = 1; i <= 10; i++) {

                User user = new User(i, "User" + i, "user" + i + "@example.com");

                session.insert("insertUser", user);

            }


            // 执行批量操作

            List<BatchResult> results = session.flushStatements();

            System.out.println("批量执行结果数量: " + results.size());


            // 提交事务

            session.commit();

        }

    }

}

7.3 分析SqlSession的生命周期管理

public class SqlSessionLifecycleExample {

    public static void main(String[] args) {

        SqlSessionFactory sqlSessionFactory = createSqlSessionFactory();


        // 1. 手动管理生命周期

        SqlSession session = sqlSessionFactory.openSession();

        try {

            // 执行业务操作

            User user = session.selectOne("selectUser", 1);

            System.out.println("查询结果: " + user);


            // 提交事务

            session.commit();

        } catch (Exception e) {

            // 回滚事务

            session.rollback();

            e.printStackTrace();

        } finally {

            // 关闭会话

            session.close();

        }


        // 2. 自动管理生命周期(推荐方式)

        try (SqlSession session2 = sqlSessionFactory.openSession()) {

            User user = session2.selectOne("selectUser", 1);

            System.out.println("查询结果: " + user);

            session2.commit();

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

8. 后续文章规划

基于SqlSession的理解,后续我们将深入分析:

第4篇:Mapper接口的动态代理机制

MapperProxy源码分析

接口方法解析

参数绑定和结果映射

第5篇:Executor执行器体系详解

BaseExecutor模板方法模式

StatementHandler语句处理器

ParameterHandler参数处理器

ResultSetHandler结果集处理器

第6篇:StatementHandler语句处理器

RoutingStatementHandler路由机制

PreparedStatementHandler实现

SQL预处理和参数绑定

总结

通过本文的学习,我们深入了解了MyBatis SqlSession的核心机制:

SqlSession接口:提供了完整的数据库操作API,支持查询、更新、事务管理等功能

SqlSessionFactory:采用工厂模式,封装了SqlSession的创建复杂性

DefaultSqlSession:SqlSession的默认实现,是用户操作数据库的主要入口

Executor执行器:SqlSession的核心组件,负责具体的SQL执行

生命周期管理:从创建到销毁的完整生命周期管理

重要提示:SqlSession是MyBatis架构的核心,理解SqlSession对于后续的源码学习至关重要。通过源码分析,我们能够更深入地理解MyBatis的设计思想和实现细节。

在下一篇文章中,我们将基于SqlSession的理解,深入分析Mapper接口的动态代理机制,了解MyBatis是如何实现接口代理的。

思考题:

为什么MyBatis要设计SqlSession接口?这种设计有什么优势?

SqlSessionFactory的工厂模式设计有什么好处?

不同Executor类型的适用场景是什么?如何选择?

SqlSession的生命周期管理需要注意哪些问题?

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容