前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >9. 动态SQL

9. 动态SQL

作者头像
捞月亮的小北
发布2023-12-01 08:50:26
1420
发布2023-12-01 08:50:26
举报
文章被收录于专栏:捞月亮的小北

Mybaits 框架的动态 SQL 技术是一种根据特定条件动态拼接 SQL 语句的功能 , 它存在的意义是为了解决拼接 SQL 语句字符串时的痛点问题

Mybatis 中动态 SQL 怎么理解?有什么作用?怎么去实现?

Mybatis 的动态 SQL 是指可以根据不同的条件动态生成 SQL 语句。它的作用主要是实现动态生成不同的 SQL 语句,以达到更灵活、高效的查询、更新、删除等操作。它大大增强了 SQL 动态适配的能力。

动态 SQL 的实现主要有两种方式:基于 XML 的实现和基于注解的实现。

  1. 基于 XML 的实现:在 Mybatis 的 Mapper XML 文件中使用文本节点、if 语句、where 语句、choose 语句、foreach 语句等元素和属性,可以根据不同的条件生成不同的 SQL 语句,实现灵活查询。

例如,以下是一个使用了 if 和 where 的例子:

代码语言:javascript
复制
<select id="queryByStatus" resultType="User">
  SELECT * FROM user WHERE 1=1
  <if test="status != null">
    AND status = #{status}
  </if>
  <if test="username != null">
    AND username like '%'||#{username}||'%'
  </if>
</select>
  1. 基于注解的实现:通过在 DAO 接口的方法上使用@SelectProvider、@InsertProvider、@UpdateProvider、@DeleteProvider 注解,提供一个动态 SQL 生成的类的实例方法来生成 SQL。

例如,以下是一个使用@SelectProvider 注解的例子:

代码语言:javascript
复制
@SelectProvider(type = SqlProvider.class, method = "queryByStatus")
List<User> queryByStatus(String status, String username);

其中,SqlProvider 是一个动态 SQL 的提供类,其中 queryByStatus 方法返回一个字符串类型的 SQL 语句,该方法根据用户实际传入的参数动态生成 SQL 语句。

动态 SQL 的实现可以根据实际的业务需求和场景,选择基于 XML 或注解两种方式进行编写。使用动态 SQL 可以方便地生成不同的 SQL 语句,使得查询、插入、更新等操作更加灵活、高效。同时,也需要注意 SQL 注入和动态 SQL 的维护难度问题。

1. if

if 标签可通过test属性​ 的表达式进行判断 , 若表达式的结果为 true , 则标签中的内容会执行 ; 反之标签中的内容不会执行

if 中 test 属性判断的是实体类当中属性的值

语法展示:

代码语言:javascript
复制
        <select id="getEmpByCondition" resultType="Emp">
            select * from t_emp where
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>

            <if test="age != null and age != ''">
                and age = #{age}
            </if>

            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </select>

2. where

where 和 if 一般结合使用:

  • a>若 where 标签中的 if 条件都不满足,则 where 标签没有任何功能,即不会添加 where 关键字
  • b>若 where 标签中的 if 条件满足,则 where 标签会自动添加 where 关键字,并将条件最前方多余的 and 去掉

注意:where 标签不能去掉条件最后多余的 and

代码语言:javascript
复制
<select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <where>
        <if test="empName != null and empName != '' ">
            emp_name = #{empName}
        </if>

        <if test="age != null and age != ''">
            and age = #{age}
        </if>

        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </where>
    </select>

3. trim

trim 用于去掉或添加标签中的内容

常用属性:

  • prefix:在 trim 标签中的内容的前面添加某些内容
  • prefixOverrides:在 trim 标签中的内容的前面去掉某些内容
  • suffix:在 trim 标签中的内容的后面添加某些内容
  • suffixOverrides:在 trim 标签中的内容的后面去掉某些内容

代码语言:javascript
复制
    <select id="getEmpByCondition" resultType="Emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="empName != null and empName != '' ">
                emp_name = #{empName} and
            </if>

            <if test="age != null and age != ''">
                age = #{age} and
            </if>

            <if test="gender != null and gender != ''">
                gender = #{gender}
            </if>
       </trim>
    </select>

4. choose , when , otherwise

choose、when、 otherwise 相当于 if...else if..else

代码语言:javascript
复制
    <select id="getEmpByChose" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name =  #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="gender != null and gender != ''">
                    gender = #{gender}
                </when>
            </choose>
        </where>
    </select>

5. foreach

代码语言:javascript
复制
<!--int insertMoreEmp(List<Emp> emps);-->
<insert id="insertMoreEmp">
	insert into t_emp values
	<foreach collection="emps" item="emp" separator=",">
		(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)
	</foreach>
</insert>

<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray">
	delete from t_emp where
	<foreach collection="eids" item="eid" separator="or">
		eid = #{eid}
	</foreach>
</delete>

<!--int deleteMoreByArray(int[] eids);-->
<delete id="deleteMoreByArray">
	delete from t_emp where eid in
	<foreach collection="eids" item="eid" separator="," open="(" close=")">
		#{eid}
	</foreach>
</delete>

  • collection : 设置要循环的数组或集合
  • item : 用一个字符串表示数组或集合中的每一个数据
  • separator : 设置每次循环的数据之间的分隔符
  • open : 循环的所有内容以什么开始
  • close : 循环的所有内容以什么结束

Mybatis 中的 foreach 标签用于循环遍历一个集合,动态生成 SQL 中的 in 语句。它的作用主要是构建动态 SQL 语句,一般用于 IN 查询、批量插入、更新和删除等操作。

foreach 标签的使用方法如下:

代码语言:javascript
复制
<select id="selectByIds" resultMap="userResultMap">
  SELECT * from user WHERE id IN
  <foreach collection="ids" item="id" open="(" separator="," close=")">
    #{id}
  </foreach>
</select>

上述代码中,ids​ 是一个列表,在 SQL 执行时,会将集合中的元素遍历一遍,生成类似于 (1, 2, 3)​ 的 SQL 语句。其中,open​、separator​、close​ 等属性用于定义拼接语句的开头、元素间的分隔符和结尾。

除了对于 IN 语句拼接,foreach 标签还可以用于批量插入、更新和删除等操作,例如:

代码语言:javascript
复制
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true">
  INSERT INTO user (username, password) VALUES
  <foreach collection="users" item="user" separator=",">
    (#{user.username}, #{user.password})
  </foreach>
</insert>

<update id="batchUpdate" parameterType="java.util.List">
  UPDATE user SET
  <foreach collection="users" item="user" separator=",">
    password = #{user.password}
  </foreach>
  WHERE id IN
  <foreach collection="ids" item="id" separator="," open="(" close=")">
    #{id}
  </foreach>
</update>

<delete id="batchDelete" parameterType="java.util.List">
  DELETE FROM user WHERE id IN
  <foreach collection="ids" item="id" separator="," open="(" close=")">
    #{id}
  </foreach>
</delete>

这三个示例分别是批量插入、批量更新和批量删除的实现方式。注意,这里 users​ 和 ids​ 也是列表,分别代表了待插入的用户和需要操作的记录的 ID。

通过使用 foreach 标签,Mybatis 使得动态 SQL 的拼接变得灵活而高效。可以通过遍历集合,动态生成 SQL 语句,以达到动态适配的目的。

6. SQL 片段

sql 片段 , 可以记录一段公共 sql 片段 , 在使用的地方通过 include 标签进行引入

代码语言:javascript
复制
<sql id="empColumns">
	eid,ename,age,sex,did
</sql>
select <include refid="empColumns"></include> from t_emp

6.1 SQL 片段的含义

Mybatis 中的 SQL 片段是一段预编译的 SQL 语句,它可以被多次使用。SQL 片段的作用是将常用的 SQL 语句封装成一个可重用的组件,方便在多个地方使用。

Mybatis 中的 SQL 片段有两种类型:

  1. 动态 SQL 片段:根据不同的条件生成不同的 SQL 语句。动态 SQL 片段可以根据参数的不同生成不同的 SQL 语句,适用于需要根据不同条件进行查询的情况。
  2. 静态 SQL 片段:固定的 SQL 语句,不需要根据参数的不同而变化。静态 SQL 片段适用于一些简单的查询操作,例如查询所有数据、插入数据等。

Mybatis 中的 SQL 片段可以通过 XML 文件或注解的方式定义,其中 XML 文件是一种常见的方式。在 XML 文件中,可以使用 <select> 、<update>、<insert>等标签来定义 SQL 片段,并通过参数绑定来实现动态 SQL 的功能。

6.2 SQL 片段的作用

SQL 片段(SQL Fragments)是 Mybatis 中一个重要的功能,它的作用是将一段 SQL 片段用 <sql>​ 元素封装,并在需要的地方通过 <include>​ 元素引用。主要有以下几个作用:

  1. 提高 SQL 的代码复用性:将一段经常重复使用的 SQL 代码封装到 SQL 片段中,可以在多个地方引用,避免了代码的冗余和重复编写。
  2. 减小 SQL 的维护难度:将一段 SQL 代码封装成 SQL 片段,可以方便维护和修改,避免了对 SQL 语句的重复修改和维护。
  3. 提高 SQL 程序的可读性和可维护性:将一段 SQL 代码封装到 SQL 片段中,可以使代码结构更加清晰,方便阅读和理解。

在 Mybatis 的 Mapper XML 文件中,可以在 <sql>​ 标签中定义 SQL 片段,例如:

代码语言:javascript
复制
<sql id="queryColumns">
  id, username, password
</sql>

然后在其他的 SQL 语句中,通过 <include>​ 元素引用该 SQL 片段:

代码语言:javascript
复制
<select id="selectById" parameterType="int" resultMap="userResultMap">
  SELECT <include refid="queryColumns"/> FROM user WHERE id = #{id}
</select>

上述语句中,使用 <include>​ 引用了 SQL 片段 "queryColumns" 中定义的代码 id, username, password​,简化了 SQL 语句的编写。

通过使用 SQL 片段,可以方便地提高代码复用和维护的效率,使 SQL 代码更加清晰和易于阅读和理解。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. if
  • 2. where
  • 3. trim
  • 4. choose , when , otherwise
  • 5. foreach
  • 6. SQL 片段
    • 6.1 SQL 片段的含义
      • 6.2 SQL 片段的作用
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档