<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 11271字,需瀏覽 23分鐘

           ·

          2021-12-18 22:28

          相關閱讀:杭州程序員從互聯(lián)網(wǎng)跳央企,曬一天工作和收入,網(wǎng)友:待一年就廢

          來源:juejin.cn/post/6883081187103866894

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

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



          入口類:MybatisSqlSessionFactoryBuilder


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


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


          這里涉及到2個MP2個功能類


          MybatisConfiguration類


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

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

          其中有3個重載方法addMapper實現(xiàn)了注冊MP動態(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 順序:     * <p> 1、加載 XML中的 SQL </p>     * <p> 2、加載 SqlProvider 中的 SQL </p>     * <p> 3、XmlSql 與 SqlProvider不能包含相同的 SQL </p>     * <p>調(diào)整后的 SQL優(yōu)先級:XmlSql > sqlProvider > CurdSql </p>     */    @Override    public void addMappedStatement(MappedStatement ms) {        // ... }    // ... 省略若干行    /**     * 使用自己的 MybatisMapperRegistry     */    @Override    public <T> void addMapper(Class<T> type) {        mybatisMapperRegistry.addMapper(type);    }    // .... 省略若干行}


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


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


          在MybatisMapperRegistry類的addMapper方法中,真正進入到MP的核心類MybatisMapperAnnotationBuilder,索公眾號互聯(lián)網(wǎng)架構師復“2T”,送你一份驚喜禮包。MybatisMapperAnnotationBuilder這個類是MP實現(xiàn)動態(tài)腳本的關鍵類。


          MybatisMapperAnnotationBuilder動態(tài)構造


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


          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注入默認的方法列表**/        if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {            GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);        }        //... 省略若干行    }
              @Override    public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {        Class<?> modelClass = extractModelClass(mapperClass);        //... 省略若干行        List<AbstractMethod> 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<AbstractMethod> getMethodList(Class<?> mapperClass) {        return Stream.of(            new Insert(),            //... 省略若干行            new SelectPage()        ).collect(toList());    }}


          在MybatisMapperAnnotationBuilder中,MP真正將框架自定義的動態(tài)SQL語句注冊到Mybatis引擎中。而AbstractMethod則履行了具體方法的SQL語句構造。索公眾號互聯(lián)網(wǎng)架構師復“2T”,送你一份驚喜禮包。


          具體的AbstractMethod實例類,構造具體的方法SQL語句


          以 SelectById 這個類為例說明下


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


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


          總結(jié)一下


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




          總體上來說,MP實現(xiàn)mybatis的增強,手段略顯繁瑣和不夠直觀,其實根據(jù)MybatisMapperAnnotationBuilder構造出自定義方法的xml文件,將其轉(zhuǎn)換為mybatis的Resource資源,可以只繼承重寫一個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();        /** 只需要通過將自定義的方法構造成xml resource和原生定義的Resource一起注入到mybatis中即可, 這樣就可以實現(xiàn)MP的自定義動態(tài)SQL和原生SQL的共生關系**/        this.setMapperLocations(InjectMapper.getMapperResource(this.dbType, beanFactory, this.mapperLocations));        super.afterPropertiesSet();    }}


          在這篇文章中,簡單介紹了MP實現(xiàn)動態(tài)語句的實現(xiàn)過程,并且給出一個可能的更便捷方法。



          1、985副教授工資曝光

          2、心態(tài)崩了!稅前2萬4,到手1萬4,年終獎扣稅方式1月1日起施行~

          3、雷軍做程序員時寫的博客,很強大!

          4、人臉識別的時候,一定要穿上衣服啊!

          5、清華大學:2021 元宇宙研究報告!

          6、績效被打3.25B,員工將支付寶告上了法院,判了

          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜桃视频在线入口www | 囯产精品久久久久久久久久久久 | 男人天堂av网 | 一级A片一毛片大全 | 无码一区一区 |