MyBatis 源码分析——动态SQL语句
有几年开发经验的程序员应该都有暗骂过原生的SQL语句吧。因为他们不能一句就搞定一个业务,往往还要通过代码来拼接相关的SQL语句。相信大家会理解SQL里面的永真(1=1),永假(1=2)的意义吧。所以mybatis动态SQL功能在笔者看来是最引吸人的。为了更好的区别XML映射文件上的SQL语句。mybatis把SQL语句分为四类。那么这个笔者已经在前面的章节里面讲过了。但是我们在开发过程中常常用到的也就俩种:静态和动态。
关于静态和动态的定义,笔者是这样子理解的——静态SQL语句显示就是里面没有相关的罗辑。即是没有#if之类的语活。反之则是动态SQL语句。而笔者感兴趣是动态SQL部分。我们都知道在读取XML映射文件信息的时候就会分析当前的SQL语句属于哪一种类型。这部分工作就是放在源码的XMLScriptBuilder类里面。
1 public SqlSource parseScriptNode() { 2 List<SqlNode> contents = parseDynamicTags(context); 3 MixedSqlNode rootSqlNode = new MixedSqlNode(contents); 4 SqlSource sqlSource = null; 5 if (isDynamic) { 6 sqlSource = new DynamicSqlSource(configuration, rootSqlNode); 7 } else { 8 sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); 9 } 10 return sqlSource; 11 }
看到了吧,是通过成员isDynamic的值来获取相关类型的SQL语句类。DynamicSqlSource类从字面上来讲就很容易看出来是属于动态的。而下面便是静态的。关键的部分还是在parseDynamicTags方法里面。
为了实现动态SQL语句的功能。mybatis设置几个动态的节点。如if,choose 等。当然如果你们想要知道有几个的话,最好跟笔者一样子点开他相关的DTD文件。如下
<!ELEMENT select (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
我们可以看到include 、trim 、where 、set 、foreach 、choose 、if 、bind。各自的用法在官网上面有些详细的说明。 大家可以去看看。相信大家看到这里心里应该有了一定的想法。为了实现动态SQL,那么mybatis一定会根据不同的节点来做不同的逻辑处理。这也是笔者为什么说——关键的部分还是在parseDynamicTags方法里面。因为parseDynamicTags方法是用于分析当前select或是delete等节点的SQL节点(即是SqlNode类)。可以说终于生成的SQL语句就是靠这若干个SqlNode类提供生成的。在前面几章中我们有讲到关于BoundSql类的作用。在这里就一下明白了。如下图
通过parseDynamicTags方法分析出需要用到的若干个SqlNode类。并确定他是否是动态SQL语句。如果是,就创建DynamicSqlSource类。而DynamicSqlSource类会存放在MappedStatement类里面。当我们要通过BoundSql类来生成StatementHandler实例的时候,就会从通过MappedStatement类获得对应的BoundSql类。而BoundSql类的getSql方法就会我们最终的落点。
其实笔者的内心是有一点小失望的。我本以为mybatis会一直实现自己的元素处理。当然这只是笔者内心的一点完美主义吧。正如官网上讲的MyBatis 采用功能强大的基于 OGNL 的表达式来消除其他元素。所以我们可以源码里面看到ognl的应用。
Map<Object, OgnlClassResolver> context = Ognl.createDefaultContext(root, new OgnlClassResolver());
对于ongl笔者就不想多说了。有兴趣的读者们可以自己去看一下。笔者建议还是去看一下吧。struts2框架里面也用到他了。
关于mybatis系列笔者就记录到这里了。希望对大家有用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?