【精选必看】MyBatis映射文件及动态SQL,一级,二级缓存介绍

news2024/11/28 4:51:20

文章目录

MyBatis映射文件

在这里插入图片描述

< r e s u l t M a p > <resultMap> <resultMap>

MyBatis映射文件中除了<insert><delete><update><select>外,还有一些标签可以使用:

resultMap

标签的作用的自定义映射关系。

MyBatis可以将数据库结果集封装到对象中,是因为结果集的列名和对象属性名相同:

当POJO属性名和数据库列名不一致时,MyBatis无法自动完成映射关系。

此时有两种解决方案:

  1. Sql语句的查询字段起与POJO属性相同的别名。

    <select id="findAll" resultType="com.mybatis.pojo.Teacher">
       select tid as id,tname as teacherName from teacher;
    </select>
    
  2. 自定义映射关系

    • 在映射文件中,使用<resultMap>自定义映射关系:
    <!-- id:自定义映射名 type:自定义映射的对象类型  -->
    <resultMap id="teacherMapper" type="com.mybatis.pojo.Teacher">
      <!-- id定义主键列  property:POJO属性名 column:数据库列名  -->
      <id property="id" column="tid"></id>
      <!-- result定义普通列  property:POJO属性名 column:数据库列名  -->
      <result property="teacherName" column="tname"></result>
    </resultMap>
    
    • <select>标签中,使用resultMap属性代替resultType属性,使用自定义映射关系。
    <select id="findAll" resultMap="teacherMapper">
       select * from teacher
    </select>
    

< sql>&< include>

<sql>用来定义可重用的Sql片段,通过<include>引入该片段。如:Sql语句的查询字段起与POJO属性相同的别名,该Sql片段就可以重用。

<sql id="selectAllField">
   select tid as id,tname as teacherName
</sql>


<select id="findAll" resultType="com.mybatis.pojo.Teacher">
  <include refid="selectAllField"></include>
   from teacher;
</select>


<select id="findById" resultType="com.mybatis.pojo.Teacher">
  <include refid="selectAllField"></include>
   from teacher where tid = #{id}
</select>

特殊字符处理

在Mybatis映射文件中尽量不要使用一些特殊字符,如:<>等。

我们可以使用符号的实体来表示:(带后面的分号)

符号实体
<& lt;
>& gt;
&& amp;
& apos;
& quot;

如:

<select id="findById2" resultType="com.mybatis.pojo.Teacher">
  <include refid="selectAllField"></include>
   from teacher where tid &gt; #{id}
</select>

动态SQL

在这里插入图片描述

一个查询的方法的Sql语句不一定是固定的。比如电商网站的查询商品,用户使用不同条件查询,Sql语句就会添加不同的查询条件。此时就需要在方法中使用动态Sql语句。

< i f > < if> <if>

<if>标签内的Sql片段在满足条件后才会添加,用法为:<if test="条件">。例如:根据不同条件查询用户:

  1. 持久层接口添加方法

    // 用户通用查询
    List<User> findByCondition(User user);
    
  2. 映射文件添加标签

    <select id="findByCondition" parameterType="com.mybatis.pojo.User" resultType="com.mybatis.pojo.User">
       select * from user where 1 = 1
      <if test="username != null and username.length() != 0">
         and username like #{username}
      </if>
      <if test="sex != null and sex.length() != 0">
         and sex = #{sex}
      </if>
      <if test="address != null and address.length() != 0">
         and address = #{address}
      </if>
    </select>
    
  3. 编写测试方法

    @Test
    public void testFindByCondition(){
      User user = new User();
      List<User> users1 = userMapper2.findByCondition(user);
      //users1.forEach(System.out::println);
    
    
      user.setUsername("%张三%");
      List<User> users2 = userMapper2.findByCondition(user);
      users2.forEach(System.out::println);
    
    
      user.setAddress("北京");
      List<User> users3 = userMapper2.findByCondition(user);
      users3.forEach(System.out::println);
    }
    
  1. if中的条件不能使用&&/||,而应该使用and/or

  2. if中的条件可以直接通过属性名获取参数POJO的属性值,并且该值可以调用方法。

  3. where后为什么要加1=1?

    任意条件都可能拼接到Sql中。如果有多个条件,从第二个条件开始前都需要加And关键字。加上1=1这个永久成立的条件,就不需要考虑后面的条件哪个是第一个条件,后面的条件前都加And关键字即可。

< w h e r e > <where> <where>

<where>可以代替sql中的where 1=1 和第一个and,更符合程序员的开发习惯,使用<where>后的映射文件如下:

<select id="findByCondition" resultType="com.mybatis.user.User" parameterType="com.mybatis.user.User">
   select * from user
  <where>
    <if test="username != null and username.length() != 0">
       username like #{username}
    </if>
    <if test="sex != null and sex.length() != 0">
       and sex = #{sex}
    </if>
  </where>
</select>

< s e t > <set> <set>

<set>标签用在update语句中。借助<if>,可以只对有具体值的字段进行更新。<set>会自动添加set关键字,并去掉最后一个if语句中多余的逗号。

<update id="update" parameterType="com.mybatis.user.User">
   update user
  <set>
    <if test="username != null and username.length() > 0">
       username = #{username},
    </if>
    <if test="sex != null and sex.length() > 0">
       sex = #{sex},
    </if>
  </set>
  <where>
     id = #{id}
  </where>
</update>

< c h o o s e > < choose> <choose> < w h e n > < when> <when> < o t h e r w i s e > < otherwise> <otherwise>

这些标签表示多条件分支,类似JAVA中的switch...case<choose>类似switch<when>类似case<otherwise>类似default,用法如下:

<select id="findByCondition" resultType="com.mybatis.user.User" parameterType="com.mybatis.user.User">
   select * from user
  <where>
    <choose>
      <when test="username.length() &lt; 5">
         username like #{username}
      </when>
      <when test="username.length() &lt; 10">
         username = #{username}
      </when>
      <otherwise>
         id = 1
      </otherwise>
    </choose>
  </where>
</select>

这段代码的含义为:用户名<5时使用模糊查询,用户名>=5并且<10时使用精确查询,否则查询id为1的用户

< f o r e a c h > <foreach> <foreach>

<foreach>类似JAVA中的for循环,可以遍历集合或数组。<foreach>有如下属性:

  • collection:遍历的对象类型
  • open:开始的sql语句
  • close:结束的sql语句
  • separator:遍历每项间的分隔符
  • item:表示本次遍历获取的元素,遍历List、Set、数组时表示每项元素,遍历map时表示键值对的值。
  • index:遍历List、数组时表示遍历的索引,遍历map时表示键值对的键。
遍历数组

我们使用<foreach>遍历数组进行批量删除。

  1. 持久层接口添加方法

    void deleteBatch(int[] ids);
    
  2. 映射文件添加标签

    <delete id="deleteBatch" parameterType="int">
       delete from user
      <where>
        <foreach open="id in(" close=")" separator="," collection="array" item="id" >
           #{id}
        </foreach>
      </where>
    </delete>
    
  3. 编写测试方法

    @Test
    public void testDeleteBatch(){
      int[] ids = {9,11};
      userMapper.deleteBatch(ids);
      session.commit();
    }
    
遍历Collection

<foreach>遍历List和Set的方法是一样的,我们使用<foreach>遍历List进行批量添加。

  1. 持久层接口添加方法

    void insertBatch(List<User> users);
    
  2. 映射文件添加标签

    <insert id="insertBatch" parameterType="com.mybatis.user.User">
       insert into user values
      <foreach collection="list" item="user" separator=",">
         (null ,#{user.username},#{user.sex},#{user.address})
      </foreach>
    </insert>
    
  3. 编写测试方法

    @Test
    public void testInsertBatch(){
      User user1 = new User("程序员1", "男", "北京");
      User user2 = new User("程序员2", "女", "上海");
      List<User> users = new ArrayList();
      users.add(user1);
      users.add(user2);
    
    
      userMapper2.insertBatch(users);
      session.commit();
    }
    
遍历Map

我们使用<foreach>遍历Map进行多条件查询。

  1. 持久层接口添加方法

    /**
       * 多条件查询
       * @param map 查询的条件键值对 键:属性名 值:属性值
       * @return
       */
    List<User> findUser(@Param("queryMap") Map<String,Object> map);
    
  2. 映射文件添加标签

    <select id="findUser" parameterType="map" resultType="com.mybatis.pojo.User">
       select * from user
      <where>
        <foreach collection="queryMap" separator="and" index="key" item="value">
           ${key} = #{value}
        </foreach>
      </where>
    </select>
    
  3. 编写测试方法

    @Test
    public void testFindUser(){
      Map<String,Object> queryMap = new HashMap();
      queryMap.put("sex","男");
      queryMap.put("address","北京");
      List<User> users = userMapper2.findUser(queryMap);
      users.forEach(System.out::println);
    }
    

MyBatis缓存

在这里插入图片描述

缓存介绍

缓存是内存当中一块存储数据的区域,目的是提高查询效率。MyBatis会将查询结果存储在缓存当中,当下次执行相同的SQL时不访问数据库,而是直接从缓存中获取结果,从而减少服务器的压力。

  • 什么是缓存?

    存在于内存中的一块数据。

  • 缓存有什么作用?

    减少程序和数据库的交互,提高查询效率,降低服务器和数据库的压力。

  • 什么样的数据使用缓存?

    经常查询但不常改变的,改变后对结果影响不大的数据。

  • MyBatis缓存分为哪几类?

    一级缓存和二级缓存

  • 如何判断两次Sql是相同的?

    1. 查询的Sql语句相同
    2. 传递的参数值相同
    3. 对结果集的要求相同
    4. 预编译的模板Id相同

MyBatis一级缓存

  • MyBatis一级缓存也叫本地缓存。SqlSession对象中包含一个Executor对象,Executor对象中包含一个PerpetualCache对象,在该对象存放一级缓存数据。
  • 由于一级缓存是在SqlSession对象中,所以只有使用同一个SqlSession对象操作数据库时才能共享一级缓存
  • MyBatis的一级缓存是默认开启的,不需要任何的配置。
测试一级缓存
@Test
public void testCache1() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session = factory.openSession();


  // 使用同一个SqlSession查询
  UserMapper mapper1 = session.getMapper(UserMapper.class);
  UserMapper mapper2 = session.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
  System.out.println(user2.hashCode());
}


@Test
public void testCache2() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session1 = factory.openSession();
  SqlSession session2 = factory.openSession();


  // 使用不同的SqlSession查询
  UserMapper mapper1 = session1.getMapper(UserMapper.class);
  UserMapper mapper2 = session2.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
  System.out.println(user2.hashCode());
}

MyBatis清空一级缓存

进行以下操作可以清空MyBatis一级缓存:

  1. SqlSession调用close():操作后SqlSession对象不可用,该对象的缓存数据也不可用。
  2. SqlSession调用clearCache()/commit():操作会清空一级缓存数据。
  3. SqlSession调用增删改方法:操作会清空一级缓存数据,因为增删改后数据库发生改变,缓存数据将不准确。
@Test
public void testCache3() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session = factory.openSession();


  UserMapper mapper1 = session.getMapper(UserMapper.class);
  UserMapper mapper2 = session.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  //     session.close();
  //     session.clearCache();
  //     session.commit();
  mapper1.delete(2);
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
  System.out.println(user2.hashCode());
}

MyBatis二级缓存

  • MyBatis二级缓存也叫全局缓存。数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般在项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的。

  • MyBatis一级缓存存放的是对象,二级缓存存放的是对象的数据。所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口。

  • MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中。

    SqlSession调用clearCache()无法将数据存到二级缓存中。

开启二级缓存
  1. POJO类实现Serializable接口。

    public class User implements Serializable {
      private int id;
      private String username;
      private String sex;
      private String address;
    }
    
    
  2. 在MyBatis配置文件添加如下设置:

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

    由于cacheEnabled默认值是true,所以该设置可以省略。

  3. 在映射文件添加<cache />标签,该映射文件下的所有方法都支持二级缓存。

    如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过<cache />标签的size属性修改该数量。

    <cache size="2048"/>
    
  4. 测试二级缓存

    @Test
    public void testCache4() throws IOException {
      InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
      SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
      SqlSessionFactory factory = builder.build(is);
      SqlSession session1 = factory.openSession();
      SqlSession session2 = factory.openSession();
    
    
      UserMapper mapper1 = session1.getMapper(UserMapper.class);
      UserMapper mapper2 = session2.getMapper(UserMapper.class);
    
    
      User user1 = mapper1.findById(1);
      System.out.println(user1);
      System.out.println(user1.hashCode());
      // 让一级缓存失效
      session1.commit();
      System.out.println("-------------------------------------------");
    
    
      User user2 = mapper2.findById(1);
      System.out.println(user2);
      System.out.println(user2.hashCode());
    }
    
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1254436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

叠加原理(superposition principle)、线性系统

叠加原理&#xff08;superposition principle&#xff09;&#xff1a;指对一个系统而言&#xff0c;两个或多个输入产生的输出&#xff0c;等于这几个输入单独引起的输出的和&#xff0c;即输入的叠加等于各输入单独引起的输出的叠加。 线性系统&#xff1a;一个系统&#x…

SAP Smartform小结

SAP系统做打印单据用的, 感觉很不好用, 特别是要嵌入韩文时必须使用嵌入的word编辑器,运行速度简直不可忍受. 见过一些Adobe interactive form的示例, 看着相当不错, 不过据说需要花money额外买licence, 哪有smartform这种免费东西来得实惠. 一般打印需求,会要求有标题抬头,打…

【开源】基于Vue+SpringBoot的农家乐订餐系统

项目编号&#xff1a; S 043 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S043&#xff0c;文末获取源码。} 项目编号&#xff1a;S043&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户2.2 管理员 三、系统展示四、核…

CSDN助手:一键下载CSDN博客:高效保存,随时阅读

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f3e1; 环境 &#x1f3e1;&#x1f4d2; 使用方法 &#x1f4d2;⚓️ 相关链接 ⚓️ &#x1f4d6; 介绍 &#x1f4d6; 这是我自己无聊的时候写的一个应用&#xff0c;以前UI有点丑&#xff0c;这次重写了一下UI 功能如下 …

球面的表面积

此推导需要用到重积分的知识&#xff0c;另外关于曲面的面积公式可以看我之前的博客

过滤器的应用

javaWeb三剑客: 1. Servlet:接收请求,处理请求(单例,也就是说&#xff0c;多个用户请求的的servlet是同一个对象) 2. Filter:拦截请求(单例->也就是说&#xff0c;多个用户请求的的filter是同一个对象) 3. Listem: 监听用户/服务器行为,javaWeb三剑客: 过滤器的实现 1&…

24. 深度学习进阶 - 矩阵运算的维度和激活函数

Hi&#xff0c;你好。我是茶桁。 咱们经过前一轮的学习&#xff0c;已经完成了一个小型的神经网络框架。但是这也只是个开始而已&#xff0c;在之后的课程中&#xff0c;针对深度学习我们需要进阶学习。 我们要学到超参数&#xff0c;优化器&#xff0c;卷积神经网络等等。看…

用xlwings新建一个excel并同时生成多个sheet

新建一个excel并同时生成多个sheet&#xff0c;要实现如下效果&#xff1a; 一般要使用数据透视表来快速实现。 今天记录用xlwings新建一个excel并同时生成多个sheet。 import xlwings as xw # 打开excel,参数visible表示处理过程是否可视,add_book表示是否打开新的Excel程序…

电子学会C/C++编程等级考试2022年12月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:数组逆序重放 将一个数组中的值按逆序重新存放。例如,原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。输入 输入为两行:第一行数组中元素的个数n(1输出 输出为一行:输出逆序后数组的整数,每两个整数之间用空格分隔。样例输入 …

摆脱无用代码的负担:TreeShaking 的魔力

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

QGIS安装及简单使用

QGIS&#xff08;Quantum GIS&#xff09;是一个自由、开源的跨平台桌面地理信息系统&#xff08;GIS&#xff09;应用程序&#xff0c;它允许用户创建、编辑、查看、分析和发布地理空间数据和地图。 操作系统&#xff1a;Windows 10 QGIS版本&#xff1a;QGIS Desktop 3.28.…

2023年03月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 计算“2+4+8+……+128”,用变量n表示每项,根据变化规律,变量n的赋值用下列哪个最合适?( ) A: B: C: D: 答案:D

[Linux]进程创建➕进程终止

文章目录 1.再谈fork()函数1.1fork()创建子进程 OS都做了哪些工作?1.2对上述问题的理解1.3写时拷贝进行父子进程分离的优势1.4了解eip寄存器和pc1.5了解进程的上下文数据1.6对计算机组成的理解1.7fork常规用法1.8fork调用失败的原因 2.进程终止2.1进程终止时操作系统要做的工作…

offer 选择难?说说我的 2 个思考

大家好&#xff0c;我是鱼皮。秋招仍在进行中&#xff0c;随着越来越多的公司开奖&#xff0c;最近 编程导航星球 的小伙伴们也陆续发来了 offer 报喜&#xff1a; 图片 图片 但也有一部分小伙伴陷入了 “甜蜜的烦恼”&#xff0c;拿了几个 offer 却不知道怎么选择。 offer 选择…

【深入剖析K8s】容器技术基础(一):从进程开始说起

容器其实是一种特殊的进程而已。 可执行镜像 为了能够让这些代码正常运行’我们往往还要给它提供数据’比如我们这个加法程序所需要的输人文件这些数据加上代码本身的二进制文件放在磁盘上’就是我们平常所说的一个程序,也叫代码的可执行镜像&#xff08;executablejmage&…

路径规划之A*算法

系列文章目录 路径规划之Dijkstra算法 路径规划之Best-First Search算法 路径规划之A*算法 路径规划之A*算法 系列文章目录前言一、前期准备1.1 算法对比1.2 数学式方法1.3 启发式方法 二、A*算法2.1 起源2.2 思想2.3 启发式函数2.4 过程2.5 案例查看 前言 之前提过Dijkstra算…

2018年2月16日 Go生态洞察:Go 1.10版本发布分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

2017年11月16日 Go生态洞察:Go用户调查深度解析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

BeanUtil的正确使用方式

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 在实际的开发中&#xff0c;我们常常会用到工具类去拷贝对象的属性&#xff0c;将一个对象的属性转换成另外一个…

机器人开发的选择

喷涂机器人 码垛机器人 纸箱码垛机器人 焊接机器人 跳舞机器人 管道清理机器人 工地巡检机器人 点餐机器人 化工巡检机器人 装箱机器人 安防巡检机器人 迎宾机器人好像有点像软银那个 污水管道检测机器人 大酒店用扫地机器人 家用扫地机器人 工厂用&#xff08;…