SSM_MyBatis_动态SQL_缓存

SSM_MyBatis


 

12.动态SQL

动态SQL元素和了JSTL或基于类似XML的文本处理器相似。在MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis采用功能强大的基于OGNL的表达式来淘汰其它大部分元素。

  • if

  • choose (when,otherwise)

  • trim (where,set)

  • foreach

1. 环境搭建

 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;
 }
 //=============在配置文件中设置驼峰命名转换,将数据库经典命名"_"转换为驼峰命名
 <setting name="mapUnderscoreToCamelCase" value="true" />

 

新建工具类

 public class IDutils {
     public static String getId(){
         //随机生成序列,清除"-"
         return UUID.randomUUID().toString().replaceAll(" -","");
     }
 }

 

2. IF

 <select id="queryBlogIF" parameterType="map" resultType="blog">
     <!--此处1=1不正规,其它动态标签讲解-->
     select * from mybatis.blog where 1=1
     <if test="title != nu11">
         and title =#{title}
     </if>
     <if test="author != null">
         and author = #{author}
     </if>
 </select>

 

测试

 public void testqueryBlogIF{
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap map = new HashMap();
     //如果不加参数则查询所有
     map.put("tit1e","Java");
     List<Blog> blogs = mapper.queryBlogIF(map);
     for(Blog blog : blogs) {
         System.out.printin(blog);
     }
     sqlSession.close();
 }

 

3. Choose (when,otherwise)

 <select id="queryBlogChoose" parameterType="map" resultType="blog">
     <!--此处1=1不正规,其它动态标签讲解-->
     select * from mybatis.blog 
     <!--如果一个子元素都不满足 where自动省略-->
     <where>
         <choose>
             <!--when只会实现一个,按先后顺序-->
             <when test="title != nu11">
                 title =#{title}
             </when>
             <when test="author != null">
                 <!--自动配置是否是第一个,是第一个自动去除AND-->
                 and author = #{author}
             </when>
             <otherwise>
                 and views = #{views}
             </otherwise>
         </choose>
     </where>
 </select>

 

4. Trim (where,set)

where元素只会在至少有一个子元素的条件返回SQL子句的情况下才去插入“WHERE"子句。

若语句的开头为"AND"或“OR", where元素也会将它们去除。

 <select id="queryBlogWhere" parameterType="map" resultType="blog">
     <!--此处1=1不正规,其它动态标签讲解-->
     select * from mybatis.blog 
     <!--如果一个子元素都不满足 where自动省略-->
     <where>
         <if test="title != nu11">
             title =#{title}
         </if>
         <if test="author != null">
             <!--自动配置是否是第一个,是第一个自动去除AND-->
             and author = #{author}
         </if>
     </where>
 </select>

 

set元素会动态前置SET关键字,同时也会删掉无关的逗号

使用set,条件成立自动拼接"set",且自动删除多余","

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

 

trim

 <trim prefix="SET" suffixoverrides=",">
 </trim>
 <!--参照文档学习-->

 

5. Foreach

 select * from user where 1=1 and (id=1 or id=2 or id=3)
 ?
 <foreach item="id" index="index" collection="ids" 
     open="(" separator= "or" close=")">
     #{item}
 </foreach> 

 

案例

 <select id="queryBlogForeach" parameterType="map" resultType="blog">
     select * from mybatis.blog
     <where>
         <!--遍历ids,每一项为id,以"and ("开头,以")"结尾,分隔符为"or"-->
         <foreach collection="ids" item="id" open="and (" close=")" separator="or">
         id =#{id}
         </foreach>
     </where>
 </select>
 HashMap map = new HashMap( );
 ArrayList<Integer> ids = new ArrayList<Integer>();
 ids.add(1);
 //.....
 map.put("ids",ids);
 List<Blog> blogs = mapper.queryBlogForeach(map);
 for (Blog blog : blogs) {
     System.out.printin(biog);
 }

 

6. SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便复用!

使用SQL标签抽取公共的部分

在需要使用的地方使用Include标签引用即可

注意事项

  • 最好基于单表来定义SQL片段

  • 不要存在where标签

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

 

建议: 现在Mysql中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可


 

13.缓存(了解)

查询 连接数据库 (占资源)

  • 一次查询结果,暂存在一个可以直接取到的地方 内存-->缓存

  • 再次查询相同数据时,直接走缓存,不用走数据库

  1. 什么是缓存[Cache ]?

    • 存在内存中的临时数据。

    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

  2. 为什么使用缓存?

    • 减少和数据库的交互次数,减少系统开销,提高系统效率。

  3. 什么样的数据能使用缓存?

    • 经常查询并且不经常改变的数据。【可以使用缓存】

1. MyBatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

  • MyBatis系统中默认定义了两级缓存 : 一级缓存和二级缓存

    • 默认情况下,只有一级缓存开启(sqlSession级别的缓存,也称为本地缓存)。

    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。

    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

2. 一级缓存

一级缓存也叫本地缓存: sqlSession

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。

  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

开启日志

映射语句文件中的所有select语句的结果将会被缓存。

映射语句文件中的所有insert、update和delete语句会刷新缓存

缓存会使用最近最少使用算法(LRU,Least Recently Used)算法来清除不需要的缓存。

缓存不会定时进行刷新(也就是说,没有刷新间隔)。

缓存会保存列表或对象(无论查询方法返回哪种)的1024个引用。

缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

缓存失效情况 :

  1. 查询不同东西

  2. 增删改

  3. 查询不同的Mapper

  4. 手动清理 SqlSession.clearCache();

小结 : 一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段

3. 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;

    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的―数据被保存到二级缓存中;

    • 新的会话查询信息,就可以从二级缓存中获取内容;

    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

提示 : 二级缓存是事务性的。这意味着,当SqlSession完成并提交时,或是完成并回滚,但没有执行fushCache=true 的insert/delete/update语句时,缓存会获得更新。

步骤:

  1. 开启全局缓存

     <setting name="cacheEnabled" value="true"/>

     

  2. 显示的开启二级缓存

     <select id="queryUserById" resultType="user" useCache="true">
         select * from user where id = #{id}
     </ select>

     

  3. 可以自定义参数

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

     

    这个更高级的配置创建了一个FIFO缓存,每隔600秒刷新,最多可以存储结果对象或列表的512个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

    可用清除策略:

    • LRU一最近最少使用 : 移除最长时间不被使用的对象。(默认)

    • FIFO一先进先出 : 按对象进入缓存的顺序来移除它们。

    • SOFT一软引用 : 基于垃圾回收器状态和软引用规则移除对象。

    • WEAK一弱引用 : 更积极地基于垃圾收集器状态和弱引用规则移除对象。

  4. 注意 : 我们需要将实体类序列化!否则就会报错!

    • 即实体类实现 Serializable接口

  • 只要开启了二级缓存,在同一个Mapper下就有效

  • 所有的数据都会先放在一级缓存中

  • 只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!

SSM_MyBatis_动态SQL_缓存

4. 自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

  1. 导包

  2. 在mapper中指定使用我们的ehcache缓存实现!

     <cache type="org.mybatis.caches.ehcache.EhcacheCache">

     

  3. 配置文件 ehcache.xml

Redis数据库来做缓存! K-V



SSM_MyBatis_动态SQL_缓存

上一篇:关于SQL事务的一些坑


下一篇:阿里云ECS服务器通用型g6和g5有哪些区别以及如何选择建议