返回顶部
首页 > 资讯 > 精选 >MyBatis动态SQL与缓存原理是什么
  • 785
分享到

MyBatis动态SQL与缓存原理是什么

2023-07-05 04:07:40 785人浏览 独家记忆
摘要

今天小编给大家分享一下mybatis动态sql与缓存原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。动态SQL为什么

今天小编给大家分享一下mybatis动态sql缓存原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

动态SQL

为什么叫做动态SQL:因为在程序执行中,mybatis提供的sql可以根据用户提供的字段数量、类型,合理的选择对应的执行sql。正是这一动态的选择特性,极大的优化了使用JDBC的代码冗余。

根据不同条件生成不同的sql语句执行

环境准备

以博客表为例:

create table `blog`(    `id` varchar(50) primary key comment '博客ID',    `title` varchar(100) not null comment '博客标题',    `author` varchar(50) not null comment '博客作者',    `create_time` datetime not null comment '创建时间',    `view` int not null comment '浏览量');

Blog实体:

@Data@AllArgsConstructorpublic class Blog {    private String id;    private String title;    private String author;    private Date creatTime;    private int views;}

IDutils,用于随机生成的ID名称

public static String getId(){  return UUID.randomUUID().toString().replaceAll("-","");}

IF语句

以上述搭建的环境为例,当我们需要查询博客时,如果用户指定了搜索搜索字段那就根据该字段查找,如果没有指定那就查询全部。如果用普通的sql语句实现,需要我们在Java程序中进行判断,但是MyBatis提供了动态SQL,我们就可以利用内置的IF标签来实现:

BlogMapper.xml配置

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

测试

@Testpublic void testGetBlogList(){  SqlSession sqlSession = MyBatisUtils.getSqlSession();  BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);  HashMap<String, Object> map = new HashMap<String, Object>();  map.put("title","Java");  map.put("author",null);  List<Blog> blogListIF = mapper.getBlogListIF(map);  for (Blog blog : blogListIF) {    System.out.println(blog);  }  sqlSession.commit();  sqlSession.close();}

此处采用模糊查询,在xml中直接对title和author字段进行判断,如果非空则执行拼接sql,反之查询全部

trim(where&Set) 

where

看下列代码:

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

此时当上述两个if满足任一时,sql拼接后变成:

select * from blog where and author = #{author}这是不符合sql语法规则的。对此MyBatis提供了where标签来处理这种情况。

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

where元素只会在它的任一子元素返回内容时,才会在sql中插入where子句。如果返回的sql开头为and 或on,where标签会自动将其抹去

set

sql中更新语句update在mybatis常用set标签来判定都需要更新哪些字段,如果用户设置了新的该字段属性,则会在set检测到,从而执行更新语句

并且set子句会动态的在行首添加上set关键字,包括删除额外的逗号

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

trim

trim包含四个属性:

prefix前缀、prefixOverrides前缀覆盖、suffix后缀、suffixOverrides后缀覆盖

当where和set不能得到预期的结果时,可以使用trim进行配置。也可以直接使用trim实现和where、set相同的效果:

<!-- trim实现set --><trim prefix="set" suffixOverrides=",">  <if test="title != null">    title = #{title},  </if>  <if test="author != null">    author = #{author},  </if></trim><!-- trim实现where --><trim prefix="where" prefixOverrides="and | or">  <choose>    <when test="title != null">      title = #{title}    </when>    <when test="author != null">      and author = #{author}    </when>    <otherwise>      and view != 0    </otherwise>  </choose></trim>

choose&when&otherwise

choose标签,类似于Java中的switch语句。当我们不想要执行全部的sql,而只是选择性的去执行对应的sql。

三者的关系类似于switch&ndash;>choose、case&ndash;>when、default&ndash;>otherwise

BlogMapper.xml编译sql

<select id="queryBloGChoose" parameterType="map" resultType="blog">  select * from blog  <where>    <choose>      <!--title不为null执行-->      <when test="title != null">        title = #{title}      </when>      <!--author不为null执行-->      <when test="author != null">        and author = #{author}      </when>      <!--默认执行-->      <otherwise>        and view != 0      </otherwise>    </choose>  </where></select>

sql片段

利用sql标签,抽离重复代码。在需要使用的地方使用include标签直接引入即可

<!-- 抽离sql --><sql id="checkTitleAuthor">  <if test="title != null">    title = #{title},  </if>  <if test="author != null">    author = #{author},  </if></sql><select id="getBlogListIF" parameterType="map" resultType="Blog">  select * from blog  <where>    <!-- 引入sql片段 -->    <include refid="checkTitleAuthor"/>  </where></select>

Foreach

利用Foreach可以在动态sql中对集合进行遍历

BlogMapper.xml

<select id="getBlogForeach" parameterType="map" resultType="blog">  select * from blog    <where>    <foreach collection="ids" item="id" open="(" separator="or" close=")">      id=#{id}    </foreach>  </where></select>

上述代码,利用map集合存储list集合交给foreach,此处collection通过键“ids”获取list,item为值,open为拼接sql的开始,close为拼接sql的结束,separator表示分隔符

缓存

什么是缓存?

缓存是存在于内存中的临时数据

使用缓存可以减少和数据库的交互次数,提高数据库性能和执行效率

官网给出:

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

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

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

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

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

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

一级缓存

也叫做本地缓存,对应MyBatis中的sqlSession。

一级缓存是默认开启的,作用域仅在sqlSession中有效

缓存示例

用户user表id查询两次相同数据示例:

@Select("select * from user where id = #{id}")Users getUserById(@Param("id") int id);// 测试public void testGetUsersList() {  SqlSession sqlSession = MyBatisUtils.getSqlSession();  UserMapper mapper = sqlSession.getMapper(UserMapper.class);  Users user1 = mapper.getUserById(2);  System.out.println(user1);  Users user2 = mapper.getUserById(2);  System.out.println(user2);  System.out.println(user1==user2);  sqlSession.close();}

打印效果分析:

MyBatis动态SQL与缓存原理是什么

上述程序分别调用两次getUserById方法,如果没有缓存机制那么最终应该会执行两次查询sql来返回数据,但是根据日志可以看到最终只执行了一次sql。 这说明,第一次查询到的数据就已经存放在了缓存当中,而第二次执行查询时将会直接从缓存中获取,不再进入sql层面查询。

看下面的示例:

<update id="updateUserInfo" parameterType="map" >  update user  <set>    <if test="name != null">      name = #{name},    </if>    <if test="pwd != null">      pwd = #{pwd},    </if>  </set>  where id = #{id}</update>
@Testpublic void testGetUsersList() {  SqlSession sqlSession = MyBatisUtils.getSqlSession();  UserMapper mapper = sqlSession.getMapper(UserMapper.class);  // 第一次查询id=2数据  Users user1 = mapper.getUserById(2);  System.out.println(user1);  System.out.println("-----------------------------------------------");  // 修改id=2数据  HashMap<String, Object> map = new HashMap<String, Object>();  map.put("name","冯七七");  map.put("id",2);  int i = mapper.updateUserInfo(map);  sqlSession.commit();  // 第二次查询id=2数据  Users user2 = mapper.getUserById(2);  System.out.println(user2);  System.out.println(user1==user2);  sqlSession.close();}

首先第一次查询数据,查询完之后调用修改方法将name修改为“ 冯七七 ” 然后再次执行查询语句

日志分析:

Created connection 594427726.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@236e3f4e]
-- 第一次执行查询sql  数据保存在sqlSession中
==>  Preparing: select * from user where id = ?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, 冯子, 234
<==      Total: 1
Users(id=2, name=冯子, pwd=234)
-----------------------------------------------
-- 修改刚刚查询的数据
==>  Preparing: update user SET name = ? where id = ?
==> Parameters: 冯七七(String), 2(Integer)
<==    Updates: 1
Committing JDBC Connection [com.Mysql.cj.jdbc.ConnectionImpl@236e3f4e]
-- 再次执行查询语句  查询刚刚修改过的数据
==>  Preparing: select * from user where id = ?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, 冯七七, 234
<==      Total: 1
Users(id=2, name=冯七七, pwd=234)
false-- 数据发生改变

得出结论,数据在执行select之后会将查询到的数据保存在缓存中,以便下次直接使用

对于增删改则会在完成之后刷新缓存,刷新之后如果需要获取数据智能再次查询数据库

缓存失效场景

  • 查询不同数据时,自然无法从缓存中直接拿到。

  • 增删改操作可能会改变原数据,所以一定会刷新缓存

  • 手动清理缓存:sqlSession.clearCache();

  • 创建不同的sqlSession对象查询

二级缓存

一级缓存是默认开启的,但是由于一级缓存作用域太低,所以诞生二级缓存

二级缓存就是全局缓存,它对应于一个namespace命名空间级别。只要开启了二级缓存,在用一个Mapper下就始终有效

工作机制:

  • 一个会话查询一条数据,查询成功后该数据会存放在一级缓存中

  • 如果当前会话关闭了,则其对应的一级缓存消失。

  • 如果开启了二级缓存,那么一级缓存消失后,其中的数据就会被保存到二级缓存中

  • 当新开的会话去查询同一数据时,就会从二级缓存中拿到

开启全局缓存

cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。

有效值true | false 默认值 true

但通常我们会在settings中显式的开启

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

然后需要在想要使用二级缓存的Mapper.xml文件中配置cache

<!-- 开启 使用默认参数 --><cache/><!-- 自定义参数 --><cache       eviction="FIFO"       flushInterval="60000"       size="512"       readOnly="true"/>

上述eviction是指驱逐策略,FIFO先进先出,按照对象进入缓存的顺序移出

flushInterval为刷新缓存的间隔时间,size为最大缓存容量,readOnly是否设置为只读

二级缓存示例

要注意的一点是,只有在一级缓存销毁之后。sqlSession才会将它缓存的东西交给二级缓存

// 测试二级缓存@Testpublic void testGetUserById(){  // 创建两个sqlSession会话  SqlSession sqlSession1 = MyBatisUtils.getSqlSession();  SqlSession sqlSession2 = MyBatisUtils.getSqlSession();  // selSession1查询一次  UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);  Users user = mapper1.getUserById(2);  System.out.println(user);  sqlSession1.close();// 关闭sqlSession1  System.out.println("---------------------------------------------");  // selSession2查询与sqlSession相同的数据  UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);  Users user1 = mapper2.getUserById(2);  System.out.println(user1);  System.out.println(user==user1);  sqlSession2.close();}

打印日志如下:

Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55536d9e]
-- sqlSession1执行sql查询数据
==>  Preparing: select * from user where id = ?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, 冯七七, 234
<==      Total: 1
Users(id=2, name=冯七七, pwd=234)
-- 回收sqlSession1到链接池
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55536d9e]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@55536d9e]
Returned connection 1431530910 to pool.
---------------------------------------------
Cache Hit Ratio [com.yuqu.dao.UserMapper]: 0.5
-- sqlSession查询数据结果
Users(id=2, name=冯七七, pwd=234)
true

很明显,sqlSession1查询到的数据首先保存在了自己的缓存中,也就是一级缓存。那么关闭sqlSession1之后,数据被交给到二级缓存。此时sqlSession再次查询相同数据,则会直接在二级缓存中拿到

一个问题:

上文提到了妖使用二级缓存则必须在对应的Mapper.xml文件中配置cache标签。一种是隐式参数第一种,采用这种方式,就必须让实体类pojo实现serializable接口,否则会报出异常

java.io.NotSerializableException: com.yuqu.pojo.Users

如果采用自定义参数形式,就不需要实现Serializable接口。因为cache中有一个参数为eviction驱逐策略直接就规定了缓存中的数据读/写的规则。

但是通常无论是否采用自定义参数,都会将实体类实现序列化接口

以上就是“MyBatis动态SQL与缓存原理是什么”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: MyBatis动态SQL与缓存原理是什么

本文链接: https://lsjlt.com/news/349447.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • MyBatis动态SQL与缓存原理是什么
    今天小编给大家分享一下MyBatis动态SQL与缓存原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。动态SQL为什么...
    99+
    2023-07-05
  • MyBatis一级缓存与二级缓存原理与作用是什么
    这篇“MyBatis一级缓存与二级缓存原理与作用是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MyBatis一级缓存与...
    99+
    2023-07-04
  • MyBatis中动态SQL的工作原理是什么
    MyBatis中动态SQL的工作原理是利用XML配置文件中的各种标签和属性来动态构建SQL语句。通过在XML配置文件中使用if、ch...
    99+
    2024-04-23
    MyBatis
  • mybatis二级缓存的原理是什么
    MyBatis的二级缓存是指缓存在SqlSessionFactory级别的缓存,可以被多个SqlSession共享。其原理如下:1....
    99+
    2023-10-09
    mybatis
  • MyBatis 动态SQL使用及原理
    目录引言1. 动态SQL概述2. if标签3. choose、when和otherwise标签4. trim标签5. set标签和where标签6. foreach7. b...
    99+
    2023-05-20
    MyBatis 动态SQL MyBatis 动态SQL
  • 什么是MyBatis缓存
    这篇文章主要介绍“什么是MyBatis缓存”,在日常操作中,相信很多人在什么是MyBatis缓存问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”什么是MyBatis缓存”的疑惑...
    99+
    2024-04-02
  • Mybatis 动态sql的编写|开启二级缓存
    ❤️作者主页:微凉秋意 ✅作者简介:后端领域优质创作者🏆,CSDN内容合伙人🏆,阿里云专家博主🏆 ✨精品专栏:数据结构与课程设计 🔥...
    99+
    2023-09-22
    mybatis sql java 数据库
  • MyBatis 动态SQL和缓存机制实例详解
    有的时候需要根据要查询的参数动态的拼接SQL语句常用标签:- if:字符判断- choose【when...otherwise】:分支选择- trim【where,set】:字符串截取,其中where标签封装查询条件,s...
    99+
    2023-05-31
    mybatis 动态sql 缓存机制
  • MyBatis一级缓存与二级缓存原理与作用分析
    目录缓存的作用MyBatis 的缓存结构一级缓存二级缓存缓存的作用 在 Web 系统中,最重要的操作就是查询数据库中的数据。但是有些时候查询数据的频率非常高,这是很耗费数据库资源的,...
    99+
    2022-12-27
    Mybatis 一级缓存 Mybatis 二级缓存 MyBatis一级缓存和二级缓存
  • Redis缓存原理是什么
    这篇文章将为大家详细讲解有关Redis缓存原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. Redis是什么Redis 是一个高性能的开源的、C语言写的Nos...
    99+
    2024-04-02
  • ehcache缓存原理是什么
    Ehcache 是一个开源的Java缓存框架,它提供了内存缓存和磁盘缓存的功能,并且具有快速、可扩展和灵活的特性。Ehcache 的...
    99+
    2023-09-13
    ehcache
  • MyBatis动态SQL编写的方法是什么
    MyBatis动态SQL编写的方法有以下几种:1. 使用XML配置文件:可以在XML配置文件中使用if、choose、when、ot...
    99+
    2023-09-29
    MyBatis SQL
  • Mybatis的一级缓存和二级缓存原理分析与使用
    目录Mybatis的一级缓存和二级缓存1 Mybatis如何判断两次查询是完全相同的查询2 二级缓存2.1 二级缓存配置2.2 二级缓存特点2.3 配置二级缓存2.4 测试Mybat...
    99+
    2024-04-02
  • mybatis一级缓存和二级缓存是什么
    mybatis一级缓存和二级缓存是mybatis提供的两种不同层次的缓存机制,一级缓存是mybatis中默认开启的缓存机制,它是基于线程的本地缓存,二级缓存是基于namespace级别的缓存,可以被多个SqlSession对象共享。本教程操...
    99+
    2023-08-09
  • Mybatis防止sql注入原理是什么
    这篇文章主要讲解了“Mybatis防止sql注入原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatis防止sql注入原理是什么”吧!Mybatis防止sql注入原理SQL 注...
    99+
    2023-06-22
  • MyBatis中动态SQL拼接的方法是什么
    MyBatis中动态SQL拼接的方法主要是使用if、choose、when、otherwise等标签来实现动态条件拼接。具体来说,可...
    99+
    2024-04-08
    MyBatis
  • webpack动态import原理是什么
    今天小编给大家分享一下webpack动态import原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。例子//&nbs...
    99+
    2023-06-30
  • Java Mybatis一级缓存和二级缓存是什么
    本篇内容主要讲解“Java Mybatis一级缓存和二级缓存是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java Mybatis一级缓存和二级缓存是什么”吧!一、什么...
    99+
    2023-07-05
  • MySQL数据库缓存原理是什么
    今天就跟大家聊聊有关MySQL数据库缓存原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。  MySQL数据库查询步骤有哪些  当MySQL收...
    99+
    2024-04-02
  • 缓存服务器的原理是什么
    缓存服务器的原理是:缓存服务器的应用模式主要是正向代理和反向代理,正向代理的工作原理是客户端将要直接发送到internet上源服务器的连接请求发送给代理服务器处理;反向代理的工作原理是将用户的请求和应用服务器应答的内容写入缓存服务器中,为后...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作