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

MyBatis SQL執(zhí)行流程的使用詳解

 更新時(shí)間:2026年02月28日 10:51:55   作者:程序員越  
本文主要介紹了MyBatis SQL執(zhí)行流程的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

本文將以最常用的select list查詢流程為核心,結(jié)合核心對(duì)象、代碼實(shí)現(xiàn)與執(zhí)行鏈路,全面拆解MyBatis SQL執(zhí)行的完整過程。

一、select list流程

1. 基本使用(編程式調(diào)用示例)

以下代碼展示了MyBatis編程式調(diào)用Mapper接口執(zhí)行查詢列表的完整示例,涵蓋從環(huán)境配置、SqlSession創(chuàng)建到結(jié)果獲取的全步驟,適用于理解底層執(zhí)行邏輯。

// 1. 獲取數(shù)據(jù)源(模擬配置,實(shí)際可通過mybatis-config.xml配置)
DataSource dataSource = TestDataSourceFactory.getDataSource();
// 2. 創(chuàng)建事務(wù)工廠(JDBC事務(wù)工廠,依賴JDBC原生事務(wù)管理)
TransactionFactory transactionFactory = new JdbcTransactionFactory();
// 3. 構(gòu)建環(huán)境對(duì)象(包含環(huán)境名稱、事務(wù)工廠、數(shù)據(jù)源)
Environment environment = new Environment("dev", transactionFactory, dataSource);
// 4. 初始化配置對(duì)象(MyBatis核心配置載體,存儲(chǔ)所有配置信息)
Configuration configuration = new Configuration(environment);
// 5. 注冊(cè)Mapper接口(告知MyBatis需要掃描的Mapper,綁定SQL映射)
configuration.addMapper(TestMapper.class);
// 6. 構(gòu)建SqlSessionFactory(會(huì)話工廠,線程安全,全局單例)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// 7. 打開SqlSession(會(huì)話對(duì)象,非線程安全,單次請(qǐng)求/事務(wù)獨(dú)占)
SqlSession session = sqlSessionFactory.openSession();
try { 
  // 8. 獲取Mapper代理對(duì)象(MyBatis動(dòng)態(tài)生成,非真實(shí)Mapper實(shí)現(xiàn)類)
  TestMapper mapper = session.getMapper(TestMapper.class);
  // 9. 調(diào)用Mapper方法執(zhí)行查詢(觸發(fā)底層SQL執(zhí)行流程)
  List<Entity> entitys = mapper.selectList(101);
} finally {
  // 10. 關(guān)閉SqlSession(釋放資源,避免連接泄漏)
  session.close();
}

2. 代碼執(zhí)行流程(完整鏈路拆解)

上述代碼中,mapper.selectList(101)是觸發(fā)SQL執(zhí)行的入口,底層通過多組件協(xié)作完成查詢,具體流程可通過以下流程圖及步驟解析理解:

流程步驟詳細(xì)解析:

  1. 獲取Mapper代理對(duì)象:調(diào)用Configuration.getMapper時(shí),MyBatis通過MapperRegistry掃描已注冊(cè)的Mapper接口,利用JDK動(dòng)態(tài)代理生成代理對(duì)象,代理對(duì)象會(huì)攔截所有Mapper方法調(diào)用,將請(qǐng)求轉(zhuǎn)發(fā)至MapperMethod。
  2. 方法執(zhí)行分發(fā):MapperMethod.execute作為核心分發(fā)方法,會(huì)先解析當(dāng)前SQL的類型(SELECT/INSERT/UPDATE/DELETE),再根據(jù)類型調(diào)用SqlSession對(duì)應(yīng)的方法(如查詢調(diào)用selectList),同時(shí)處理參數(shù)映射(將方法參數(shù)轉(zhuǎn)換為SQL可用參數(shù))。
  3. SqlSession層轉(zhuǎn)發(fā):SqlSession作為應(yīng)用與MyBatis底層的橋梁,不直接執(zhí)行SQL,而是將請(qǐng)求委托給Executor(執(zhí)行器),同時(shí)維護(hù)事務(wù)狀態(tài)。
  4. Executor執(zhí)行調(diào)度:Executor是SQL執(zhí)行的核心調(diào)度器,負(fù)責(zé)事務(wù)控制、緩存管理及SQL執(zhí)行協(xié)調(diào)。調(diào)用Executor.query時(shí),會(huì)先檢查一級(jí)緩存,緩存未命中則繼續(xù)向下執(zhí)行,同時(shí)創(chuàng)建Transaction對(duì)象管理事務(wù)。
  5. 創(chuàng)建StatementHandler:通過Configuration.newStatementHandler創(chuàng)建StatementHandler,該組件是JDBC Statement的封裝者,負(fù)責(zé)Statement的創(chuàng)建、參數(shù)設(shè)置、SQL執(zhí)行及結(jié)果處理的統(tǒng)籌。
  6. 插件攔截增強(qiáng):interceptorChain.pluginAll會(huì)遍歷所有注冊(cè)的攔截器,對(duì)StatementHandler進(jìn)行代理增強(qiáng)(如分頁插件、數(shù)據(jù)脫敏插件可在此處攔截,修改SQL或處理參數(shù)/結(jié)果),這是MyBatis擴(kuò)展的核心入口。
  7. 參數(shù)設(shè)置:通過ParameterHandler(參數(shù)處理器)將Mapper方法參數(shù)綁定到JDBC PreparedStatement的占位符上,支持多種參數(shù)類型(基本類型、對(duì)象、集合)及參數(shù)映射規(guī)則(如@Param注解、對(duì)象屬性映射)。
  8. SQL執(zhí)行:StatementHandler.query調(diào)用JDBC Statement的executeQuery方法執(zhí)行SQL,獲取數(shù)據(jù)庫返回的ResultSet。
  9. 結(jié)果處理:ResultSetHandler(結(jié)果處理器)將ResultSet數(shù)據(jù)映射為Java對(duì)象(支持簡單類型、復(fù)雜對(duì)象、集合、嵌套結(jié)果集等),最終返回給上層調(diào)用者。

二、核心對(duì)象關(guān)系及作用詳解

MyBatis SQL執(zhí)行流程依賴多個(gè)核心對(duì)象的協(xié)作,各對(duì)象職責(zé)清晰、相互依賴,構(gòu)成MyBatis的核心架構(gòu),以下結(jié)合對(duì)象功能、實(shí)現(xiàn)類及關(guān)系展開說明:

1. Configuration(全局配置中心)

MyBatis的“大腦”,存儲(chǔ)所有配置信息(全局配置、Mapper映射、插件、類型別名等),同時(shí)作為所有核心對(duì)象(Executor、StatementHandler、ParameterHandler等)的工廠,負(fù)責(zé)對(duì)象的創(chuàng)建與初始化,貫穿SQL執(zhí)行全流程。

2. Executor(執(zhí)行器,SQL執(zhí)行調(diào)度核心)

負(fù)責(zé)SQL執(zhí)行的統(tǒng)籌調(diào)度,同時(shí)處理事務(wù)控制、一級(jí)緩存管理,其實(shí)現(xiàn)類對(duì)應(yīng)不同的執(zhí)行策略,可通過配置指定默認(rèn)執(zhí)行器類型:

  • SimpleExecutor(默認(rèn)執(zhí)行器):簡單執(zhí)行策略,無任何優(yōu)化,每執(zhí)行一條SQL都會(huì)新建一個(gè)Statement對(duì)象,執(zhí)行完成后關(guān)閉,適用于大多數(shù)簡單場(chǎng)景。
  • ReuseExecutor(復(fù)用執(zhí)行器):對(duì)相同SQL(SQL語句+參數(shù)配置一致)的Statement進(jìn)行復(fù)用,避免頻繁創(chuàng)建/關(guān)閉Statement,提升性能,適用于重復(fù)執(zhí)行相同SQL的場(chǎng)景。
  • BatchExecutor(批處理執(zhí)行器):實(shí)現(xiàn)SQL批處理功能,將多條INSERT/UPDATE/DELETE語句批量提交,減少數(shù)據(jù)庫交互次數(shù),大幅提升批處理效率,僅適用于批處理場(chǎng)景。
  • CachingExecutor(緩存執(zhí)行器):若開啟二級(jí)緩存,MyBatis會(huì)自動(dòng)為上述執(zhí)行器包裝一層CachingExecutor,負(fù)責(zé)二級(jí)緩存的管理與查詢,優(yōu)先從二級(jí)緩存獲取數(shù)據(jù)。

3. StatementHandler(Statement封裝者)

直接與JDBC Statement交互,負(fù)責(zé)Statement的創(chuàng)建、參數(shù)設(shè)置、SQL執(zhí)行及結(jié)果回調(diào),是MyBatis封裝JDBC操作的核心組件,默認(rèn)實(shí)現(xiàn)類對(duì)應(yīng)不同的Statement類型:

  • SimpleStatementHandler:處理普通Statement(無占位符的SQL),不支持參數(shù)綁定,適用于靜態(tài)SQL場(chǎng)景。
  • PreparedStatementHandler(默認(rèn)實(shí)現(xiàn)):處理PreparedStatement(帶占位符的SQL),支持參數(shù)綁定、SQL預(yù)編譯,可防止SQL注入,適用于大多數(shù)動(dòng)態(tài)SQL場(chǎng)景。
  • CallableStatementHandler:處理CallableStatement,用于執(zhí)行數(shù)據(jù)庫存儲(chǔ)過程,支持輸入/輸出參數(shù)映射。

補(bǔ)充:RoutingStatementHandler并非直接實(shí)現(xiàn)類,而是一個(gè)路由處理器,會(huì)根據(jù)SQL類型自動(dòng)選擇對(duì)應(yīng)的StatementHandler實(shí)現(xiàn)類。

4. SqlSession(會(huì)話對(duì)象)

應(yīng)用程序與MyBatis底層交互的入口,封裝了Executor、事務(wù)等核心組件,提供增刪改查方法及事務(wù)控制(提交/回滾)。默認(rèn)實(shí)現(xiàn)為DefaultSqlSession,非線程安全,需保證單次請(qǐng)求/事務(wù)對(duì)應(yīng)一個(gè)SqlSession,使用后及時(shí)關(guān)閉。

5. InterceptorChain(攔截器鏈)

MyBatis的擴(kuò)展機(jī)制核心,管理所有注冊(cè)的攔截器(Interceptor),在核心對(duì)象創(chuàng)建時(shí)(如Executor、StatementHandler),通過pluginAll方法為對(duì)象生成代理,允許開發(fā)者在SQL執(zhí)行的關(guān)鍵節(jié)點(diǎn)(參數(shù)設(shè)置、SQL執(zhí)行、結(jié)果處理)插入自定義邏輯,常見應(yīng)用場(chǎng)景包括自動(dòng)分頁、數(shù)據(jù)脫敏、日志打印、分庫分表等。

6. 其他輔助組件

  • ParameterHandler:參數(shù)處理器,負(fù)責(zé)將Mapper方法參數(shù)綁定到Statement占位符,支持類型轉(zhuǎn)換(如Java類型與數(shù)據(jù)庫類型映射)。
  • ResultSetHandler:結(jié)果處理器,負(fù)責(zé)將ResultSet轉(zhuǎn)換為Java對(duì)象,支持復(fù)雜結(jié)果映射(如一對(duì)一、一對(duì)多嵌套映射)。
  • MetaObject:元對(duì)象工具,用于操作Java對(duì)象的屬性(即使屬性為private),支撐參數(shù)綁定與結(jié)果映射的底層反射操作。

三、核心代碼邏輯簡述

以下通過核心類的關(guān)鍵代碼,進(jìn)一步理解MyBatis對(duì)象創(chuàng)建與SQL執(zhí)行的底層邏輯,重點(diǎn)解析Configuration(對(duì)象工廠)與MapperMethod(方法分發(fā))的核心實(shí)現(xiàn)。

1. org.apache.ibatis.session.Configuration(核心對(duì)象工廠)

該類不僅存儲(chǔ)配置,更通過一系列newXXX方法創(chuàng)建核心對(duì)象,同時(shí)集成攔截器鏈,為對(duì)象提供增強(qiáng)能力,關(guān)鍵代碼解析如下:

public class Configuration {
   /**
    * 獲取Mapper代理對(duì)象
    * 核心邏輯:委托MapperRegistry創(chuàng)建代理,將SqlSession傳入代理,便于后續(xù)調(diào)用
    */
   public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
	    return mapperRegistry.getMapper(type, sqlSession);
	}

	/**
	 * 創(chuàng)建元對(duì)象,用于反射操作對(duì)象屬性
	 * 支撐ParameterHandler、ResultSetHandler的底層屬性訪問
	 */
	public MetaObject newMetaObject(Object object) {
	    return MetaObject.forObject(object, objectFactory, objectWrapperFactory);
	}

	/**
	 * 創(chuàng)建ParameterHandler(參數(shù)處理器)
	 * 先通過語言驅(qū)動(dòng)創(chuàng)建默認(rèn)實(shí)現(xiàn),再通過攔截器鏈增強(qiáng)
	 */
	public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
	    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
        // 攔截器增強(qiáng):允許插件修改參數(shù)處理邏輯
	    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
	    return parameterHandler;
	}

	/**
	 * 創(chuàng)建ResultSetHandler(結(jié)果處理器)
	 * 實(shí)例化默認(rèn)實(shí)現(xiàn)DefaultResultSetHandler,再通過攔截器鏈增強(qiáng)
	 */
	public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
	      ResultHandler resultHandler, BoundSql boundSql) {
	    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
        // 攔截器增強(qiáng):允許插件修改結(jié)果處理邏輯(如數(shù)據(jù)脫敏)
	    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
	    return resultSetHandler;
	}

	/**
	 * 創(chuàng)建StatementHandler(Statement封裝者)
	 * 實(shí)例化路由處理器RoutingStatementHandler,再通過攔截器鏈增強(qiáng)
	 */
	public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
	    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
        // 攔截器增強(qiáng):允許插件修改SQL執(zhí)行邏輯(如分頁插件)
	    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
	    return statementHandler;
	}

	/**
	 * 創(chuàng)建Executor(執(zhí)行器)
	 * 根據(jù)執(zhí)行器類型實(shí)例化對(duì)應(yīng)實(shí)現(xiàn),開啟緩存則包裝為CachingExecutor,最后通過攔截器增強(qiáng)
	 */
	public Executor newExecutor(Transaction transaction) {
	    return newExecutor(transaction, defaultExecutorType);
	}

	public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	    executorType = executorType == null ? defaultExecutorType : executorType;
	    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	    Executor executor;
	    if (ExecutorType.BATCH == executorType) {
	      executor = new BatchExecutor(this, transaction);
	    } else if (ExecutorType.REUSE == executorType) {
	      executor = new ReuseExecutor(this, transaction);
	    } else {
	      executor = new SimpleExecutor(this, transaction);
	    }
	    // 若開啟二級(jí)緩存,包裝為CachingExecutor
	    if (cacheEnabled) {
	      executor = new CachingExecutor(executor);
	    }
        // 攔截器增強(qiáng):允許插件修改執(zhí)行器邏輯(如事務(wù)增強(qiáng)、緩存擴(kuò)展)
	    executor = (Executor) interceptorChain.pluginAll(executor);
	    return executor;
	}
}

2. org.apache.ibatis.binding.MapperMethod(方法執(zhí)行分發(fā)器)

該類負(fù)責(zé)解析Mapper方法的SQL類型、參數(shù)信息,將方法調(diào)用分發(fā)至SqlSession對(duì)應(yīng)的方法,是Mapper代理對(duì)象與SqlSession之間的橋梁,核心execute方法邏輯如下(補(bǔ)充完整核心邏輯):

public class MapperMethod {
  // 存儲(chǔ)SQL命令信息(類型、語句ID等)
  private final SqlCommand command;
  // 存儲(chǔ)方法簽名信息(返回值類型、參數(shù)類型等)
  private final MethodSignature method;

  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    this.command = new SqlCommand(config, mapperInterface, method);
    this.method = new MethodSignature(config, mapperInterface, method);
  }

  // 核心方法:處理增刪改查方法執(zhí)行,分發(fā)至SqlSession
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    // 根據(jù)SQL命令類型分發(fā)執(zhí)行
    switch (command.getType()) {
      case INSERT: {
        // 處理參數(shù)映射,將args轉(zhuǎn)換為SQL參數(shù)
        Object param = method.convertArgsToSqlCommandParam(args);
        // 調(diào)用SqlSession.insert,返回影響行數(shù)
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        // 無返回值且有ResultHandler參數(shù)(回調(diào)處理結(jié)果)
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        }
        // 返回列表/數(shù)組
        else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        }
        // 返回Map
        else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        }
        // 返回Cursor(游標(biāo),適用于大量數(shù)據(jù)流式查詢)
        else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        }
        // 返回單個(gè)對(duì)象
        else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    // 處理返回值為null且方法返回類型為基本類型的情況(拋出異常)
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

  // 執(zhí)行查詢列表邏輯
  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    // 若方法有RowBounds參數(shù)(分頁參數(shù)),調(diào)用帶分頁的selectList
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.selectList(command.getName(), param, rowBounds);
    } else {
      // 無分頁,調(diào)用普通selectList
      result = sqlSession.selectList(command.getName(), param);
    }
    // 若返回值需要轉(zhuǎn)換為數(shù)組,進(jìn)行類型轉(zhuǎn)換
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      return method.convertResultToList(result);
    }
    return result;
  }

  // 其他輔助方法(executeWithResultHandler、executeForMap等)省略...

  // 處理影響行數(shù)返回結(jié)果(適配boolean/int等返回類型)
  private Object rowCountResult(int rowCount) {
    final Object result;
    if (method.returnsVoid()) {
      result = null;
    } else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
      result = rowCount;
    } else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
      result = (long) rowCount;
    } else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
      result = rowCount > 0;
    } else {
      throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
    }
    return result;
  }
}

四、總結(jié)

MyBatis SQL執(zhí)行流程本質(zhì)是“分層協(xié)作+接口抽象”的設(shè)計(jì)模式:通過Configuration統(tǒng)一管理配置與對(duì)象創(chuàng)建,SqlSession提供上層入口,Executor調(diào)度核心流程,StatementHandler封裝JDBC操作,配合ParameterHandler、ResultSetHandler完成參數(shù)與結(jié)果的映射,最終通過攔截器鏈提供靈活擴(kuò)展能力。

理解這一流程,既能幫助開發(fā)者快速定位SQL執(zhí)行過程中的問題(如參數(shù)綁定錯(cuò)誤、結(jié)果映射異常、插件攔截失效等),也能為自定義擴(kuò)展(如開發(fā)插件、優(yōu)化執(zhí)行邏輯)提供底層支撐,真正掌握MyBatis的核心原理。

到此這篇關(guān)于MyBatis SQL執(zhí)行流程的使用詳解的文章就介紹到這了,更多相關(guān)MyBatis SQL執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

阿克| 龙泉市| 皮山县| 柘城县| 通许县| 尉氏县| 名山县| 兴化市| 彩票| 长垣县| 莱西市| 易门县| 巴彦淖尔市| 河间市| 慈利县| 门源| 昆山市| 乌拉特前旗| 台山市| 江孜县| 竹溪县| 岳阳县| 黔西县| 广元市| 千阳县| 蒙自县| 华宁县| 苍梧县| 东莞市| 樟树市| 社会| 陆河县| 胶州市| 长治县| 都兰县| 扬州市| 连城县| 榆社县| 武汉市| 天长市| 麻阳|