一、缓存

一级缓存

默认开启。
一级缓存也称之为sesssion级别的缓存, 也就是说在一次回话中执行相同的查询时,会首先查询缓存, 如果缓存没有数据,则直接查询数据库,并且个给缓存放一份,如果有就直接查询缓存。

所有的增删改操作都会清空缓存。
还有一些操作也会清空缓存:

①手动清理缓存 ② 提交了事务 ③管理链接,并且开启了新的连接

session级别的缓存:在一个sqlSession的一个事务中,多次查询相同的数据,会被缓存。

二级缓存

二级缓存又叫sessionFactory级别的缓存。
可以在两个session(事务)之间共享数据。

二级缓存是默认不开启的,需要手动开启。

我们可以在映射文件中开启二级缓存:
image-20210322140522012.png
eviction:清除缓存的策略,一般都是配置FIFO。

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

    flushInterval :设置刷新时间,以毫秒单位,如果不设置就会不刷新。 size:应用数目。默认是1024。 readOnly:是否只读。

  1. @Test
  2. public void testCache2(){
  3. SqlSession sqlSession = factory.openSession();
  4. Student st = sqlSession.selectOne("com.st.mapper.StudentMapper.queryByStudentId",1L);
  5. System.out.println(st.getStudentName());
  6. sqlSession.clearCache();//清空
  7. //关闭连接
  8. sqlSession.close();
  9. //重新打开一个sqlSession, 两个sqlSession之间不能共享一级缓存的内容,但是可以共享二级缓存的内容
  10. sqlSession = factory.openSession();
  11. Student st1 = sqlSession.selectOne("com.st.mapper.StudentMapper.queryByStudentId",1L);
  12. System.out.println(st1.getStudentName());
  13. //没有结束,就没有提交,也没有回滚
  14. }

二级缓存的情况下,增删改依然会清空缓存

二、动态sql

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

if标签

案例:多条件组合查询
根据学生的姓名和性别组合查询。
以前的做法: 在程序中使用java完成逻辑判断。当然还有 “where 1 = 1”
MyBatis的动态sql:

<!-- 动态sql -->
<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<select id="queryByNameAndGender" parameterType="student" resultMap="student">
    select * from student where 1 = 1
    <!-- test里面判断时,直接写属性名称 -->
    <if test="studentName!=null and studentName!=''">
        and stuName like '%${studentName}%'
    </if>
    <if test="stuGender!=null and stuGender!=-1">
        and stuGender = #{stuGender}
    </if>
</select>

测试:

@Test
public void testSql_if(){
    Student student = new Student();
    student.setStuGender(1);
    student.setStudentName("三");

    SqlSession sqlSession = factory.openSession();
    List<Student> sts = sqlSession.selectList("com.st.mapper.StudentMapper.queryByNameAndGender",student);
    for (Student st : sts){
        System.out.println(st);
    }
}

choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
案例:
查询学生,只按照一个条件查询,但是可以传入多个,如果某一个可以使用,则不再使用别的

<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<select id="queryByNameAndGender1" parameterType="student" resultMap="stuResultMapping">
    select * from student where 1 = 1
    <!-- test里面判断时,直接写属性名称 -->
    <choose>
        <when test="studentName!=null and studentName!=''">
            and stuName like '%${studentName}%'
        </when>
        <when test="stuGender!=null and stuGender!=-1">
            and stuGender = #{stuGender}
        </when>
        <otherwise>
            <!-- 这里可以有其他的条件 -->
        </otherwise>
    </choose>
</select>

多重的if else ,当一个条件满足之后,就不会在判断其他条件了。
测试:还是if的测试程序。

trim、where、set

where

处理where语句块的, 有了where标签,我们就不用使用“where 1 =1 ”。标签会自动判断,去掉多余的and。
案例:

<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<!-- where标签 -->
<select id="queryByNameAndGender2" parameterType="student" resultMap="stuResultMapping">
    select * from student
    <!-- 自动添加where语句块,并且删除多余的 “and” -->
    <where>
        <!-- test里面判断时,直接写属性名称 -->
        <if test="studentName!=null and studentName!=''">
            and stuName like '%${studentName}%'
        </if>
        <if test="stuGender!=null and stuGender!=-1">
            and stuGender = #{stuGender}
        </if>
    </where>
</select>

set

处理update语句中的set部分。添加set字样,删除多余的“,”
案例:

<!-- set标签 -->
<update id="updateStudent" parameterType="student">
    update student
    <set>
        <if test="studentName!=null and studentName!=''">
            stuName=#{studentName},
        </if>
        <if test="loginPass!=null and loginPass!=''">
            longinPass=#{loginPass},
        </if>
        <if test="stuGender!=null and stuGender!=-1">
            stuGender=#{stuGender}
        </if>
    </set>
    where stuId=#{stuId}
</update>

trim

和where等价的trim:

<!-- 根据name和gender组合查询学生信息 -->
<!-- 传入的参数是学生对象,使用学生对象封装查询参数 -->
<!-- 和where等价的trim -->
<select id="queryByNameAndGender3" parameterType="student" resultMap="stuResultMapping">
    select * from student
    <!-- prefiex:最前面添加一个where字样 -->
    <!-- prefixOverrides:取出前面多余的(and或者or)字样 -->
    <trim prefix="where" prefixOverrides="and | or">
        <!-- test里面判断时,直接写属性名称 -->
        <if test="studentName!=null and studentName!=''">
            and stuName like '%${studentName}%'
        </if>
        <if test="stuGender!=null and stuGender!=-1">
            and stuGender = #{stuGender}
        </if>
    </trim>
</select>

和set等价的trim:

<!-- set标签 -->
<update id="updateStudent1" parameterType="student">
    update student
    <!-- prefix:添加set字样  suffixOverrides:删除多余的后缀(“,”) -->
    <trim prefix="set" suffixOverrides=",">
        <if test="studentName!=null and studentName!=''">
            stuName=#{studentName},
        </if>
        <if test="loginPass!=null and loginPass!=''">
            longinPass=#{loginPass},
        </if>
        <if test="stuGender!=null and stuGender!=-1">
            stuGender=#{stuGender}
        </if>
    </trim>
    where stuId=#{stuId}
</update>

foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

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

提示** 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

查询指定班级编号的学生信息:

<!-- foreach标签 -->
<select id="queryStudentByClassIds" resultMap="stuResultMapping">
    select * from student where classId in
    <foreach collection="list" index="index" item="cid" separator="," open="(" close=")">
        #{cid}
    </foreach>
</select>
@Test
public void testSql_foreach(){
    List<Long> cids=new ArrayList<Long>(Arrays.asList(new Long []{1L,3L,4L,5L}));

    SqlSession sqlSession = factory.openSession();
    List<Student> sts = sqlSession.selectList("com.st.mapper.StudentMapper.queryStudentByClassIds",cids);
    for (Student st : sts){
        System.out.println(st);
    }
}