日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mybatis源码阅读(四):核心接口4.1——StatementHandler

發(fā)布時(shí)間:2025/3/11 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis源码阅读(四):核心接口4.1——StatementHandler 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

*************************************優(yōu)雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內(nèi)容對(duì)你覺得有用,并想獲取更多的賺錢方式和免費(fèi)的技術(shù)教程

請(qǐng)關(guān)注微信公眾號(hào):HB荷包

一個(gè)能讓你學(xué)習(xí)技術(shù)和賺錢方法的公眾號(hào),持續(xù)更新
*************************************優(yōu)雅的分割線 **********************************
前言

難得復(fù)工了,公司百業(yè)待興,有一大堆接口需要對(duì)接,忙的不行?;剡^神來發(fā)現(xiàn)自己快一個(gè)月沒寫博客了,趕緊抽時(shí)間寫一寫,不能斷更。

截止上一篇博客,我們已經(jīng)把結(jié)果集映射的內(nèi)容介紹完畢,接下來就是對(duì)Mybatis中的核心接口進(jìn)行介紹,通過介紹這些核心接口,使讀者們更深刻地理解Mybatis的運(yùn)行機(jī)制以及原理。
StatementHandler

StatementHandler接口是Mybatis的核心接口之一,它完成了Mybatis中最核心的工作,也是Executor接口實(shí)現(xiàn)的基礎(chǔ)。

StatementHandler接口中功能有很多,如創(chuàng)建Statement對(duì)象、執(zhí)行SQL語句、批量執(zhí)行SQL語句等。StatementHandler接口定義如下。

/**

  • Mybatis核心接口之一,完成了Mybatis中最核心的工作,也是Executor接口實(shí)現(xiàn)的基礎(chǔ)。

  • @author Clinton Begin
    */
    public interface StatementHandler {

    /**

    • 從數(shù)據(jù)庫連接中獲取一個(gè)Statement
    • @param connection
    • @param transactionTimeout
    • @return
    • @throws SQLException
      */
      Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

    /**

    • 綁定statement執(zhí)行時(shí)所需的實(shí)參
    • @param statement
    • @throws SQLException
      */
      void parameterize(Statement statement)
      throws SQLException;

    /**

    • 批量執(zhí)行sql語句
    • @param statement
    • @throws SQLException
      */
      void batch(Statement statement)
      throws SQLException;

    /**

    • 執(zhí)行 update/insert/delete語句
    • @param statement
    • @return
    • @throws SQLException
      */
      int update(Statement statement)
      throws SQLException;

    /**

    • 執(zhí)行select語句
    • @param statement
    • @param resultHandler
    • @param
    • @return
    • @throws SQLException
      */
      List query(Statement statement, ResultHandler resultHandler)
      throws SQLException;

    /**

    • 查詢游標(biāo)
    • @param statement
    • @param
    • @return
    • @throws SQLException
      */
      Cursor queryCursor(Statement statement)
      throws SQLException;

    /**

    • 獲取BoundSql
    • @return
      */
      BoundSql getBoundSql();

    /**

    • 獲取ParameterHandler
    • @return
      */
      ParameterHandler getParameterHandler();

}

該接口的繼承關(guān)系如下。其中,CallableStatementHandler用于調(diào)用存儲(chǔ)過程,而mysql的存儲(chǔ)過程在大多數(shù)公司都很少使用甚至禁止使用,這里就不對(duì)其進(jìn)行介紹了,有興趣的朋友可以自己參考源碼閱讀

RoutingStatementHandler

RoutingStatementHandler使用策略模式,根據(jù)MappedStatement中指定的statementType字段,創(chuàng)建對(duì)應(yīng)的StatementHandler接口實(shí)現(xiàn)。由于其這種思路,還有人認(rèn)為這是個(gè)路由。RoutingStatementHandler核心代碼如下。

public class RoutingStatementHandler implements StatementHandler {

/*** 底層封裝的真正的StatementHandler對(duì)象* 這里的delegate在寫框架的過程中使用較多*/ private final StatementHandler delegate;public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// RoutingStatementHandler的主要功能是根據(jù)MappedStatement的配置,生成對(duì)應(yīng)的StatementHandler對(duì)象switch (ms.getStatementType()) {case STATEMENT:delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case PREPARED:delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case CALLABLE:delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;default:throw new ExecutorException("Unknown statement type: " + ms.getStatementType());}}

}

BaseStatementHandler

BaseStatementHandler是一個(gè)抽象類,實(shí)現(xiàn)了StatementHandler接口。它只提供了一些參數(shù)綁定相關(guān)的方法,對(duì)數(shù)據(jù)庫不進(jìn)行任何操作。該類的字段如下。

protected final Configuration configuration; protected final ObjectFactory objectFactory; protected final TypeHandlerRegistry typeHandlerRegistry;/*** 記錄結(jié)果集映射對(duì)象*/ protected final ResultSetHandler resultSetHandler;/*** 記錄使用的參數(shù)處理器對(duì)象。ParameterHandler的主要功能是為SQL綁定實(shí)參* 也就是使用傳入的實(shí)參替換SQL語句中的 ? 占位符*/ protected final ParameterHandler parameterHandler;protected final Executor executor;/*** 記錄SQL語句對(duì)應(yīng)的MappedStatement*/ protected final MappedStatement mappedStatement;/*** 記錄用戶設(shè)置的offset和limit,用于在結(jié)果集中定位映射的起始位置和結(jié)束位置*/ protected final RowBounds rowBounds;protected BoundSql boundSql;

在BaseStatementHandler的構(gòu)造方法中,除對(duì)上面的字段進(jìn)行初始化之外,還會(huì)調(diào)用KeyGenerator.processBefore()方法初始化SQL的主鍵,具體實(shí)現(xiàn)如下。

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {this.configuration = mappedStatement.getConfiguration();this.executor = executor;this.mappedStatement = mappedStatement;this.rowBounds = rowBounds;this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.objectFactory = configuration.getObjectFactory();if (boundSql == null) {// 調(diào)用KeyGenerator.processBefore 方法獲取主鍵generateKeys(parameterObject);boundSql = mappedStatement.getBoundSql(parameterObject);}this.boundSql = boundSql;this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql); }protected void generateKeys(Object parameter) {KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();ErrorContext.instance().store();keyGenerator.processBefore(executor, mappedStatement, null, parameter);ErrorContext.instance().recall(); }

BaseStatementHandler實(shí)現(xiàn)了StatementHandler的prepare方法,該方法用來初始化Statement對(duì)象,然后為其分配超時(shí)時(shí)間等屬性。其中,初始化StatementHandler的方法是個(gè)抽象方法instantiateStatement,是一個(gè)抽象方法,需要由子類去實(shí)現(xiàn),代碼如下。

@Override public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement = null;try {// 初始化statement對(duì)象,交給子類去實(shí)現(xiàn)statement = instantiateStatement(connection);// 設(shè)置超時(shí)時(shí)間setStatementTimeout(statement, transactionTimeout);setFetchSize(statement);return statement;} catch (SQLException e) {closeStatement(statement);throw e;} catch (Exception e) {closeStatement(statement);throw new ExecutorException("Error preparing statement. Cause: " + e, e);} }

BaseStatementHandler依賴兩個(gè)重要的組件,分別是ParameterHandler和ResultSetHandler。后者在前面的文章中已經(jīng)介紹,不在重復(fù)。
ParameterHandler

通過前面介紹動(dòng)態(tài)SQL可知,在BoundSql中記錄的SQL語句可能包含?占位符,每個(gè)?占位符都對(duì)應(yīng)了BoundSql.parameterMapings集合中的一個(gè)元素。在ParameterHandler中只定義了一個(gè)setParameter方法,該方法用于為SQL語句綁定實(shí)參。ParameterHandler接口只有唯一一個(gè)實(shí)現(xiàn)類 DefaultParameterHandler,核心字段如下。

/*** 管理Mybatis中的全部TypeHandler對(duì)象*/ private final TypeHandlerRegistry typeHandlerRegistry;/*** SQL節(jié)點(diǎn)*/ private final MappedStatement mappedStatement;/*** 用戶傳入的實(shí)參對(duì)象*/ private final Object parameterObject; private final BoundSql boundSql; private final Configuration configuration;

DefaultParameterHandler的setParameters方法中會(huì)遍歷parameterMappings集合中記錄的ParameterMapping對(duì)象,并根據(jù)其中記錄的參數(shù)名稱找到對(duì)應(yīng)的實(shí)參,再與SQL綁定。setParameters方法如下。

/*** 設(shè)置參數(shù)* @param ps*/ @Override public void setParameters(PreparedStatement ps) {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());// 取出參數(shù)映射列表List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {// 遍歷參數(shù)for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);// OUT是存儲(chǔ)過程中的輸出參數(shù),這里需要過濾掉這些參數(shù)if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;// 獲取參數(shù)名稱String propertyName = parameterMapping.getProperty();// 獲取對(duì)應(yīng)的實(shí)參值if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {// 實(shí)參可以直接通過TypeHandler轉(zhuǎn)換成jdbcTypevalue = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);value = metaObject.getValue(propertyName);}// 獲取parameterMapping中設(shè)置的TypeHandler對(duì)象TypeHandler typeHandler = parameterMapping.getTypeHandler();JdbcType jdbcType = parameterMapping.getJdbcType();if (value == null && jdbcType == null) {jdbcType = configuration.getJdbcTypeForNull();}try {// 為語句綁定實(shí)參typeHandler.setParameter(ps, i + 1, value, jdbcType);} catch (TypeException | SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}} }

對(duì)SQL語句綁定完實(shí)參后,就可以調(diào)用Statement對(duì)象的execute方法執(zhí)行SQL了。
SimpleStatementHandler

SimpleStatementHandler是BaseStatementHandler的子類,底層使用了Statement對(duì)象完成數(shù)據(jù)庫的相關(guān)操作,所以SQL語句中不能存在占位符,因此parameterize方法是空實(shí)現(xiàn)。

SimpleStatementHandler的instantiateStatement方法直接通過JDBC Connection創(chuàng)建Statement,代碼如下。

/*** 創(chuàng)建statement對(duì)象* @param connection* @return* @throws SQLException*/ @Override protected Statement instantiateStatement(Connection connection) throws SQLException {if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {return connection.createStatement();} else {return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);} }

query方法完成了數(shù)據(jù)庫查詢的操作,并通過ResultSetHandler將結(jié)果集映射成結(jié)果對(duì)象,代碼如下。

@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.handleResultSets(statement); }

update方法負(fù)責(zé)執(zhí)行insert、update、delete的SQL語句,并根據(jù)配置的KeyGenerator獲取數(shù)據(jù)庫生成的主鍵,具體實(shí)現(xiàn)如下。

/*** 負(fù)責(zé)執(zhí)行insert、update、delete語句* @param statement* @return* @throws SQLException*/ @Override public int update(Statement statement) throws SQLException {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();int rows;if (keyGenerator instanceof Jdbc3KeyGenerator) {statement.execute(sql, Statement.RETURN_GENERATED_KEYS);rows = statement.getUpdateCount();keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else if (keyGenerator instanceof SelectKeyGenerator) {statement.execute(sql);rows = statement.getUpdateCount();keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else {statement.execute(sql);rows = statement.getUpdateCount();}return rows; }

PreparedStatementHandler

該類底層依賴于PrepareStatement對(duì)象完成數(shù)據(jù)庫的操作,instantiateStatement方法直接調(diào)用Connection的prepareStatement方法創(chuàng)建PrepareStatement對(duì)象,代碼如下。

/*** 直接調(diào)用Connection的prepareStatement方法創(chuàng)建PrepareStatement對(duì)象* @param connection* @return* @throws SQLException*/ @Override protected Statement instantiateStatement(Connection connection) throws SQLException {// 獲取待執(zhí)行的sqlString sql = boundSql.getSql();// 根據(jù)keyGenerator的值創(chuàng)建PrepareStatement對(duì)象if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {String[] keyColumnNames = mappedStatement.getKeyColumns();if (keyColumnNames == null) {// 返回?cái)?shù)據(jù)庫生成的主鍵return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);} else {// 在insert語句執(zhí)行完成之后,將keyColumnNames指定的列返回return connection.prepareStatement(sql, keyColumnNames);}} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {// 設(shè)置結(jié)果集是否可以滾動(dòng)以及游標(biāo)是否可以上下移動(dòng),設(shè)置結(jié)果集是否可更新return connection.prepareStatement(sql);} else {// 創(chuàng)建普通的PrepareStatement對(duì)象return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);} }

PrepareStatement的其他方法的實(shí)現(xiàn)與SimpleStatementHandler對(duì)應(yīng)的方法實(shí)現(xiàn)類型,這里就不贅述了。

*************************************優(yōu)雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內(nèi)容對(duì)你覺得有用,并想獲取更多的賺錢方式和免費(fèi)的技術(shù)教程

請(qǐng)關(guān)注微信公眾號(hào):HB荷包

一個(gè)能讓你學(xué)習(xí)技術(shù)和賺錢方法的公眾號(hào),持續(xù)更新
*************************************優(yōu)雅的分割線 **********************************

總結(jié)

以上是生活随笔為你收集整理的Mybatis源码阅读(四):核心接口4.1——StatementHandler的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。