国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

mybatis sqlSession的運行過程

BoYang / 2028人閱讀

摘要:在找那個可以根據(jù)中的屬性,確定類的全限定類名。并且根據(jù)節(jié)點所對應(yīng)的,找到所要執(zhí)行的方法。因為他根據(jù)的是類名方法名進行唯一確定節(jié)點的。

當(dāng)我們使用sqlSession.getMapper(xx.class)方法時,Mybatis其實是使用了jdk的動態(tài)代理技術(shù),在MapperProxyFactory中生成對應(yīng)的Mapper對象。

這段是MappedProxyFactory中的一段代碼

protected T newInstance(MapperProxy mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

其中mapperProxy對應(yīng)的是MapperProxy,該類實現(xiàn)了InvocationHanlder接口。
正如我們所知,JDK的動態(tài)代理是根據(jù)接口來生成代理對象的。在Mybatis找那個可以根據(jù)Mapper.xml中的namespace屬性,確定類的全限定類名。并且根據(jù)節(jié)點(insert | select | update | delete)所對應(yīng)的ID,找到所要執(zhí)行的方法。也因此,Mybatis中的方法是不能重載的。因為他根據(jù)的是類名+方法名進行唯一確定MapperStatement(節(jié)點)的。

這個就是MapperStatement所封裝的一些信息了

再接著,當(dāng)我們調(diào)用Mapper對應(yīng)的方法時,此時,會交給代理對象進行處理。
MapperProxy#的invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(Object.class.equals(method.getDeclaringClass())) {
            try {
                return method.invoke(this, args);
            } catch (Throwable var5) {
                throw ExceptionUtil.unwrapThrowable(var5);
            }
        } else {
        //執(zhí)行到這一步,如果方法是第一次調(diào)用,那么會創(chuàng)建對象,如果不是則使用緩存
        //需要注意的是調(diào)用的cacheMapperMethod方法,其實就是用一個Map進行緩存                        
            MapperMethod mapperMethod = this.cachedMapperMethod(method);
            return mapperMethod.execute(this.sqlSession, args);
        }
    }

緊接著,調(diào)用了MapperMethod#execute(this,sqlSession,args);
這個方法比較簡單,就是根據(jù)節(jié)點的類型,進行相應(yīng)的處理。比如節(jié)點是insert 那就走到insert的邏輯,其他類似了。。。

本人的節(jié)點類型是select,方法返回值是list,所以代碼執(zhí)行了這個方法

private  Object executeForMany(SqlSession sqlSession, Object[] args) {
        Object param = this.method.convertArgsToSqlCommandParam(args);
        List result;
        if(this.method.hasRowBounds()) {
            RowBounds rowBounds = this.method.extractRowBounds(args);
            result = sqlSession.selectList(this.command.getName(), param, rowBounds);
        } else {
            result = sqlSession.selectList(this.command.getName(), param);
        }

        return !this.method.getReturnType().isAssignableFrom(result.getClass())?(this.method.getReturnType().isArray()?this.convertToArray(result):this.convertToDeclaredCollection(sqlSession.getConfiguration(), result)):result;
    }

這里看到方法還執(zhí)行了convertArgsToSqlCommandParam(args)方法,這個方法返回的對象值如下。其實說白了,就是對我們傳進去參數(shù)的封裝。需要注意到,這邊其實是個Map對象,因為我的Mapper接口的方法是使用@Param注解的形式的。如果你傳進去的是個POJO或者Map,那么這邊就是POJO或者Map,如果是基本數(shù)據(jù)類型(單個值),那么會被轉(zhuǎn)換成包裝數(shù)據(jù)類型

中間的有些步驟就省略了。接下里的話,會將于需要執(zhí)行的對象的方法,sql,sql參數(shù)創(chuàng)建一個緩存key
.

然后調(diào)用CacheExecutor#query,根據(jù)key查詢有沒有緩存,如果有緩存,直接從緩存中拿,如果沒有,則繼續(xù)執(zhí)行。

期間會調(diào)用一個比較重要的方法 BaseExecutor#queryFromDatabase

private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);  //key其實就是之前提到過的CacheKey,value只是充當(dāng)一個占位。。

        List list;
        try {
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);  //代碼執(zhí)行到這里。。。
        } finally {
            this.localCache.removeObject(key);
        }

        this.localCache.putObject(key, list);
        if(ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

下面就是比較關(guān)鍵的地方了
代碼執(zhí)行了simpleExecutor#doQuery

 public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;

        List var9;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
            stmt = this.prepareStatement(handler, ms.getStatementLog());
            var9 = handler.query(stmt, resultHandler);
        } finally {
            this.closeStatement(stmt);
        }

        return var9;
    }

從這邊可以看出在Executor內(nèi)創(chuàng)建了StatementHandler,并對參數(shù)進行了預(yù)處理,而調(diào)用的handler.query()方法后,var9的值,就是我們所要查詢的結(jié)果了。

值得一提的是StatementHandler有4個默認(rèn)的實現(xiàn)類:
RoutingStatementHandler:這是一個封裝類,不提供具體的實現(xiàn),根據(jù)Executor的類型,創(chuàng)建不同的類型的StatementHandler
SimpleStatementHandler:這個類對應(yīng)于JDBC的Statement對象,用于沒有預(yù)編譯參數(shù)的SQL的運行
PreparedStatementHandler:用于預(yù)編譯參數(shù)SQL的運行
CallableStatementHandler:用于存儲過程的調(diào)度

在newStatementHandler方法中,我們也可以看到是創(chuàng)建了RoutingStatementHandler對象,會根據(jù)具體的Executor類型,創(chuàng)建不同的StatementHandler。而這個具體的StatementHandler被存儲在了RoutingStatementHandler的delegate屬性中

先看configuration#newStatementHandler。注意到這邊有個interceptorChain.pluginAll 這邊就是用來執(zhí)行插件的。

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);
        StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll(statementHandler);
        return statementHandler;
}

這個是所創(chuàng)建的StatementHandler所包含的信息,可以看到包含了很多東西

再來看simpleExecutor#prepareStatement

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
        Connection connection = this.getConnection(statementLog); // 在此處獲取了數(shù)據(jù)的連接,此對象是個包裝對象,包裝了JDBC的Connection
        Statement stmt = handler.prepare(connection);  // 這邊是進行一些預(yù)處理
        handler.parameterize(stmt);  
        return stmt;
    }

這邊的調(diào)用的parameterize的方法就是對參數(shù)進行預(yù)處理了。其實就是遍歷parameterMappings集合,然后從里面取出參數(shù)的屬性,對參數(shù)進行處理,這個就是這個方法的邏輯。(注:parameterMappings 集合中存放的是傳遞進來的參數(shù)的屬性)

當(dāng)查詢到結(jié)果到時候,會調(diào)用DefaultResultSetHandler對結(jié)果進行包裝。并且查詢完結(jié)果后,會將結(jié)果放到緩存中去

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67751.html

相關(guān)文章

  • 【深入淺出MyBatis筆記】MyBatis解析和運行原理

    摘要:的解析和運行原理構(gòu)建過程提供創(chuàng)建的核心接口。在構(gòu)造器初始化時會根據(jù)和的方法解析為命令。數(shù)據(jù)庫會話器定義了一個對象的適配器,它是一個接口對象,構(gòu)造器根據(jù)配置來適配對應(yīng)的對象。它的作用是給實現(xiàn)類對象的使用提供一個統(tǒng)一簡易的使用適配器。 MyBatis的解析和運行原理 構(gòu)建SqlSessionFactory過程 SqlSessionFactory提供創(chuàng)建MyBatis的核心接口SqlSess...

    bitkylin 評論0 收藏0
  • MyBatis原理概括

    摘要:避免了幾乎所有的代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集。這個對象主要是獲取方法對應(yīng)的命令和執(zhí)行相應(yīng)操作等的處理,具體細(xì)節(jié)同學(xué)們可以抽空研究。所以這里的方法主要使用了和對象幫助我們處理語句集和參數(shù)的處理。 博文目標(biāo):希望大家看了這篇博文后,對Mybatis整體運行過程有一個清晰的認(rèn)識和把握。 1.什么是 MyBatis ? MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程...

    mikasa 評論0 收藏0
  • Mybatis系列】從源碼角度深度理解Mybatis緩存特性

    摘要:一級緩存介紹及相關(guān)配置。在這個章節(jié),我們學(xué)習(xí)如何使用的一級緩存。一級緩存實驗配置完畢后,通過實驗的方式了解一級緩存的效果。源碼分析了解具體的工作流程后,我們隊查詢相關(guān)的核心類和一級緩存的源碼進行走讀。 我,后端Java工程師,現(xiàn)在美團點評工作。愛健身,愛技術(shù),也喜歡寫點文字。個人網(wǎng)站: http://kailuncen.me公眾號: KailunTalk (凱倫說) 前言 本文主要涉及...

    Ku_Andrew 評論0 收藏0
  • Mybatis系列】從源碼角度深度理解Mybatis緩存特性

    摘要:一級緩存介紹及相關(guān)配置。在這個章節(jié),我們學(xué)習(xí)如何使用的一級緩存。一級緩存實驗配置完畢后,通過實驗的方式了解一級緩存的效果。源碼分析了解具體的工作流程后,我們隊查詢相關(guān)的核心類和一級緩存的源碼進行走讀。 我,后端Java工程師,現(xiàn)在美團點評工作。愛健身,愛技術(shù),也喜歡寫點文字。個人網(wǎng)站: http://kailuncen.me公眾號: KailunTalk (凱倫說) 前言 本文主要涉及...

    young.li 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<