mybatis动态SQL解析备忘录

mybatis 动态sql解析源码分析

首先,不考虑依赖及调用关系来孤立的看几个主要的接口:


  • SqlNode接口:单理解就是xml中的每个标签,比如最基本的数据库ruid操作,对应xml文件中的<insert>、<select>、<update>、<delete>标签。但是这些基本标签都是数据库原生支持的操作,只需要解析标签生成SQL语句即可,并不涉及到动态Sql的解析,因此很自然就能想到,涉及动态SQL解析的部分,对应的标签是:<choose>(分支选择)、<foreach>(集合循环)、<if>(条件选择)、<trim>(字符串去空格)、<include>(java对象绑定,如<bind name="currentDate" value="new java.util.Date()")、<where>(条件查询)、<set>(更新)等。
  • SqlSource接口:sql源接口,代表从xml文件或DAO接口注解映射的sql内容,主要就是用于创建BoundSql,有实现类DynamicSqlSource(动态Sql源),StaticSqlSource(静态Sql源)等。
  • BoundSql类:封装mybatis最终产生sql的类,包括sql语句,参数,参数源数据等参数
  • BaseBuilder抽象类:有各种不同的实现类,分别用于解析处理不同的文件,其配置方式区分为独立使用mybatis和与spring集成,两者的配置不同: 独立使用时,全局属性(如<typeAliases>)、环境信息(如<settings>)、mapper文件配置(<mappers>)都在mybatis-config.xml中配置,使用不同的标签元素进行配置;与spring集成时,关于mapper文件的配置,都在spring SqlSessionFactoryBean类中配置,具体的可注入配置属性可看源码。 两种配置也可结合使用。其实现类如下:

1、XMLConfigBuilder:对应解析mybatis-config.xml配置文件,该文件配置mybatis的全局性设置,解析生成Configuration对象,内部会使用XMLMapperBuilder解析<mappers>标签配置(注意,其子标签<mapper>中的属性设置,只能三选一),如:

    <configuration>
    <settings>
        <setting name="defaultScriptingLanguage" value="extXml" />
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!--<setting name="cacheEnabled" value="true" />
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="multipleResultSetsEnabled" value="true" />
        <setting name="useColumnLabel" value="true" />
        <setting name="useGeneratedKeys" value="false" />
        <setting name="autoMappingBehavior" value="PARTIAL" />
        <setting name="defaultExecutorType" value="SIMPLE" />
        <setting name="defaultStatementTimeout" value="25" />
        <setting name="defaultFetchSize" value="100" />
        <setting name="safeRowBoundsEnabled" value="false" />
        <setting name="mapUnderscoreToCamelCase" value="false" />
        <setting name="localCacheScope" value="SESSION" />
        <setting name="jdbcTypeForNull" value="OTHER" />
        <setting name="lazyLoadTriggerMethods"          value="equals,clone,hashCode,toString" />-->
    </settings>
    <typeAliases>
        <typeAlias alias="extXml" type="package.xxxLanguageDriver" />
    </typeAliases>
    <mappers>
        <package name="packageName"/>
        <mapper resource="" | url="" | class="" />
    </mappers>  
  </configuration>

解析过程主方法:
这里写图片描述

  • 在独立使用mybatis时,使用SqlSessionManager读取该配置文件,生成XMLConfigBuilder,解析文件生成Configuration,最终生成SqlSessionFactory
  • 在与spring集成时,需要将该文件所在路径以”configLocation”属性名注入SqlSessionFactoryBean,由FactoryBean解析,以生成SqlSessionFactory

2、XMLMapperBuilder:遍历mybatis中所有的mapper xml文件(如user.xml),依次处理节点:<mapper>--<cache-ref>--<cache>--<parameterMap>--<resultMap>--<sql>--<select|insert|update|delete>(对于<cache-ref>、<resultMap>、<select|insert|update|delete>这三类标签,因为要涉及动态数据解析,注册到MapperRegistry中的都是以incomplete(未完成的)的容器存在,在绑定Mapper到namespace后进一步处理),然后处理Mapper到namespace的绑定,将<mapper>节点namespace属性及解析后的映射信息绑定到对应的Dao接口,使用代理工厂(MapperProxyFactory)模式生成Dao接口的代理对象,注册到Configuration对象的MapperRegistry中。MapperRegistry中使用Map<Class<?>, MapperProxyFactory<?>>存放 mapper 注册信息。其中key为Class类型,使用Resources.classForName(namespace)获取,value为一个Mapper的代理工厂,工厂中持有DAO 对应的mapperInterface接口类型和方法映射信息,生成Mapper代理(入参为”MapperProxy implements InvocationHandler, Serializable”) 。
以上解析过程,都会借助MapperBuilderAssistant辅助类进行处理。在解析<select|insert|update|delete>标签时,内部会收集<select|insert|update|delete>标签,循环使用XMLStatementBuilder处理每个statement节点。
3、XMLStatementBuilder:解析直接映射到sql的statement语句,持有MapperBuilderAssistant对象,用于获取当前处理mapper的命名空间并通过该对象将解析后的statement注入到Configuration中。XMLStatementBuilder处理statement标签,处理每个statement配置的databaseId、fetchSize、timeout、parameterMap、parameterType、resultMap、resultType、lang、resultSetType、statementType、flushCache、useCache、resultOrdered等属性,还会解析如<include>等引用标签。关于<if>、<choose>、<bind>等动态标签处理,使用lang属性设置的LanguageDriver,LanguageDriver再调用XMLScriptBuilder进行处理。但是一般情况下不需要为每个sql单独设置LanguageDriver,可在全局设置文件中设置,这里引出一个扩展点,即自定义LanguageDriver、XMLScriptBuilder、自定义标签对应的SqlNode以及自定义的SqlSource以处理自定义的标签解析动态Sql。
4、XMLScriptBuilder :负责整个statement是上下文节点中每个具体标签的处理,将标签类型分为三类:CDATA_SECTION_NODE(如:要在xml中使用<号或<=等,要写[[!CDATA < ]])、TEXT_NODE(如#{placeholder})、ELEMENT_NODE(如<if>、<trim>等),对于ELEMENT_NODE,每种标签对应了各自的NodeHandler进行处理。XMLScriptBuilder对动态标签进行处理后,生成SqlSource

下一个要解析的过程是在spring环境中,mapper与namespace绑定的另一种方式:spring的自动扫描机制MapperScannerConfigurer。先简单介绍下,MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor BeanDefinition注册后处理器,在postProcessBeanDefinitionRegistry方法中调用ClassPathMapperScanner extends ClassPathBeanDefinitionScanner处理Dao接口扫描,ClassPathMapperScanner重写doScan方法,在父类完成BeanDefinition信息扫描后,调用自身的processBeanDefinitions方法生成MapperFactoryBean,从而生成Mapper接口(对应的DAO)的代理对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值