Mybatis总结-动态sql、缓存机制

Mybatis总结

动态SQL的使用

  • 动态SQL是Mybatis强大的特性之一,极大的简化我们拼装SQL的操作
  • 动态SQL元素和使用JSTL或其他类似基于XML的文本处理器相似
  • MySQL采用功能强大的OGNL的表达式来简化操作
    • if
    • choose(when,otherwise)
    • trim(where,set)
    • foreach

if标签

  • 与java中的if类似,其中if标签中的test代表条件,支持使用& 和 ||,同时支持trim()
   <select id="getEmpsByConditionIf" resultType="com.wjl.mybatis.bean.Employee">
        select * from tbl_employee where
            <if test="id != null">
                id=#{id}
            </if>
            <if test="lastName != null and lastName !=''">
                and last_name like #{lastName}
            </if>
            <if test="email !=null  and email.trim()!=''">
                and email = #{email}
            </if>
            <if test="gender ==0 || gender ==1">
                and gender = #{gender}
            </if>
    </select>
  • where标签,当如上图一样使用if时,当id为空时,此时sql语句编程 select * from tbl_employee where and last_name = xxx …,where 标签,将if包含,会将if标签中多余的and或者or去除(只能放到前面and email = #{email}) where只会去掉第一个多出来的,where标签代表使用where查询
   <select id="getEmpsByConditionIf" resultType="com.wjl.mybatis.bean.Employee">
        select * from tbl_employee
        <where>
            <if test="id != null">
                id=#{id}
            </if>
            <if test="lastName != null and lastName !=''">
                and last_name like #{lastName}
            </if>
            <if test="email !=null  and email.trim()!=''">
                and email = #{email}
            </if>
            <if test="gender ==0 || gender ==1">
                and gender = #{gender}
            </if>
        </where>
    </select>

trim标签

  • 当有人习惯将and写在之后时,如下,这样where标签就无法满足去除掉多余的and的功能了,此时可以使用trim标签来自定义截取字符串
 <if test="id != null">
         id=#{id} and
  </if>
 <select id="getEmpsByConditionTrim" resultType="com.wjl.mybatis.bean.Employee">
        select * from tbl_employee
        <!--prefix="" suffix="" prefixOverrides="" suffixOverrides=""
         prefix 前缀:trim标签体中是整个字符串中拼串后的结果,prefix是给整个字符串加一个前缀
         prefixOverrides : 去掉拼接字符串前多余的字符
         suffix:整体加后缀
         suffixOverrides:去除多余的后面的字符
         使用trim来自定义字符串截取规则
         -->
        <trim prefix="where" suffixOverrides="and">
            <if test="id != null">
                id=#{id} and
            </if>
            <if test="lastName != null and lastName !=''">
                last_name like #{lastName} and
            </if>
            <if test="email !=null  and email.trim()!=''">
                email = #{email} and
            </if>
            <if test="gender ==0 || gender ==1">
                gender = #{gender}
            </if>
        </trim>
    </select>

choose标签

  • 类似于java语言中的分支选择:swtich-case,分支选择
    <select id="getEmpsByConditionChoose" resultType="com.wjl.mybatis.bean.Employee">
        select * from tbl_employee
        <where>
            <choose>
                <when test="id!=null">id = #{id}</when>
                <when test="lastName!=null">last_name =#{lastName}</when>
                <when test="email!=null">email=#{email}</when>
                <otherwise>
                    gender=0
                </otherwise>
            </choose>
        </where>
    </select>

foreach标签

  • 类似于Java中的for循环,collection:指定输入对象中集合属性 item:每次遍历生成的对象 open:开始遍历时拼接的串 close:结束遍历时两个对象需要拼接的串,separator mybatis会在每次迭代后给sql语句append上separator属性指定的字符,该参数为可选项,index 在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。
<insert id="insertEmployee">
    insert into tbl_employee(last_name,email,gender)
    values
        <foreach collection="list" item="item" index="index" separator=",">
        (#{item.lastName,jdbcType=VARCHAR}, #{item.email,jdbcType=VARCHAR}, #{item.gender,jdbcType=VARCHAR})
    </foreach>
   </insert>

Mybatis的缓存机制

  • Mybatis包含了一个非常强大的查询缓存特性,它可以非常方便的配置和定制,可以极大的提升查询的效率
  • MyBatis系统中默认定义了两级缓存,分别为一级缓存和二级缓存
    • 默认情况下只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)开启.
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高可扩展型.mybatis定义了缓存接口Cache,可以通过实现Cache接口来自定义二级缓存.

一级缓存

  • 一级缓存(local cache),即本地缓存,作用域默认为sqlSession.当Session flush 或close后,该Session中的所有Cache将被清空
  • 本地缓存不能被关闭,但可以调用clearCache()来清空本地缓存,或者改变缓存的作用域
  • 同一次会话期间,只要查询过的数据都会保存在当前SqlSession的一个Map中
    • key:hashCode+查询的sqlid+编写的sql查询语句+参数
  • 下述例子,当进行第二次查询的时候,没有清空缓存的时候,两个查询出来的对象相等,并不会再次发送请求在数据库中查询,当手动清空缓存后sqlSession.clearCache();,会再次发送请求
    @Test
    public void testFirstLevelCache() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSeesionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee empById = mapper.getEmpById(1);
            System.out.println(empById);
            // 手动清空缓存
            //sqlSession.clearCache();
            Employee empById1 = mapper.getEmpById(1);
            System.out.println(empById1 == empById);
        } finally {
            sqlSession.close();
        }
    }
  • 一级缓存失效的四种情况(没有使用到当前一级缓存的情况,效果就是,还需要向数据库发出查询)
    • sqlSession发生改变 System.out.println(empById1==empById); false
    • sqlSession相同,查询条件不同(当前一级缓存中没有这个数据)
    • sqlSession相同,两次查询之间执行了增删改(这次增删改可能会对当前数据有影响)
    • sqlSession相同,两次查询期间手动清空了缓存

二级缓存

  • 二级缓存(second level cache),全局作用缓存,二级缓存默认不开启,需要手动配置
  • 二级缓存的工作机制
    1. 一个会话,查询一条数据,这个会话就会被放在当前会话的一级缓存中
    2. 如果会话关闭;一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存
    3. sqlSession === EmployeeMapper==》Employee
      DepartmentMapper ===》Department
    4. 不同namespace查出的数据会放在自己对应的缓存中(map)
    5. 查出的数据都会放在一级缓存中,只有会话提交或者关闭以后,一级缓存的数据才会转移到二级缓存中
  • Mybatis提供二级缓存的接口以及实现,缓存实现要求POJO实现Serializable接口
  • 二级缓存在SqlSession关闭或者提交之后才会生效
  • 使用步骤
    1. 开启全局二级缓存 ,在全局配置文件的settings中设置 <setting name="cacheEnabled" value="true"></setting>

      <settings>
      <!-- 开启全局二级缓存 -->
      <setting name="cacheEnabled" value="true"></setting>
      </settings>
      
    2. 去对应Mapper.xml中配置使用二级缓存 ,<cache></cache>

    3. POJO需要实现序列化接口

    4. 测试

        @Test
          public void testSecondLevelCache() throws IOException {
              SqlSessionFactory sqlSessionFactory = getSqlSeesionFactory();
              SqlSession sqlSession = sqlSessionFactory.openSession(true);
              SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
              try{
                  //
                  EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
                  EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
                  Employee empById = mapper.getEmpById(1);
                  System.out.println(empById);
                  sqlSession.close();
      
                  // 第二次查询是从二级缓存中获取的,并没有发送数据
                  Employee empById1 = mapper1.getEmpById(1);
                  System.out.println(empById1);
                  sqlSession1.close();
              }finally {
                  
              }
          }
      
  • 相关mapper.xml中配置<cache></cache>的相关属性
    • eviction 缓存的回收策略
      • LRU-最近最少使用的:移除最长时间不被使用的对象
      • FIFO:先进先出:按照对象进入缓存的顺序移除他们
      • SOFT:软引用:移除基于垃圾回收器状态和软引用规则的对象
      • WEAK:软引用:更积极的移除位于基于垃圾回收器状态和弱引用规则的对象
      • 默认是LRU
    • flushInterval: 缓存刷新间隔
      • 多长时间清空一次,默认不清空,设置毫秒值
    • readOnly:缓存是否只读
      - true:只读,所有从缓存中获取数据的操作都是只读操作,不会修改数据, mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户,不安全,速度快
      - false:非只读,mybatis觉得获取的数据可能会被修改, mybatis会利用序列化&反序列胡克隆一份新的数据给你 安全,速度慢
    • size :存放多少元素
    • type: 指定自定义缓存的全类名,实现Cache接口即可
二级缓存有关的设置
  1. 全局setting中设置cacheEnabled=true;false:关闭缓存(二级缓存关闭)(一级缓存一直可用)
  2. 每一个select标签都有useCache="true",false,一级缓存可用,二级缓存关闭
  3. 每个增删改标签的:flushCache="true",增删改执行完成后就会清空缓存(一级缓存清空二级缓存也会被清空)
  4. 查询标签flushCache="false",如果作为true,则每次查询之前都会清空缓存
  5. sqlSession.clearCache();清空当前session的一级缓存
  6. localCacheScope:本地缓存作用域
    • 一级缓存SESSION:当前回话的所有数据保存在回话缓存中
    • STATEMENT:可以禁用一级缓存
  7. 当在某一个作用域(一级缓存session/二级缓存Namespaces)进行了增/删/改操作后,默认该作用域中所有的select中的缓存将会被clear

尚硅谷B站Mybatis教程: Mybatis从入门到精通

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值