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

<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语句。

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

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},而其他对立条件不生效。
测试结果如下:
Springboot-Mybatis之动态SQL和缓存_第1张图片
但若传入一个空的map,可见mybatis拼接的是中的SQL。
测试结果如下:
Springboot-Mybatis之动态SQL和缓存_第2张图片
提醒: 如果每个case都符合,那么只会拼接第一个的SQL!

3、set

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

<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

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

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

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

5、foreach

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

<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}},可见执行结果如下:
Springboot-Mybatis之动态SQL和缓存_第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,敬请期待!

你可能感兴趣的:(javaweb,mybatis,sql,缓存,java)