1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官問:Mybatis Plus 是如何實(shí)現(xiàn)動(dòng)態(tài) SQL 語句的?原理你懂嗎?

        共 6351字,需瀏覽 13分鐘

         ·

        2021-12-01 01:19

        程序員的成長之路
        互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
        關(guān)注


        閱讀本文大概需要 4?分鐘。

        來源:juejin.cn/post/6883081187103866894


        Mybatis-Plus(簡稱MP)是一個(gè) Mybatis 的增強(qiáng)工具,那么它是怎么增強(qiáng)的呢?其實(shí)就是它已經(jīng)封裝好了一些crud方法,開發(fā)就不需要再寫xml了,直接調(diào)用這些方法就行,就類似于JPA。

        那么這篇文章就來閱讀以下MP的具體實(shí)現(xiàn),看看是怎樣實(shí)現(xiàn)這些增強(qiáng)的。


        # 入口類:MybatisSqlSessionFactoryBuilder


        通過在入口類 MybatisSqlSessionFactoryBuilder#build方法中, 在應(yīng)用啟動(dòng)時(shí), 將mybatis plus(簡稱MP)自定義的動(dòng)態(tài)配置xml文件注入到Mybatis中。

        public?class?MybatisSqlSessionFactoryBuilder?extends?SqlSessionFactoryBuilder?{????public?SqlSessionFactory?build(Configuration?configuration)?{????????????//?...?省略若干行????????????if?(globalConfig.isEnableSqlRunner())?{????????????????new?SqlRunnerInjector().inject(configuration);????????????}????????????//?...?省略若干行????????????return?sqlSessionFactory;????????}}

        這里涉及到2個(gè)MP2個(gè)功能類

        • 擴(kuò)展繼承自Mybatis的MybatisConfiguration類: MP動(dòng)態(tài)腳本構(gòu)建,注冊,及其它邏輯判斷。

        • SqlRunnerInjector: MP默認(rèn)插入一些動(dòng)態(tài)方法的xml 腳本方法。


        # MybatisConfiguration類


        這里我們重點(diǎn)剖析MybatisConfiguration類,在MybatisConfiguration中,MP初始化了其自身的MybatisMapperRegistry,而MybatisMapperRegistry是MP加載自定義的SQL方法的注冊器。

        MybatisConfiguration中很多方法是使用MybatisMapperRegistry進(jìn)行重寫實(shí)現(xiàn)。

        其中有3個(gè)重載方法addMapper實(shí)現(xiàn)了注冊MP動(dòng)態(tài)腳本的功能。

        public?class?MybatisConfiguration?extends?Configuration?{????/**?????*?Mapper?注冊?????*/????protected?final?MybatisMapperRegistry?mybatisMapperRegistry?=?new?MybatisMapperRegistry(this); // ....
        ????/**?????*?初始化調(diào)用?????*/????public?MybatisConfiguration()?{????????super();????????this.mapUnderscoreToCamelCase?=?true;????????languageRegistry.setDefaultDriverClass(MybatisXMLLanguageDriver.class); }????/**?????* MybatisPlus 加載 SQL 順序:?????*?

        ?1、加載?XML中的?SQL?

        ?????*?

        ?2、加載?SqlProvider?中的?SQL?

        ?????*?

        ?3、XmlSql?與?SqlProvider不能包含相同的?SQL?

        ?????*?

        調(diào)整后的 SQL優(yōu)先級(jí):XmlSql > sqlProvider > CurdSql

        ?????*/????@Override????public?void?addMappedStatement(MappedStatement?ms)?{????????//?... }????//?...?省略若干行????/**?????*?使用自己的?MybatisMapperRegistry?????*/????@Override????public??void?addMapper(Class?type)?{????????mybatisMapperRegistry.addMapper(type);????}????//?....?省略若干行}

        在MybatisMapperRegistry中,MP將mybatis的MapperAnnotationBuilder替換為MP自己的MybatisMapperAnnotationBuilder

        public?class?MybatisMapperRegistry?extends?MapperRegistry?{????@Override????public??void?addMapper(Class?type)?{????????//?...?省略若干行????????MybatisMapperAnnotationBuilder?parser?=?new?MybatisMapperAnnotationBuilder(config,?type);????????parser.parse();????????//?...?省略若干行????}}

        在MybatisMapperRegistry類的addMapper方法中,真正進(jìn)入到MP的核心類MybatisMapperAnnotationBuilder,MybatisMapperAnnotationBuilder這個(gè)類是MP實(shí)現(xiàn)動(dòng)態(tài)腳本的關(guān)鍵類。

        # MybatisMapperAnnotationBuilder動(dòng)態(tài)構(gòu)造


        在MP的核心類MybatisMapperAnnotationBuilder的parser方法中,MP逐一遍歷要加載的Mapper類,加載的方法包括下面幾個(gè)

        public?class?MybatisMapperAnnotationBuilder?extends?MapperAnnotationBuilder?{????@Overrde????public?void?parse()?{????????//...?省略若干行????????for?(Method?method?:?type.getMethods())?{????????????/**?for循環(huán)代碼,?MP判斷method方法是否是@Select?@Insert等mybatis注解方法**/????????????parseStatement(method);????????????InterceptorIgnoreHelper.initSqlParserInfoCache(cache,?mapperName,?method);????????????SqlParserHelper.initSqlParserInfoCache(mapperName,?method);????????}????????/**?這2行代碼,?MP注入默認(rèn)的方法列表**/????????if?(GlobalConfigUtils.isSupperMapperChildren(configuration,?type))?{????????????GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant,?type);????????}????????//...?省略若干行 }
        ????@Override????public?void?inspectInject(MapperBuilderAssistant?builderAssistant,?Class?mapperClass)?{????????Class?modelClass?=?extractModelClass(mapperClass);????????//...?省略若干行????????List?methodList?=?this.getMethodList(mapperClass);????????TableInfo?tableInfo?=?TableInfoHelper.initTableInfo(builderAssistant,?modelClass);????????//?循環(huán)注入自定義方法????????methodList.forEach(m?->?m.inject(builderAssistant,?mapperClass,?modelClass,?tableInfo));????????mapperRegistryCache.add(className);????}}public class DefaultSqlInjector extends AbstractSqlInjector {
        ????@Override????public?List?getMethodList(Class?mapperClass)?{????????return?Stream.of(????????????new?Insert(),????????????//...?省略若干行????????????new?SelectPage()????????).collect(toList());????}}


        在MybatisMapperAnnotationBuilder中,MP真正將框架自定義的動(dòng)態(tài)SQL語句注冊到Mybatis引擎中。而AbstractMethod則履行了具體方法的SQL語句構(gòu)造。

        # 具體的AbstractMethod實(shí)例類,構(gòu)造具體的方法SQL語句

        以 SelectById 這個(gè)類為例說明下

        /**?*?根據(jù)ID?查詢一條數(shù)據(jù)?*/public?class?SelectById?extends?AbstractMethod?{????@Override????public?MappedStatement?injectMappedStatement(Class?mapperClass,?Class?modelClass,?TableInfo?tableInfo)?{????????/**?定義?mybatis?xml?method?id,?對應(yīng)??**/ SqlMethod sqlMethod = SqlMethod.SELECT_BY_ID;????????/**?構(gòu)造id對應(yīng)的具體xml片段?**/????????SqlSource?sqlSource?=?new?RawSqlSource(configuration,?String.format(sqlMethod.getSql(),????????????sqlSelectColumns(tableInfo,?false),????????????tableInfo.getTableName(),?tableInfo.getKeyColumn(),?tableInfo.getKeyProperty(),????????????tableInfo.getLogicDeleteSql(true,?true)),?Object.class);????????/**?將xml?method方法添加到mybatis的MappedStatement中?**/????????return?this.addSelectMappedStatementForTable(mapperClass,?getMethod(sqlMethod),?sqlSource,?tableInfo);????}}

        至此,MP完成了在啟動(dòng)時(shí)加載自定義的方法xml配置的過程,后面的就是mybatis ${變量} #{變量}的動(dòng)態(tài)替換和預(yù)編譯,已經(jīng)進(jìn)入mybatis自有功能。

        # 總結(jié)一下


        MP總共改寫和替換了mybatis的十多個(gè)類,主要如下圖所示:



        總體上來說,MP實(shí)現(xiàn)mybatis的增強(qiáng),手段略顯繁瑣和不夠直觀,其實(shí)根據(jù)MybatisMapperAnnotationBuilder構(gòu)造出自定義方法的xml文件,將其轉(zhuǎn)換為mybatis的Resource資源,可以只繼承重寫一個(gè)Mybatis類:SqlSessionFactoryBean 比如如下:

        public class YourSqlSessionFactoryBean extends SqlSessionFactoryBean implements ApplicationContextAware {
        ????private?Resource[]?mapperLocations;????????@Override????public?void?setMapperLocations(Resource...?mapperLocations)?{????????super.setMapperLocations(mapperLocations);????????/**?存使用mybatis原生定義的mapper?xml文件路徑**/????????this.mapperLocations?=?mapperLocations; }
        ????/**?????*?{@inheritDoc}?????*/????@Override????public?void?afterPropertiesSet()?throws?Exception?{????????ConfigurableListableBeanFactory?beanFactory?=?getBeanFactory();????????/**?只需要通過將自定義的方法構(gòu)造成xml?resource和原生定義的Resource一起注入到mybatis中即可,?這樣就可以實(shí)現(xiàn)MP的自定義動(dòng)態(tài)SQL和原生SQL的共生關(guān)系**/????????this.setMapperLocations(InjectMapper.getMapperResource(this.dbType,?beanFactory,?this.mapperLocations));????????super.afterPropertiesSet();????}}

        在這篇文章中,簡單介紹了MP實(shí)現(xiàn)動(dòng)態(tài)語句的實(shí)現(xiàn)過程,并且給出一個(gè)可能的更便捷方法。
        推薦閱讀:
        妙用Java 8中的 Function接口 消滅if...else(非常新穎的寫法)
        大文件上傳服務(wù)器、支持超大文件HTTP斷點(diǎn)續(xù)傳實(shí)踐總結(jié)

        最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)個(gè)「在看」,點(diǎn)擊上方小卡片,進(jìn)入公眾號(hào)后回復(fù)「面試題」領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        朕已閱?

        瀏覽 68
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            色婷婷播放| 揉捏花蒂抽打虐乳 | 色视频在线播放 | 丝袜高跟国产成人精品一区 | 成人拍拍视频 | 欧美熟妇性爱视频 | 中文字幕在线观看免费高清完整版在线 | 公主被太监h各种姿势调教 | 国产做爱xxxⅹ性视频播放量 | 美女黄色18 |