Springboot-Mybatis之动态SQL和缓存

一、 动态SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
如果之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识,因为大致写法是差不多的。

1、if 语句

if语句是最简单的,通常用在where处添加条件拼接查询条件。

mapper.xml

<select id="getStudentsIf" 
		resultType="Student" parameterType="map">
    select id,name
    from student
    where 1=1
    <if test="deptId != null">
        and dept_id = #{deptId}
    </if>
</select>

测试代码(下面的例子中测试都是靠map这种传参)

Map map = new HashMap<>();
map.put("deptId",3);
List<Student> list = studentMapper.getStudentsIf(map);
list.forEach(System.out::println);

通过这个例子可以看到,通过if语句判断参数中deptId是否为空,根据判定结果追加SQL。如果这是deptId是3则查询班级ID是3是学生,null则查询全部学生。

问 :那里的where 1=1是啥?
答:为了保证sql可以执行。
问:怎么优化?
答:这里介绍一下<where>标签,我们知道在拼接条件时,从第二个条件开始要加OR或者AND,但若只有一个条件就不用加AND,但是如何控制呢?<where>标签帮助我们智能识别了,<where>中有条件成立,他就会自动加上在sql上拼接上“where”,如果第一个成立条件要拼接的sql是and id = #{id},就会自动帮助我们省忽略and,但若<where>中无成立的条件,mybatis咋会执行<where>之前的语句。

<select id="getStudentsIf" 
		resultType="Student" parameterType="map">
    select id,name
    from student
    <where>
	    <if test="deptId != null">
	        and dept_id = #{deptId}
	    </if>
    </where>
</select>

可见,利用where标签才是高级做法。

2、choose、when、otherwise

如果我们不想要全部的条件,只想取其中一个,而上面的if是无数个单独的if语句,没有else if 和else,针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch-case语句。

<choose>标签相当于最外层的switch,而<when> 相当于每一个case。<otherwise>是默认的。

mapper.xml

<select id="getStudentsChoose" resultType="Student" parameterType="map">
        select id,name,dept_id
        from student
        <where>
            <choose>
                <when test="name != null">
                    name = #{name}
                </when>
                <when test="deptId != null">
                    and dept_id = #{deptId}
                </when>
                <otherwise>
                    and id = #{id}
                </otherwise>
            </choose>
        </where>

在这里我们传入的map中只有{"deptId":2},所以mybatis智能拼接上了dept_id = #{deptId},而其他对立条件不生效。
测试结果如下:
在这里插入图片描述
但若传入一个空的map,可见mybatis拼接的是<otherwise>中的SQL。
测试结果如下:
g-blog.csdnimg.cn/2021012421195977.png)
提醒: 如果每个case都符合,那么只会拼接第一个<when>的SQL!

3、set

set一般用于update语句,和前面的where相似。<set>会帮助我们省略掉多余的“逗号,”

<update id="update" parameterType="map">
        update Student
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="deptId != null">
                dept_id = #{deptId}
            </if>
        </set>
        where id = #{id}
    </update>

在测试用例中我们传入一个{"id":2}{"name":二弟},可见mybatis帮我们拼接的SQL如下↓在这里插入图片描述

4、trim

可以发现<set><where>可以帮助我们忽略不必要的字符。但我们仍然可以通过自定义 trim 元素来定制 where /set元素的功能,例如

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

标签中参数意义不多赘述,自行翻译理解。

5、foreach

假如我们要拼接不定个数的SQL,参数传入一个List,如何编写动态sql呢?
答:利用<foreach>

<select id="getStudentsById" parameterType="map"   
		resultType="Student">
    select id,name,dept_id
    from student
    <where>
        <foreach collection="Ids"  separator="or" item="id" 
       			 open="(" close=")">
            id = #{id}
        </foreach>
    </where>
</select>

foreach 标签中,collection对应传入要遍历集合的名字,separator是拼接的每个sql间的分隔符,item是遍历到的当前元素,open和close分别代表遍历前和后加的前后缀。

以上sql传入一个{"Ids",new int[]{1,2,3}},可见执行结果如下:
在这里插入图片描述
这样就把参数list中所有id对应学生查询出来啦。

二、 mybatis缓存

1、一级缓存

也叫本地会话缓存。
针对于一个sqlsession,若想多次执行同一条sql,第一次会把查询结果保存在一级缓存中,再次查询时会直接去一级缓存中获取,不会再次访问数据库,大大减少了数据库的负压。

但当此sqlsession关闭连接后,一级缓存会清空。

2、二级缓存

也叫全局缓存。当sqlsession关闭连接后,会将一级缓存中的数据转存到二级缓存中。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<cache/>

并且在配置文件中开启缓存即可。

当然我们可以通过 cache 元素的属性来修改默认参数。比如:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

如果开启了二级缓存,映射语句文件中的所有 select 语句的结果将会被缓存,映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。

当执行一条语句时的执行顺序:
1.先去二级缓存中查
2.再去一级缓存中查
3.到数据库中查。

至此,mybatis的相关内容已经结束啦!是不是很简单呢~后序我们还会学习mybatis-plus,敬请期待!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值