Mybatis框架(六)

十二、动态SQL

什么是动态SQL:动态SQL是指 根据不同的条件生成不同的SQL语句

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

if
choose (when, otherwise)
trim (where, set)
foreach

搭建环境

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

创建一个基础工程

1、导包

2、编写配置文件

3、编写实体类

@Data
public class Blog {
    private int id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

4、编写实体类对应的Mapper接口 和 Mapper.xml文件

@SuppressWarnings("all")抑制警告

1、IF

接口类

public interface BlogMapper {
//    查询博客
    List<Blog> queryBlogIF(Map map);
}

Mapper.xml

where 1=1是为了解决 and 的问题,

后面会使用 <where>代替,会自动取消后续的 and

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>

测试类

 @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        map.put("title","Java如此简单");
        map.put("author", "狂神说2");
        List<Blog> blog = mapper.queryBlogIF(map);

        for(Blog blog1 : blog ){
            System.out.println(blog1);
        }
        sqlSession.close();
    }

2、choose (when, otherwise)

而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的switch语句。

传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员挑选的 Blog)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
               and author = #{author}
            </when>
            <otherwise>
                and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

3、trim (where, set)

WHERE

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog 
        <where>
            <if test="title != null">
                 title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if> 
        </where>
    </select>

通过自定义 trim 元素来定制 where 元素的功能

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

set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。

set 元素会动态地在行首插入 SET 关键字并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

set 元素等价的自定义 trim 元素

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

所谓的动态 SQL ,本质上还是SQL语句,只是我们可以在SQL 层面 ,去执行一个逻辑代码。

4、SQL片段

有的时候我们可能需要将一些功能抽取出来,公用。

步骤

使用SQL标签抽取公共部分

    <sql id="if-title-author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </sql>

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

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
           <include refid="if-title-author"></include>
        </where>
    </select>
注意事项:
  • 最好基于单表来定义 SQL 片段
  • 不要存在 where 标签

forEach

(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20200810092812989.png)]

<!--    我们现在可以传一个万能的map,这个map中可以存在一个集合-->
    <select id="queryBlogforeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

测试类

    @Test
    public void queryBlogForeach(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        ArrayList<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(2);
        hashMap.put("ids",ids);
        mapper.queryBlogforeach(hashMap);
        sqlSession.close();
    }

动态SQL就是在拼接SQL语句,我们只要保证SQL 正确性,按照SQL的格式,去排列组合就可以了。

十三、缓存

1、介绍

查询 == > 连接数据库,消耗资源

一次查询的结果,给他暂存一个可以直接 取到的地方——内存:缓存

我们再次查询相同的数据时的时候,可以直接走缓存,就不用走数据库了。

什么是缓存

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

为什么要使用缓存

  • 减少数据库的交互此时,减少系统开销,提高系统效率

什么样的数据能使用缓存

  • 经常查询并且不会经常的改变的数据

2、一级缓存

  • 一级缓存也叫本地缓存——SqlSession
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,没有必要再去数据库查询。

测试步骤

  • 开启日志
  • 测试在一个 Sesion 中查询两次相同的记录
  • 查看日志输出

**如下可以看到,查询同一条数据的时候,只需要打开一次 JDBC。 **
在这里插入图片描述

缓存失效的情况
  • 增删改操作可能会改变 原来的数据,所以必定会刷新缓存!
  • 查询不同的东西
  • 查询不同的mapper.xml
  • 手动清理缓存sqlSession.clearCache();
小结
  • 一级缓存默认是开启的,只在一次SQLSession中有效,也就是拿到连接到关闭连接内有效【一级缓存可以看成Map】
  • 页面的每次刷新相当于 新建 SqlSession

3、二级缓存

  • 二级缓存也叫做全局缓存,一级缓存作用域太低,所以诞生了二级缓存
  • 基于namespace 级别的缓存,一个名称空间,对应一个二级缓存。
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果关闭了当前会话,这个会话对应的一级缓存也就没有了;但是我们打开二级缓存后,会话关闭了,一级缓存中的数据保存在二级缓存中;
    • 新的会话查询数据,就可以从二级缓存中获取内容;
    • 不同的mapper 查出的数据会放在自己对应的缓存(map)中

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

<!--在当前 Mapper.xml 中使用 二级缓存-->
<cache/>
<!--可以关闭单个的缓存-->
    <select id="queryUserById" resultType="user" useCache="false">
        select * from user where id = #{id}
    </select>

二级缓存参数配置

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

在这里插入图片描述

步骤
  • 开启全局缓存【默认是开启的】
<setting name="cacheEnabled" value="true"/>

在这里插入图片描述

  • 在要使用二级缓存的Mapper中开启
<!--在当前 Mapper.xml 中使用 二级缓存-->
<cache/>

也可以自定义参数

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

问题:我需要将实体类 序列化,否则报错:

Caused by: java.io.NotSerializableException: com.lsw.pojo.User
//   implements Serializable
public class User implements Serializable {
    private int id;
    private  String name;
    private String pwd;
}

小结:
  • 只要开启了二级缓存,在同一个Mapper下就会有效
  • 所有的数据都会先放在 一级缓存中
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中

4、mybatis缓存原理

缓存顺序
  • 先看二级缓存中有没有数据
    • 有数据——>直接取出数据
    • 没有数据——>进入一级缓存中查看
  • 再看一级缓存中有没有数据
    • 有数据——取出数据
    • 没有数据——>查找数据库
  • 查找数据库

在这里插入图片描述

5、自定义缓存—ehcache

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点

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

要在 程序中使用——导包

   <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
   </dependency>

主流的缓存

Redis数据库来做缓存,非关系型数据库 K-V 键值对

mybatis 初步的学习就到这里了,如果你也想详细的学习 mybatis 框架,请到这里 狂神说Java

猜你喜欢

转载自blog.csdn.net/weixin_43866812/article/details/108431116