首页 > 数据库 >【学习笔记】动态SQL

【学习笔记】动态SQL

时间:2023-01-09 14:44:06浏览次数:50  
标签:title author 笔记 SQL blog sql 动态 where select

动态SQL

1. 概念

动态SQL:动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

总结:根据不同的条件生成不同的sql语句

动态sql主要有以下四个标签:

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

在mapper.xml文件中使用这四个标签灵活调度sql语句。

 

2. 环境搭建

以blog为例,进行动态sql的学习

  • 创建blog数据库表

    create table blog(
        `id` varchar(50) not null comment '博客id',
        `title` varchar(100) not null comment '博客标题',
        `author` varchar(30) not null comment '博客作者',
        `create_time` datetime not null comment '创建时间',
        `views` int(30) not null comment '浏览量'
    )engine=INNODB default charset = utf8
  • 创建实体类模型

    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }

    在这一步有两个问题:

    • createTime这个属性 与数据库表create_time字段不对应,解决方案是在xml配置文件中setting标签有一个属性为mapUnderscoreToCamelCase(是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。) 设置为true就能实现java属性驼峰命名到数据库下划线命名映射。

    • 我们要实现id为自动生成随机的内容,解决方案是写一个工具类

      public class IDUtils {
          public static String getId(){
              return UUID.randomUUID().toString().replaceAll("-","");
          }
      }

      随机生成一个UID,并把其中的“-” 替换为空

 

  • 向数据库表blog中插入数据

 

3. IF标签

在select标签中进行条件的判断,根据判断结果向原来的sql语句中追加不同的sql语句

场景:我们在查询blog时,传入的参数为title 和 author ,当这两个参数为空时我们希望所有的blog都被查出来,当参数不为空时,只查该有该参数的结果。

实现:

  • mapper.xml

    <select id="queryBlogIF" resultType="Blog" parameterType="map">
        select * from blog where 1=1
        
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="anthor != null">
            and author = #{author}
        </if>
    </select>

    if标签中的 test 属性就是判断条件,如果满足就拼接标签里面的内容

  • 首先不往map中放值,也就是title和author都为null

    @Test
    public void test02(){
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    ​
        HashMap map = new HashMap();
        mapper.queryBlogIF(map)
    ​
        sqlSession.close();
    }

    image-20230106152232936

    四条结果都显示出来了

  • 往map中放入title和author的值

    image-20230106152457035

    只有一条对应参数的记录

 

4. trim(where,set)

where

官方对于where标签的解释:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

对于上面的案例来说,我们在sql语句中是这样写的

select * from blog where 1=1

显然 where 1=1 是不合乎规定的,我们可以使用where标签来控制where子句的存在与否

<select id="queryBlogIF" resultType="Blog" parameterType="map">
     select * from blog
     <where>
         <if test="title != null">
             title = #{title}
         </if>
         <if test="author != null">
             and author = #{author}
         </if>
     </where>
 </select>

如果两个if判断都不满足,那么就没有where子句,sql就变成了 select * from blog

如果只传入title,sql变成了:select * from blog where title = #{title}

如果只传入author,sql变成了 select * from blog where author = #{author} ,它会自动将and去除

如果都传入,sql就为:select * from blog where title = #{title} and author = #{author}

set

官方解释:

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号

<update id="updateBlogSet" parameterType="map">
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</update>

set标签会自动为sql添加set关键字,并且可以去掉多余的逗号

 

trim

官方:

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

举例:

trim标签有四个属性

prefix:前缀 ,可以自定义前缀

prefixOverrides:前缀覆盖,可以覆盖掉sql语句中的prefixOverrides 包含的内容

<select id="queryBlogIF" resultType="Blog" parameterType="map">
        select * from blog
       <trim prefix="where" prefixOverrides="and">
           <if test="title != null">
               and title = #{title}
           </if>
           <if test="author != null">
               and author = #{author}
           </if>
       </trim>
    </select>

我们自定义的前缀为where,并且可以覆盖掉sql前面的and

suffix:后缀,也可以自定义

suffixOverrides:后缀覆盖,可以覆盖掉sql后面的内容

<trim prefix="where" prefixOverrides="and" suffixOverrides=",">
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author},
    </if>
</trim>

注意看,我们在第二个if标签中的sql后面多加了个逗号,如果没有suffixOverrides="," 就会报错,加上它,它就会帮你覆盖掉最后的逗号。

 

 

5. choose (when, otherwise)

官方对于choose的解释:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

是的choose标签就像java的switch语句,只满足其中一条就结束判断

choose标签中,包含的是when和otherwise标签

when标签就相当于case , otherwise相当于default

<select id="queryBlogChoose" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
               author = #{author}
            </when>
            <otherwise>
                views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

如果title不为空,那么sql就是 select * from blog where title = #{title}

title为空,author不为空 sql就是:select * from blog where author = #{author}

title和author都为空,sql'就是:select * from blog where views = #{views}

如果什么都不传,sql是:select * from blog WHERE views = ? 也就什么也查不出来

 

6.sql片段

当动态sql中存在一些重复的代码,我们可以将他们提取出来,作为sql片段,用以复用。

举个例子:像上面的案例

<if test="title != null">
    and title = #{title}
</if>
<if test="author != null">
    and author = #{author},
</if>

这段代码频繁地出现在每个动态sql中,我们可以将它们提取为sql片段

sql片段是通过 sql 标签来实现的

<sql id="if-title-author" >
     <if test="title != null">
         title = #{title}
     </if>
     <if test="author != null">
         and author = #{author}
     </if>
 </sql> 
<select id="queryBlogIF" resultType="Blog" parameterType="map">
     select * from blog
     <where>
        <include refid="if-title-author"></include>
     </where>
</select>

在sql标签中,属性就是这个给这个sql片段取的标识符,在sql片段里面,放复用的代码

在使用这个sql片段的地方,用include标签来引用,属性refid就是sql片段的 id

注意:

  • 最好基于单表进行sql片段的定义

  • 不要在sql片段里写where标签

 

7.foreach

foreach是对集合进行遍历

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

foreach的属性有:

collecton:指定一个集合,遍历这个集合中的内容

item:集合中的每一项

index:集合中每一项的索引

open:要拼接的sql语句的前缀

close:要拼接的sql语句的后缀

separator:集合的每一项中间的分隔符

使用场景案例:

我们要找数据库中某三个元素

<select id="queryBlogForeach" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <foreach collection="titles" item="title" open="(" separator="or" close=")">
            title = #{title}
        </foreach>
    </where>
</select>
public void test05(){
    SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
​
    HashMap map = new HashMap();
​
    ArrayList<String> titles = new ArrayList<>();
​
    titles.add("mybatis动态sql");
    titles.add("mybatis注解开发");
    titles.add("mybatis配置优化");
​
​
    map.put("titles",titles);
​
    mapper.queryBlogForeach(map);
​
    sqlSession.close();
}

最后的sql语句为:select * from blog WHERE ( title = ? or title = ? or title = ? )

 

8.总结

所谓的动态sql本质还是sql,只是我们在sql层面去执行一些逻辑代码,根据不同的条件生成不同的sql语句

动态sql就是在拼接sql语句

标签:title,author,笔记,SQL,blog,sql,动态,where,select
From: https://www.cnblogs.com/wztblogs/p/17037008.html

相关文章

  • sql server技巧类sql语句
    1、1=1,1=2的使用,在SQL语句组合时用的较多“where1=1”是表示选择全部“where1=2”全部不选,如:if@strWhere!=’’beginset@strSQL=‘selectcount(*)asTotal......
  • fhqTreap学习笔记/做题记录
    \(\rmfhqTreap\)学习笔记&做题记录发大电部分我是\(\rmfhqTreap\)批众所周知,\(\rmfhqTreap\)可以部分(或者完全?)替代splay的区间功能,而且写起来又方便,所以去tm的s......
  • 扩展KMP学习笔记
    前置芝士:KMP,manachar告示:本文字符串下标均从$1$开始。扩展KMP算法提供了一个计算$Z$函数的方法。求解$Z$函数定义$Z$函数$z_i$表示字符串$s$以下标$i$......
  • mysql安装与配置
    下载mysql进入msql官网downloads点击此链接点击链接点击绿框,选择版本下载第一个配置文件在mysql的安装目录下创建my.ini将下面的代码输入进去[mysql]default......
  • python ssh链接Mysql数据库
    fromsshtunnelimportSSHTunnelForwarderimporttime,datetime,pymysql,json,requestsdefssh_mysql(sql,method):#SSH信息ssh_ip=''ssh_port=22......
  • sql server语句(1)
    1、说明:复制表(只复制结构,源表名:a新表名:b)(Access可用)法一:select*intobfromawhere1<>1(仅用于SQlServer)法二:selecttop0*intobfroma2、说明:拷贝表(拷贝......
  • 只是一篇笔记
    笔记//Awake用于在游戏开始之前初始化变量或游戏状态,不管SetActive多少次,它只会调用一次voidAwake(){print("1");GetTextFromFIle(textF......
  • pg 判断表或者模式是否存在 满足条件后执行创建表sql
    createorreplacefunctioncreate_view_a()returnsvoidas$$declareviewExistinteger;beginselectcount(1)intoviewExistFROMpg_namespaceWHERE......
  • 退火算法学习笔记
    初创建于2022-02-0900:29前段时间学习了一下退火算法。这里简单记一下踩过的坑~退火算法是一种搜索算法,我认为其核心思想便是”以一定的概率接受一个更差的解“,这样可......
  • sql server基础语句
    1、说明:创建数据库CREATEDATABASEdatabase-name2、说明:删除数据库dropdatabasedbname3、说明:备份sqlserver—创建备份数据的deviceUSEmasterEXECsp_addum......