首页
/ 深入理解MyBatis动态SQL:lcomment/development-recipes项目实践指南

深入理解MyBatis动态SQL:lcomment/development-recipes项目实践指南

2025-06-25 16:17:34作者:秋泉律Samson

什么是动态SQL

动态SQL是MyBatis框架最强大的特性之一。如果你曾经使用过JDBC或其他类似框架,就会明白根据条件拼接SQL语句是多么痛苦的事情。MyBatis提供了一套强大的动态SQL语言,可以在映射的SQL语句中使用。

MyBatis 3对动态SQL进行了重大改进,采用OGNL(Object-Graph Navigation Language)作为基础表达式语言,使得SQL语句的构建更加灵活和强大。

核心动态SQL元素

1. if条件判断

if元素是最基本的条件判断,允许你在SQL中包含条件性的where子句部分。

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG 
  WHERE state = 'ACTIVE'
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

使用技巧

  • 字符串比较:可以使用==!=eq.equals()方法
  • 忽略大小写比较:使用.equalsIgnoreCase()方法
  • 数字比较:支持>>=<<=等运算符
  • 逻辑运算:使用and代替&&or代替||

2. choose-when-otherwise多重选择

类似于Java中的switch-case结构,提供多重条件选择:

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG 
  WHERE state = 'ACTIVE'
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

3. trim-where-set智能处理

where元素

解决SQL拼接中AND/OR位置问题:

<select id="findActiveBlogLike" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
  </where>
</select>

set元素

动态更新语句解决方案:

<update id="updateAuthorIfNecessary">
  update Author
  <set>
    <if test="username != null">username=#{username},</if>
    <if test="password != null">password=#{password},</if>
  </set>
  where id=#{id}
</update>

trim元素

更灵活地处理SQL片段:

<!-- 替代where -->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

<!-- 替代set -->
<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

4. foreach循环遍历

特别适合构建IN条件:

<select id="selectPostIn" resultType="Post">
  SELECT * FROM POST P
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

支持的数据类型

  • 数组
  • 实现了Iterable接口的集合
  • Map对象(index为key,item为value)

5. script脚本支持

在注解方式的Mapper接口中使用动态SQL:

@Update({"<script>",
  "update Author",
  "  <set>",
  "    <if test='username != null'>username=#{username},</if>",
  "  </set>",
  "where id=#{id}",
  "</script>"})
void updateAuthorValues(Author author);

6. bind变量绑定

使用OGNL表达式创建变量并绑定到上下文:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

高级特性

多数据库厂商支持

通过_databaseId变量实现不同数据库的SQL适配:

<insert id="insert">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    <if test="_databaseId == 'oracle'">
      select seq_users.nextval from dual
    </if>
    <if test="_databaseId == 'db2'">
      select nextval for seq_users from sysibm.sysdummy1"
    </if>
  </selectKey>
  insert into users values (#{id}, #{name})
</insert>

可插拔脚本语言支持

MyBatis 3.2+支持自定义脚本语言驱动:

public interface LanguageDriver {
    ParameterHandler createParameterHandler(...);
    SqlSource createSqlSource(...);
}

配置方式

  1. 全局默认语言驱动:
<settings>
  <setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>
  1. 语句级别指定:
<select id="selectBlog" lang="myLanguage">...</select>
  1. 注解方式指定:
@Lang(MyLanguageDriver.class)
@Select("SELECT * FROM BLOG")
List<Blog> selectBlog();

最佳实践建议

  1. 复杂条件处理:对于复杂的条件查询,优先使用where+if组合,避免SQL语法错误
  2. 批量操作:使用foreach处理批量插入/更新时,注意数据库对批量语句长度的限制
  3. 性能考虑:动态SQL虽然灵活,但过度使用可能导致SQL难以维护和优化
  4. 可读性:对于特别复杂的动态SQL,考虑拆分为多个SQL语句或在业务层处理部分逻辑
  5. 测试覆盖:动态SQL的各个分支路径都应该有对应的测试用例覆盖

通过合理运用MyBatis的动态SQL特性,可以大大减少重复SQL代码,提高开发效率,同时保持SQL语句的清晰和可维护性。

登录后查看全文
热门项目推荐

热门内容推荐

最新内容推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
22
6
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
192
270
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
909
541
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
341
1.21 K
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
142
188
nop-entropynop-entropy
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
8
0
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
377
387
金融AI编程实战金融AI编程实战
为非计算机科班出身 (例如财经类高校金融学院) 同学量身定制,新手友好,让学生以亲身实践开源开发的方式,学会使用计算机自动化自己的科研/创新工作。案例以量化投资为主线,涉及 Bash、Python、SQL、BI、AI 等全技术栈,培养面向未来的数智化人才 (如数据工程师、数据分析师、数据科学家、数据决策者、量化投资人)。
Jupyter Notebook
63
58
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
1.1 K
0
note-gennote-gen
一款跨平台的 Markdown AI 笔记软件,致力于使用 AI 建立记录和写作的桥梁。
TSX
87
4