最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SqlSession的創(chuàng)建與生命周期源碼解讀

 更新時間:2025年09月25日 08:50:29   作者:lunzi_fly  
文章解析了MyBatis?SqlSession的核心作用、工廠模式、Executor類型及生命周期管理,說明其設(shè)計優(yōu)勢與性能優(yōu)化,為后續(xù)源碼分析奠定基礎(chǔ),本文給大家詳細介紹SqlSession的創(chuàng)建與生命周期,感興趣的朋友一起看看吧

1. 學習目標確認

1.0 第2篇思考題解答

在深入學習SqlSession之前,讓我們先回顧并解答第2篇中提出的思考題,這將幫助我們更好地理解SqlSession在整個架構(gòu)中的作用。

思考題1:為什么MyBatis要設(shè)計如此復雜的配置系統(tǒng)?

答案要點

  • 統(tǒng)一管理:所有配置項集中管理,避免配置分散和重復
  • 靈活性:支持XML、注解、代碼三種配置方式,滿足不同場景需求
  • 可擴展性:通過插件系統(tǒng)和自定義配置支持功能擴展
  • 性能優(yōu)化:配置緩存、懶加載等機制提升性能
  • 類型安全:強類型配置減少運行時錯誤

SqlSession的作用:SqlSession作為配置系統(tǒng)的使用者,通過Configuration獲取所有必要的配置信息。

思考題2:配置系統(tǒng)的擴展性體現(xiàn)在哪些方面?

答案要點

  • 插件擴展:Interceptor接口支持功能擴展
  • 類型處理器擴展:TypeHandler接口支持自定義類型轉(zhuǎn)換
  • 對象工廠擴展:ObjectFactory接口支持自定義對象創(chuàng)建
  • 數(shù)據(jù)源擴展:DataSource接口支持自定義數(shù)據(jù)源
  • 事務(wù)管理擴展:TransactionFactory接口支持自定義事務(wù)管理

SqlSession的擴展性:SqlSession通過Executor、StatementHandler等組件實現(xiàn)功能擴展。

思考題3:如何優(yōu)化配置解析的性能?

答案要點

  • 緩存機制:解析后的配置對象緩存,避免重復解析
  • 懶加載:非必需配置延遲加載,減少啟動時間
  • 批量處理:相關(guān)配置項批量解析,提高效率
  • 內(nèi)存優(yōu)化:優(yōu)化配置對象的內(nèi)存使用,減少GC壓力

SqlSession的性能:SqlSession通過Executor緩存、連接池等技術(shù)優(yōu)化性能。

思考題4:基于配置系統(tǒng)的理解,應(yīng)該從哪個組件開始深入源碼分析?

推薦順序:SqlSession → Executor → StatementHandler → ParameterHandler + ResultSetHandler

從SqlSession開始的原因

  • SqlSession是配置系統(tǒng)的直接使用者
  • 理解SqlSession有助于理解整個執(zhí)行流程
  • 為后續(xù)學習Executor等組件奠定基礎(chǔ)

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

SqlSession是MyBatis的核心接口,代表與數(shù)據(jù)庫的一次會話。它是MyBatis架構(gòu)中接口層的重要組成部分,為用戶提供了簡潔的API來執(zhí)行數(shù)據(jù)庫操作。

SqlSession的核心職責

  • 數(shù)據(jù)庫操作:提供CRUD操作的統(tǒng)一接口
  • 事務(wù)管理:管理數(shù)據(jù)庫事務(wù)的提交和回滾
  • Mapper管理:獲取Mapper接口的動態(tài)代理對象
  • 會話管理:管理會話的生命周期和資源釋放

重要提示:理解SqlSession的設(shè)計和實現(xiàn)是深入MyBatis源碼的關(guān)鍵,后續(xù)的Executor、StatementHandler等組件都圍繞SqlSession展開。

2. SqlSession接口設(shè)計分析

2.1 SqlSession接口結(jié)構(gòu)

讓我們深入分析SqlSession接口的設(shè)計:

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);
    // 自定義結(jié)果處理(流式結(jié)果)
    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);
    // 事務(wù)管理
    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 接口設(shè)計特點分析

2.2.1 泛型設(shè)計

// 泛型設(shè)計提供了類型安全
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter);

優(yōu)勢

  • 類型安全:編譯時類型檢查,避免運行時類型轉(zhuǎn)換錯誤
  • 代碼簡潔:無需手動類型轉(zhuǎn)換
  • IDE支持:更好的代碼提示和重構(gòu)支持

2.2.2 ResultHandler自定義結(jié)果處理

// 支持自定義結(jié)果處理,適用于流式結(jié)果處理
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

使用場景

  • 流式處理:處理大量數(shù)據(jù)時避免內(nèi)存溢出
  • 自定義轉(zhuǎn)換:對結(jié)果進行自定義處理
  • 實時處理:邊查詢邊處理結(jié)果

示例用法

// 流式處理大量數(shù)據(jù)
session.select("selectAllUsers", null, new ResultHandler<User>() {
    @Override
    public void handleResult(ResultContext<? extends User> resultContext) {
        User user = resultContext.getResultObject();
        // 實時處理每個用戶數(shù)據(jù)
        processUser(user);
    }
});

2.2.3 方法重載設(shè)計

// 支持不同參數(shù)組合
<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);

優(yōu)勢

  • 使用靈活:支持不同使用場景
  • 向后兼容:保持API的向后兼容性
  • 漸進式學習:從簡單到復雜的使用方式

2.2.4 資源管理設(shè)計

public interface SqlSession extends Closeable {
    // 繼承Closeable接口,支持try-with-resources語法
}

優(yōu)勢

  • 自動資源管理:支持try-with-resources語法
  • 防止資源泄漏:確保資源正確釋放
  • 代碼簡潔:減少樣板代碼

3. SqlSessionFactory工廠模式分析

3.1 SqlSessionFactory接口設(shè)計

SqlSessionFactory是創(chuàng)建SqlSession的工廠接口,采用工廠模式設(shè)計:

package org.apache.ibatis.session;
import java.sql.Connection;
public interface SqlSessionFactory {
    // 基本創(chuàng)建方法
    SqlSession openSession();
    SqlSession openSession(boolean autoCommit);
    SqlSession openSession(Connection connection);
    // 執(zhí)行器類型指定
    SqlSession openSession(ExecutorType execType);
    SqlSession openSession(ExecutorType execType, boolean autoCommit);
    SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
    SqlSession openSession(ExecutorType execType, Connection connection);
    // 事務(wù)隔離級別指定
    SqlSession openSession(TransactionIsolationLevel level);
    // 配置獲取
    Configuration getConfiguration();
}

3.2 DefaultSqlSessionFactory實現(xiàn)分析

DefaultSqlSessionFactory是SqlSessionFactory的默認實現(xiàn),讓我們深入分析其源碼:

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);
    }
    // 核心創(chuàng)建方法
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;
        try {
            // 1. 獲取環(huán)境配置
            final Environment environment = configuration.getEnvironment();
            // 2. 獲取事務(wù)工廠
            final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
            // 3. 創(chuàng)建事務(wù)
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            // 4. 創(chuàng)建執(zhí)行器
            final Executor executor = configuration.newExecutor(tx, execType);
            // 5. 創(chuàng)建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 工廠模式的優(yōu)勢

3.3.1 封裝復雜性

// 用戶只需要調(diào)用簡單的方法
SqlSession session = sqlSessionFactory.openSession();
// 內(nèi)部復雜的創(chuàng)建過程被封裝
// 1. 環(huán)境配置獲取
// 2. 事務(wù)工廠創(chuàng)建
// 3. 事務(wù)對象創(chuàng)建
// 4. 執(zhí)行器創(chuàng)建
// 5. SqlSession創(chuàng)建

3.3.2 參數(shù)靈活性

// 支持多種參數(shù)組合
SqlSession session1 = sqlSessionFactory.openSession(); // 默認配置
SqlSession session2 = sqlSessionFactory.openSession(true); // 自動提交
SqlSession session3 = sqlSessionFactory.openSession(ExecutorType.BATCH); // 批處理執(zhí)行器

3.3.3 配置驅(qū)動

// 基于Configuration配置創(chuàng)建SqlSession
final Executor executor = configuration.newExecutor(tx, execType);

4. SqlSession生命周期管理

4.1 生命周期階段

SqlSession的生命周期可以分為以下幾個階段:

4.2 創(chuàng)建階段詳細分析

4.2.1 配置獲取

// 從Configuration獲取環(huán)境配置
final Environment environment = configuration.getEnvironment();

Environment包含

  • DataSource:數(shù)據(jù)源配置
  • TransactionFactory:事務(wù)工廠配置
  • Id:環(huán)境標識

4.2.2 事務(wù)創(chuàng)建

// 創(chuàng)建事務(wù)對象
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

事務(wù)創(chuàng)建過程

  • 獲取事務(wù)工廠:從環(huán)境配置獲取TransactionFactory
  • 創(chuàng)建事務(wù)對象:使用DataSource和參數(shù)創(chuàng)建Transaction
  • 設(shè)置事務(wù)屬性:隔離級別、自動提交等

4.2.3 執(zhí)行器創(chuàng)建

// 創(chuàng)建執(zhí)行器
final Executor executor = configuration.newExecutor(tx, execType);

執(zhí)行器創(chuàng)建過程

  • 執(zhí)行器類型選擇:根據(jù)ExecutorType選擇具體實現(xiàn)
  • 緩存包裝:如果啟用緩存,用CachingExecutor包裝
  • 插件應(yīng)用:應(yīng)用所有配置的插件

4.2.4 SqlSession創(chuàng)建

// 創(chuàng)建SqlSession對象
return new DefaultSqlSession(configuration, executor, autoCommit);

4.3 使用階段分析

4.3.1 SQL執(zhí)行流程

// 用戶調(diào)用
User user = session.selectOne("selectUser", 1);
// 內(nèi)部執(zhí)行流程
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獲取流程

// 用戶調(diào)用
UserMapper mapper = session.getMapper(UserMapper.class);
// 內(nèi)部實現(xiàn)
@Override
public <T> T getMapper(Class<T> type) {
    return configuration.getMapper(type, this);
}

4.4 資源釋放階段

4.4.1 手動關(guān)閉

// 手動關(guān)閉SqlSession
session.close();
// 內(nèi)部關(guān)閉流程
@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 自動關(guān)閉

// 使用try-with-resources語法
try (SqlSession session = sqlSessionFactory.openSession()) {
    User user = session.selectOne("selectUser", 1);
    // 自動關(guān)閉
}

5. DefaultSqlSession實現(xiàn)分析

5.1 DefaultSqlSession類結(jié)構(gòu)

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 核心方法實現(xiàn)分析

5.2.1 selectOne方法實現(xiàn)

@Override
public <T> T selectOne(String statement, Object parameter) {
    // 調(diào)用selectList獲取結(jié)果
    List<T> list = this.selectList(statement, parameter);
    // 結(jié)果數(shù)量驗證
    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;
    }
}

設(shè)計亮點

  • 復用selectList:避免代碼重復
  • 結(jié)果驗證:確保返回單個結(jié)果
  • 異常處理:結(jié)果過多時拋出異常

5.2.2 selectList方法實現(xiàn)

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        // 1. 獲取MappedStatement
        MappedStatement ms = configuration.getMappedStatement(statement);
        // 2. 委托給Executor執(zhí)行
        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();
    }
}

執(zhí)行流程

  • 獲取映射語句:從Configuration獲取MappedStatement
  • 參數(shù)包裝:處理集合參數(shù)
  • 委托執(zhí)行:委托給Executor執(zhí)行查詢
  • 異常處理:統(tǒng)一異常處理
  • 資源清理:重置錯誤上下文

5.2.3 update方法實現(xiàn)

@Override
public int update(String statement, Object parameter) {
    try {
        // 1. 標記為臟數(shù)據(jù)
        dirty = true;
        // 2. 獲取MappedStatement
        MappedStatement ms = configuration.getMappedStatement(statement);
        // 3. 委托給Executor執(zhí)行
        return executor.update(ms, wrapCollection(parameter));
    } catch (Exception e) {
        throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

設(shè)計特點

  • 臟數(shù)據(jù)標記:標記SqlSession為臟狀態(tài)
  • 統(tǒng)一處理:insert、update、delete都使用相同邏輯

5.2.4 事務(wù)管理方法

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

事務(wù)管理特點

  • 條件提交:根據(jù)dirty狀態(tài)決定是否需要提交
  • 強制選項:支持強制提交/回滾
  • 狀態(tài)重置:提交/回滾后重置dirty狀態(tài)

6. Executor執(zhí)行器體系分析

6.1 Executor接口設(shè)計

Executor是MyBatis執(zhí)行器的核心接口,其繼承關(guān)系如下:

Executor是MyBatis執(zhí)行器的核心接口:

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;
    // 事務(wù)管理
    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的抽象基類,實現(xiàn)了模板方法模式:

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;
    }
    // 抽象方法:子類實現(xiàn)具體的數(shù)據(jù)庫查詢
    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);
    }
    // 抽象方法:子類實現(xiàn)具體的數(shù)據(jù)庫更新
    protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
}

6.3 具體執(zhí)行器實現(xiàn)

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

特點

  • 簡單實現(xiàn):每次執(zhí)行都創(chuàng)建新的Statement
  • 資源管理:及時關(guān)閉Statement和Connection
  • 性能考慮:適合單次執(zhí)行場景

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對象
  • 性能優(yōu)化:減少Statement創(chuàng)建開銷
  • 內(nèi)存管理:需要管理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,創(chuàng)建新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;
        }
    }
}

特點

  • 批量執(zhí)行:收集多個SQL語句批量執(zhí)行
  • 性能優(yōu)化:減少數(shù)據(jù)庫交互次數(shù)
  • 結(jié)果管理:管理批量執(zhí)行的結(jié)果

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

特點

  • 裝飾器模式:包裝其他執(zhí)行器,添加緩存功能
  • 二級緩存:支持跨SqlSession的緩存
  • 緩存管理:自動管理緩存的刷新和清理

6.4 Executor類型總結(jié)

執(zhí)行器類型特點適用場景性能特點
SimpleExecutor每次執(zhí)行創(chuàng)建新Statement單次執(zhí)行、簡單查詢簡單直接,適合輕量級操作
ReuseExecutor重用相同SQL的Statement重復執(zhí)行相同SQL減少Statement創(chuàng)建開銷
BatchExecutor批量執(zhí)行多個SQL批量插入、更新、刪除大幅減少數(shù)據(jù)庫交互次數(shù)
CachingExecutor裝飾器模式,添加緩存需要緩存的查詢場景避免重復查詢,提升性能

選擇建議

  • 默認場景:使用SimpleExecutor,簡單可靠
  • 重復SQL:使用ReuseExecutor,提升性能
  • 批量操作:使用BatchExecutor,大幅提升批量操作性能
  • 緩存需求:配合CachingExecutor,提升查詢性能

7. 實踐案例

7.1 跟蹤SqlSession創(chuàng)建流程

讓我們通過一個完整的例子來跟蹤SqlSession的創(chuàng)建流程:

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創(chuàng)建示例

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. 創(chuàng)建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        // 2. 解析配置文件,創(chuàng)建SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
        // 3. 創(chuàng)建SqlSession
        SqlSession session = sqlSessionFactory.openSession();
        // 4. 使用SqlSession
        User user = session.selectOne("selectUser", 1);
        System.out.println("查詢結(jié)果: " + user);
        // 5. 使用Mapper接口
        UserMapper userMapper = session.getMapper(UserMapper.class);
        User user2 = userMapper.selectUser(1);
        System.out.println("Mapper查詢結(jié)果: " + user2);
        // 6. 關(guān)閉SqlSession
        session.close();
    }
}

執(zhí)行流程分析

  • SqlSessionFactoryBuilder.build()
    • 創(chuàng)建XMLConfigBuilder
    • 解析配置文件
    • 創(chuàng)建Configuration對象
    • 創(chuàng)建DefaultSqlSessionFactory
  • DefaultSqlSessionFactory.openSession()
    • 調(diào)用openSessionFromDataSource()
    • 獲取Environment配置
    • 創(chuàng)建TransactionFactory
    • 創(chuàng)建Transaction對象
    • 創(chuàng)建Executor
    • 創(chuàng)建DefaultSqlSession
  • DefaultSqlSession使用
    • 調(diào)用selectOne()方法
    • 內(nèi)部調(diào)用selectList()
    • 委托給Executor執(zhí)行
    • 返回查詢結(jié)果
  • 資源釋放
    • 調(diào)用session.close()
    • 關(guān)閉Executor
    • 關(guān)閉Transaction
    • 關(guān)閉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執(zhí)行查詢");
            User user = session.selectOne("selectUser", 1);
            System.out.println("查詢結(jié)果: " + user);
        }
        // 2. 使用ReuseExecutor
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.REUSE)) {
            System.out.println("使用ReuseExecutor執(zhí)行查詢");
            User user = session.selectOne("selectUser", 1);
            System.out.println("查詢結(jié)果: " + user);
        }
        // 3. 使用BatchExecutor
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
            System.out.println("使用BatchExecutor執(zhí)行批量更新");
            // 批量插入
            for (int i = 1; i <= 10; i++) {
                User user = new User(i, "User" + i, "user" + i + "@example.com");
                session.insert("insertUser", user);
            }
            // 執(zhí)行批量操作
            List<BatchResult> results = session.flushStatements();
            System.out.println("批量執(zhí)行結(jié)果數(shù)量: " + results.size());
            // 提交事務(wù)
            session.commit();
        }
    }
}

7.3 分析SqlSession的生命周期管理

public class SqlSessionLifecycleExample {
    public static void main(String[] args) {
        SqlSessionFactory sqlSessionFactory = createSqlSessionFactory();
        // 1. 手動管理生命周期
        SqlSession session = sqlSessionFactory.openSession();
        try {
            // 執(zhí)行業(yè)務(wù)操作
            User user = session.selectOne("selectUser", 1);
            System.out.println("查詢結(jié)果: " + user);
            // 提交事務(wù)
            session.commit();
        } catch (Exception e) {
            // 回滾事務(wù)
            session.rollback();
            e.printStackTrace();
        } finally {
            // 關(guān)閉會話
            session.close();
        }
        // 2. 自動管理生命周期(推薦方式)
        try (SqlSession session2 = sqlSessionFactory.openSession()) {
            User user = session2.selectOne("selectUser", 1);
            System.out.println("查詢結(jié)果: " + user);
            session2.commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

8. 后續(xù)文章規(guī)劃

基于SqlSession的理解,后續(xù)我們將深入分析:

  • 第4篇:Mapper接口的動態(tài)代理機制
    • MapperProxy源碼分析
    • 接口方法解析
    • 參數(shù)綁定和結(jié)果映射
  • 第5篇:Executor執(zhí)行器體系詳解
    • BaseExecutor模板方法模式
    • StatementHandler語句處理器
    • ParameterHandler參數(shù)處理器
    • ResultSetHandler結(jié)果集處理器
  • 第6篇:StatementHandler語句處理器
    • RoutingStatementHandler路由機制
    • PreparedStatementHandler實現(xiàn)
    • SQL預處理和參數(shù)綁定

總結(jié)

通過本文的學習,我們深入了解了MyBatis SqlSession的核心機制:

  • SqlSession接口:提供了完整的數(shù)據(jù)庫操作API,支持查詢、更新、事務(wù)管理等功能
  • SqlSessionFactory:采用工廠模式,封裝了SqlSession的創(chuàng)建復雜性
  • DefaultSqlSession:SqlSession的默認實現(xiàn),是用戶操作數(shù)據(jù)庫的主要入口
  • Executor執(zhí)行器:SqlSession的核心組件,負責具體的SQL執(zhí)行
  • 生命周期管理:從創(chuàng)建到銷毀的完整生命周期管理

重要提示:SqlSession是MyBatis架構(gòu)的核心,理解SqlSession對于后續(xù)的源碼學習至關(guān)重要。通過源碼分析,我們能夠更深入地理解MyBatis的設(shè)計思想和實現(xiàn)細節(jié)。

在下一篇文章中,我們將基于SqlSession的理解,深入分析Mapper接口的動態(tài)代理機制,了解MyBatis是如何實現(xiàn)接口代理的。

思考題

  • 為什么MyBatis要設(shè)計SqlSession接口?這種設(shè)計有什么優(yōu)勢?
  • SqlSessionFactory的工廠模式設(shè)計有什么好處?
  • 不同Executor類型的適用場景是什么?如何選擇?
  • SqlSession的生命周期管理需要注意哪些問題?

到此這篇關(guān)于SqlSession的創(chuàng)建與生命周期的文章就介紹到這了,更多相關(guān)SqlSession的創(chuàng)建與生命周期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

三亚市| 射洪县| 常山县| 兴国县| 乐昌市| 宝坻区| 泽库县| 大同市| 石景山区| 乐陵市| 凤冈县| 钦州市| 保靖县| 阆中市| 红安县| 寿宁县| 浦东新区| 太原市| 称多县| 双鸭山市| 汝州市| 深圳市| 青阳县| 昌黎县| 浦北县| 海宁市| 新和县| 合山市| 垦利县| 桦甸市| 澄城县| 闸北区| 边坝县| 会昌县| 和田市| 万载县| 黄龙县| 广州市| 海原县| 崇左市| 左云县|