有关MyBatis的动态SQL

有关MyBatis动态SQL

MyBatis动态SQL是一种根据不同条件灵活拼接SQL语句的技术,基于OGNL表达式实现。动态 SQL 大大减少了编写代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。

1.什么是动态SQL?

动态sql可以在一些需要灵活拼接sql语句的场景中使用,作用是根据一些条件,拼接出需要的sql语句。

动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。而动态 SQL 恰好解决了这一问题,可以根据场景动态的构建查询。

动态 SQL 只有几个基本元素,与 JSTL 或 XML 文本处理器相似,十分简单明了,大量的判断都可以在 MyBatis 的映射 XML 文件里配置,以达到许多需要大量代码才能实现的功能。

MyBatis 也可以在注解中配置 SQL,但是由于注解功能受限,且对于复杂的 SQL 语句来说可读性差,所以使用较少。本教程不对它们进行介绍。

2.动态SQL的作用与原理

2.1 作用

  • 灵活拼接SQL:根据参数值动态添加或删除SQL片段,例如条件查询、批量操作、多分支选择等场景
  • 简化代码:避免手动处理逗号、空格、WHERE/AND/OR等语法细节,提升代码可读性
  • 提高安全性:通过预编译机制(#{})防止SQL注入,但需注意复杂逻辑下的潜在风险

2.2 执行原理

  • OGNL表达式:MyBatis使用OGNL(Object-Graph Navigation Language)从参数对象中解析条件值,判断是否包含特定SQL片段

  • 动态解析流程

    ① XML中的SQL标签(如<if> <where>、)被解析为SqlNode对象;

    ② 运行时根据参数值生成BoundSql对象,拼接最终SQL;

    ③ 核心类如OgnlExpressionEvaluator处理表达式计算,TrimSqlNodeWhereSqlNode

    等处理语法修剪;

3.常用动态SQL标签及用法

MyBatis 的动态 SQL 包括以下几种元素,如下表所示。

元素作用备注
if判断语句单条件分支判断
choose(when、otherwise)相当于 Java 中的 switch case 语句多条件分支判断
trim、where辅助元素用于处理一些SQL拼装问题
foreach循环语句在in语句等列举条件常用
bind辅助元素拼接参数

3.1 <if>标签

  • 功能:通过test属性判断条件是否成立,决定是否包含SQL片段。当判断条件为 true 时,才会执行所包含的 SQL 语句

  • 示例:根据姓名和年龄动态查询用户:

    <select id="selectUser">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if><if test="age > 0">AND age = #{age}</if></where>
    </select>
    
    • 示例:可多个 if 语句同时使用。以下语句表示为可以按照student名称(stu_name)或者stu_age进行模糊查询。如果您不输入名称或年龄,则返回所有的student记录。但是,如果你传递了任意一个参数,它就会返回与给定参数相匹配的记录。
    <select id="select13" resultType="Student">select * from student where true<if test="name!=null">and stu_name='${name}'</if><if test="age!=null">and stu_age=${age}</if></select>
    

    注意:字符串比较需用toString()避免类型错误,如

    test="sex == '1'.toString()"
    

3.2 <where>标签

  • 功能:自动生成WHERE子句,并去除首个条件的AND/OR前缀,避免语法错误。

  • if 语句中判断条件为 true 时,where 关键字才会加入到组装的 SQL 里面,否则就不加入。where 会检索语句,它会将 where 后的第一个 SQL 条件语句的 AND 或者 OR 关键词去掉。

  • 示例:

    <where><if test="name != null">name = #{name}</if><if test="age != null">AND age = #{age}</if>
    </where>
    
    • 最佳实践:每个条件建议以AND/OR开头,<where>会自动处理首前缀,where后面的意思是,如果后面if条件中有成立的语句,则加上where语句,如果没有成立的条件语句,则不加where条件,第一个成立条件的语句,前面的and或者or自动删除。

3.3 <trim>标签

<trim prefix="前缀" suffix="后缀" prefixOverrides="忽略前缀字符" suffixOverrides="忽略后缀字符">SQL语句
</trim>
  • 功能:自定义前缀/后缀的添加或删除,适用于复杂场景。
  • 属性prefix(添加前缀)、suffix(添加后缀)、prefixOverrides(删除前缀)、suffixOverrides(删除后缀)。

trim 中属性说明如下。

属性描述
prefix给SQL语句拼接的前缀,为 trim 包含的内容加上前缀
suffix给SQL语句拼接的后缀,为 trim 包含的内容加上后缀
prefixOverrides去除 SQL 语句前面的关键字或字符,该关键字或者字符由 prefixOverrides 属性指定。
suffixOverrides去除 SQL 语句后面的关键字或者字符,该关键字或者字符由 suffixOverrides 属性指定。
  • 示例:替代<where>实现相同功能:

    <trim prefix="WHERE" prefixOverrides="AND |OR "><if test="name != null">AND name = #{name}</if>
    </trim>
    

3.4 <choose><when><otherwise>标签

  • 功能:实现多分支选择逻辑,类似Java的switch-case-default

  • <choose><when test="判断条件1">SQL语句1</when><when test="判断条件2">SQL语句2</when><when test="判断条件3">SQL语句3</when><otherwise>SQL语句4</otherwise>
    </choose>
    
  • 示例:

    <choose><when test="name != null">AND name = #{name}</when><when test="age != null">AND age = #{age}</when><otherwise>AND status = 1</otherwise>
    </choose>
    

3.5 <foreach>标签

对于一些 SQL 语句中含有 in 条件,需要迭代条件集合来生成的情况,可以使用 foreach 来实现 SQL 条件的迭代。

<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">参数值
</foreach>  

参数说明:

foreach 标签主要有以下属性,说明如下。

  • item:表示集合中每一个元素进行迭代时的别名。
  • index:指定一个名字,表示在迭代过程中每次迭代到的位置。
  • open:表示该语句以什么开始(既然是 in 条件语句,所以必然以(开始)。
  • separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是 in 条件语句,所以必然以,作为分隔符)。
  • close:表示该语句以什么结束(既然是 in 条件语句,所以必然以)开始)。

使用 foreach 标签时,最关键、最容易出错的是 collection 属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下 3 种情况:

  • 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
  • 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
  • 如果传入的参数是多个,需要把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。
  • 功能:遍历集合(如List、Array),生成批量操作的SQL,常用于IN语句或批量插入。

  • 示例:根据ID列表查询用户:

    SELECT * FROM user WHERE id IN
    <foreach collection="idList" item="id" open="(" separator="," close=")">#{id}
    </foreach>
    

3.6 <set>标签

  • 功能:在更新操作中动态生成SET子句,自动去除末尾逗号。

  • 示例:

    <update id="updateUser">UPDATE user<set><if test="name != null">name = #{name},</if><if test="age != null">age = #{age}</if></set>WHERE id = #{id}
    </update>
    

3.7 bind标签

每个数据库的拼接函数或连接符号都不同,例如 MySQL 的 concat 函数、Oracle 的连接符号“||”等。这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。幸运的是,MyBatis 提供了 bind 标签来解决这一问题。

bind 标签可以通过 OGNL 表达式自定义一个上下文变量。

比如,按照名称进行模糊查询,SQL 映射文件如下。

<select id="select14e" resultType="Student"><bind name="myvalue" value="'%'+stu_name+'%'" />SELECT *FROM studentWHERE stu_name like #{myvalue}
</select>            

bind 元素属性如下:

  • value:对应传入实体类的某个字段,可以进行字符串拼接等特殊处理。
  • name:给对应参数取的别名。

以上代码中的“_parameter”代表传递进来的参数,它和通配符连接后,赋给了 pattern,然后就可以在 select 语句中使用这个变量进行模糊查询,不管是 MySQL 数据库还是 Oracle 数据库都可以使用这样的语句,提高了可移植性。

4.使用建议与注意事项

  1. 优先使用<where><set>:避免手动添加1=1或处理逗号,提高代码简洁性

  2. 模糊查询优化:使用<bind>标签统一处理模糊匹配,如<bind name="nameLike" value="'%' + name + '%'" />,解决不同数据库的语法差异

  3. 性能考量:动态SQL可能影响执行计划优化,复杂条件建议结合索引设计使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/73034.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react使用拖拽,缩放组件,采用react-rnd解决 -完整版

屏幕录制2025-03-10 10.16.06 以下代码仅提供左侧可视化区域 右侧数据根据你们的存储数据来 大家直接看Rnd标签设置的属性即可&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; /*** 用户拖拽水印的最终位置信息*/ export interface ProductWatermarkValue {wat…

Spring Cloud之远程调用OpenFeign参数传递

目录 OpenFeign参数传递 传递单个参数 传递多个参数 传递对象 传递JSON OpenFeign参数传递 传递单个参数 服务提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

每日一练之移除链表元素

题目&#xff1a; 画图解析&#xff1a; 方法&#xff1a;双指针 解答代码&#xff08;注&#xff1a;解答代码带解析&#xff09;&#xff1a; //题目给的结构体 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* }…

从零开始的python学习(五)P75+P76+P77+P78+P79+P80

本文章记录观看B站python教程学习笔记和实践感悟&#xff0c;视频链接&#xff1a;【花了2万多买的Python教程全套&#xff0c;现在分享给大家&#xff0c;入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

基于SpringBoot实现旅游酒店平台功能八

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高&#xff0c;旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求&#xff0c;旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…

FastAPI 分页模块实现详解

1. 简介 本文详细介绍了一个基于 FastAPI 框架的通用分页处理模块的实现。该模块提供了标准的分页参数处理、数据切片和响应格式化功能&#xff0c;可以轻松地集成到任何 FastAPI 项目中。 2. 代码实现 2.1 导入必要的模块 首先&#xff0c;我们需要导入所需的模块&#xf…

Java 学习记录:基础到进阶之路(一)

今天&#xff0c;让我们深入到 Java 项目构建、基础语法及核心编程概念的领域&#xff0c;一探究竟。 软件安装及环境配置请查看之前更新的博客有着详细的介绍&#xff1a; IDEA软件安装&环境配置&中文插件-CSDN博客 目录 1.Java 项目构建基础 1.项目中的 SRC 目录…

Yashan DB 对象管理

一、什么是数据库对象 数据库对象是数据库里面用来存储和指向数据的各种概念和结构的总称。数据库支持的对象包括&#xff1a; • 表&#xff1a;表是一个逻辑概念&#xff0c;是数据库组织管理数据的基本单位。 • 索引&#xff1a;索引是建立在表上的逻辑对象&#xff0c;索…

deepseek 3FS编译

3FS在ubuntu22.04下的编译&#xff08;记录下编译过程&#xff0c;方便后续使用&#xff09; 环境信息 OS ubuntu 22.04内核版本 6.8.0-52-genericlibfuse 3.16.1rust 1.75.0FoundationDB 7.1.66meson 1.0.0ninja 1.10.1 libfuse编译 以下建议均在root下执行 pip3 install…

python-uiautomator2 安装教程

目录 一、简介 二、支持平台及语言 三、工作原理 四、安装 一、简介 uiautomator2是一个python库&#xff0c;用于Android的UI自动化测试&#xff0c;其底层基于Google uiautomator&#xff0c;Google提供的uiautomator库可以获取屏幕上任意一个APP的任意一个控件属性&…

无头浏览器与请求签名技术-Cloudflare防护

在实际数据采集实践中&#xff0c;许多目标网站&#xff08;例如 Amazon&#xff09;都会采用 Cloudflare 等防护措施&#xff0c;防止机器人和非正常流量。本文将分享一个故障场景下的排查与改进方案&#xff0c;讲述如何利用无头浏览器、请求签名技术以及爬虫代理 IP来实现数…

Spring Cloud之注册中心之Nacos健康监测和环境隔离

目录 Nacos健康检查 两种健康检查机制 Nacos服务类型实例 Nacos环境隔离 创建namespace 配置namespace Nacos健康检查 两种健康检查机制 Nacos作为注册中⼼, 需要感知服务的健康状态, 才能为服务调⽤⽅提供良好的服务. Nacos 中提供了两种健康检查机制&#xff1a; 客⼾…

Vue3实战学习(Element-Plus常用组件的使用(输入框、下拉框、单选框多选框、el-image图片))(上)(5)

目录 一、Vue3工程环境配置、项目基础脚手架搭建、Vue3基础语法、Vue3集成Element-Plus的详细教程。(博客链接如下) 二、Element-Plus常用组件使用。 &#xff08;1&#xff09;el-input。(input输入框) <1>正常状态的el-input。 <2>el-input的disable状态。 <3…

微服务——网关、网关登录校验、OpenFeign传递共享信息、Nacos共享配置以及热更新、动态路由

之前学习了Nacos&#xff0c;用于发现并注册、管理项目里所有的微服务&#xff0c;而OpenFeign简化微服务之间的通信&#xff0c;而为了使得前端可以使用微服务项目里的每一个微服务的接口&#xff0c;就应该将所有微服务的接口管理起来方便前端调用&#xff0c;所以有了网关。…

2025年3月11日(有限元牛顿迭代法:通俗讲解与示例)

牛顿迭代法的正确流程解释 是的&#xff0c;你的理解基本正确&#xff01;但需要更准确地描述内外力的关系和迭代逻辑。以下是更清晰的步骤说明&#xff1a; 核心流程&#xff08;修正版&#xff09; 假设已知 外力 ( F_{\text{ext}} )&#xff08;如2000 N&#xff09;&…

爬虫的精准识别:基于 User-Agent 的正则实现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

【AI大模型】LLM训练deepseek如何识别视频

要让像DeepSeek这样的大语言模型&#xff08;LLM&#xff09;具备视频识别能力&#xff0c;需要结合多模态学习技术&#xff0c;将视觉信息与文本语义进行融合。以下是实现这一目标的关键步骤和技术要点&#xff1a; --- 一、视频识别的核心挑战 1. 多模态数据&#xff1a;视频…

【物联网-以太网-W5500】

物联网-以太网-W5500 ■ W5500-简介■■■■ ■ W5500-简介 ■ ■ ■ ■

centos linux安装mysql8 重置密码 远程连接

1. 下载并安装 MySQL Yum 仓库 从 MySQL 官方网站下载并安装 Yum 仓库配置文件。 # 下载MySQL 8.0的Yum仓库包 wget https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm # 安装Yum仓库包 sudo rpm -ivh mysql80-community-release-el7-5.noarch.rpm2. 启…

C++【类和对象】(超详细!!!)

C【类和对象】 1.运算符重载2.赋值运算符重载3.日期类的实现 1.运算符重载 (1).C规定类类型运算符使用时&#xff0c;必须转换成调用运算符重载。 (2).运算符重载是具有特殊名字的函数&#xff0c;名字等于operator加需要使用的运算符&#xff0c;具有返回类型和参数列表及函数…