当前位置: 首页 > news >正文

【框架学习 | 第一篇】一篇文章读懂MyBatis

文章目录

  • 1.Mybatis介绍
    • 1.1Mybatis历史
    • 1.2Mybatis特点
    • 1.3与其他持久化框架对比
    • 1.4对象关系映射——ORM
  • 2.搭建Mybatis
    • 2.1引入依赖
    • 2.2创建核心配置文件
    • 2.3创建表、实体类、mapper接口
    • 2.4创建映射文件
      • 2.4.1映射文件命名位置规则
      • 2.4.2编写映射文件
      • 2.4.3修改核心配置文件中映射文件路径
    • 2.5Junit测试
    • 2.6修改、删除、查询功能测试
  • 3.核心配置文件详讲(了解)
    • 3.1environment、properties讲解
    • 3.2typeAliases讲解
    • 3.3mappers
      • 3.3.1将UserMapper.xml转移到新目录下
      • 3.3.2在核心配置文件中引入映射文件
  • 4.MyBatis获取参数值的两种方式(重要)
    • 4.1区分${}和#{}
      • 4.4.1区分点
      • 4.4.2预编译过程
      • 4.4.3 ${}的sql注入问题
    • 4.2获取参数值的各种情况
      • 4.2.1情况一:参数为单个的字面量类型
      • 4.2.2情况二:参数为多个时
        • (1)使用原生的map
        • (2)使用自己的map(${}、#{})
      • 4.2.3参数是实体类类型的参数
      • 4.2.4使用@Param注解命名参数(以这个和实体类类型两种情况为标准)
    • 4.3举例
      • 4.3.1mapper接口
      • 4.3.2映射文件
      • 4.3.3测试
    • 4.4小结
    • 4.5@Param标识的源码解析
  • 5.MyBatis的各种查询功能
    • 5.1查询的数据只有一条
      • 5.1.1接收情况
      • 5.1.2举例
    • 5.2查询的数据有多条
    • 5.3查询单个数据(聚合函数)
  • 6.特殊SQL的执行
    • 6.1模糊查询
    • 6.2批量删除
    • 6.3动态设置表名(会出现sql注入问题)
    • 6.4添加功能获取自增的主键
  • 7.自定义映射resultMap
    • 7.1搭建mybatis框架
    • 7.2字段名和属性名不一致
      • 7.2.1给字段名起别名
      • 7.2.2全局配置mapUnderscoreToCamelCase
      • 7.2.3resultMap(建议使用)
    • 7.3多对一(从员工到部门)映射关系
      • 7.3.1通过级联属性(连接查询)赋值
      • 7.3.2通过association标签
      • 7.3.3通过分步查询(推荐)
        • (1)通过id查询员工信息、并查出did
        • (2)通过did查询员工所对应的部门
        • (3)测试
      • 7.3.4分步查询的好处:延迟加载
        • (1)开启延迟加载之前
        • (2)开启全局延迟加载之后
        • (3)可以局部关闭延迟加载
    • 7.4.一对多映射关系
      • 7.4.1通过collection解决一对多映射关系
  • 8.动态SQL
    • 8.1if-where-trim标签
      • 8.1.1if标签
      • 8.1.2where标签
      • 8.1.3trim标签
    • 8.2choose-when-ohterwise标签
    • 8.3.foreach标签
      • 8.3.1实现批量删除方式一
      • 8.3.2实现批量删除方式二
      • 8.3.3实现批量添加
    • 8.4SQL标签
  • 9.MyBatis缓存
    • 9.1介绍
      • 9.1.1一级缓存
      • 9.1.2二级缓存
    • 9.2一级缓存
      • 9.2.1一级缓存生效(默认生效)
      • 9.2.2一级缓存失效
    • 9.3二级缓存
      • 9.3.1二级缓存开启
      • 9.3.2二级缓存失效
      • 9.3.3二级缓存的相关配置
    • 9.4缓存查询的顺序
  • 10_MyBaits的逆向工程
    • 10.1创建逆向工程的步骤
    • 10.2豪华尊享版两种函数的区别
    • 10.3QBC查询
    • 10.4QBC修改
  • 11_MyBatis分页
    • 11.1使用步骤
    • 11.2使用

在这里插入图片描述

框架系列第一篇主要围绕MyBatis展开,从MyBatis介绍、搭建学习环境,再到探讨映射文件获取参数值(${}、#{})@param注解命名参数、各种查询功能(1条、多条、单个数据)、再到特殊SQL的执行(模糊查询、批量删除)、自定义resultMap(重点讲述了多对一、一对多的解决方案)、动态SQL(if、where、foreach标签)MyBatis的一二级缓存

1.Mybatis介绍

1.1Mybatis历史

  1. 原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了Google Code,随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis ,代码于2013年11月迁移到Github(下载地址见后)
  2. iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Obje

1.2Mybatis特点

  1. Mybatis是一个半自动的ORM(Object Relation Mapping)框架
  2. 面向接口编程思想:可以使用简单的XML或注解用于配置和原始映射,将接口和Java的实体类对象映射成数据库中的记录
  3. 支持定制化SQL、存储过程以及==高级映射(一对多的映射关系)==的持久化框架
  4. 封装了几乎所有的JDBC代码和手动设置参数以及获取结果集

1.3与其他持久化框架对比

  • JDBC
    • SQL夹杂在Java代码中耦合度高,导致硬编码内伤。
    • 维护不易且实际开发需求中 SQL有变化,频繁修改的情况多见。
    • 代码冗长,开发效率低。
  • Hibernate和IPA
    • 操作简便,开发效率高
    • 程序中的长难复杂 SQL需要绕过框架
    • 内部自动生产的 SQL,不容易做特殊优化。
    • 基于全映射的全自动框架,大量字段的 POJ0 进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • MyBatis
    • 轻量级,性能出色
    • SQL和Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据。
    • 开发效率稍逊于HIbernate,但是完全能够接受

1.4对象关系映射——ORM

ORM即Object Relationship Mapping,对象关系映射!

解释/含义
对象java的实体类对象
关系关系型数据库
映射二者之间的对应关系

在java概念和数据库概念中的对应关系如下:

java概念数据库概念
属性字段/列
对象记录/行

2.搭建Mybatis

搭建一个基于Maven的project

2.1引入依赖

<dependencies><!-- Mybatis核心 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!-- log4j日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
</dependencies>

2.2创建核心配置文件

  1. 习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。
  2. 将来整合Spring之后,这个配置文件可以省略
  3. 核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息核心配置文件存放的位置是src/main/resources目录下

image-20240304232348464

2.3创建表、实体类、mapper接口

image-20240304232548553

MyBatis 中的 mapper 接口相当于以前的 DAO 接口,但是区别在于, mapper 仅仅是接口,我们不需要提供实现类(面向接口编程);

image-20240304232617262

2.4创建映射文件

2.4.1映射文件命名位置规则

  1. 表所对应的 实体类的类名+Mapper.xml ,例如:表 t_user,映射的实体类为 User,所对应的映射文件为 UserMapper.xml放到resources目录下
  2. 因此一个映射文件对应一个实体类,对应一张表的操作
  3. MyBatis 映射文件用于编写 SQL,访问以及操作表中的数据

2.4.2编写映射文件

MyBatis中面向接口编程的两个一致:

  •  ==映射文件的namespace要和mapper接口的全类名保持一致==
    
  •  ==映射文件中SQL语句的id要和mapper接口中的方法名一致==
    

image-20240304232819888

首先先根据核心配置文件中的来引入映射文件,再根据方法名匹配到SQL语句

2.4.3修改核心配置文件中映射文件路径

若修改核心配置文件中的映射文件路径,则需将UserMapper.xml文件放置在resources/mapper文件夹下

image-20240304232954726

2.5Junit测试

image-20240304233129822

2.6修改、删除、查询功能测试

  • UserMapper.java

image-20240304233507867

  • UserMapper.xml

image-20240304233546616

3.核心配置文件详讲(了解)

MyBatis核心配置文件中,标签的顺序properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,lugins?,environments?,databaseIdProvider?,mappers?

3.1environment、properties讲解

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--MyBatis核心配置文件中,标签的顺序:properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?--><!--引入properties文件,此时就可以${属性名}的方式访问属性值--><properties resource="jdbc.properties" /><!--设置类型别名--><typeAliases><!--typeAlias:设置某个类型的别名属性:type:设置需要设置别名的类型alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名且不区分大小写--><!--<typeAlias type="com.atguigu.User"></typeAlias>--><!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写--><package name="com.atguigu.mybatis.pojo"/></typeAliases><!--environments:配置多个连接数据库的环境属性:default:设置默认使用的环境的id--><environments default="development"><!--environment:配置某个具体的环境属性:id:表示连接数据库的环境的唯一标识,不能重复--><environment id="development"><!--transactionManager:设置事务管理方式属性:type="JDBC|MANAGED"JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理MANAGED:被管理,例如被Spring管理--><transactionManager type="JDBC"/><!--dataSource:配置数据源,与spring整合后不用再设置dataSource属性:type:设置数据源的类型type="POOLED|UNPOOLED|JNDI"POOLED:表示使用数据库连接池缓存数据库连接,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建UNPOOLED:表示不使用数据库连接池,即每次使用连接都需要重新创建JNDI:表示使用上下文中的数据源--><dataSource type="POOLED"><!--设置连接数据库的驱动--><property name="driver" value="${jdbc.driver}"/><!--设置连接数据库的连接地址--><property name="url" value="${jdbc.url}"/><!--设置连接数据库的用户名--><property name="username" value="${jdbc.username}"/><!--设置连接数据库的密码--><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--引入映射文件--><mappers><!--<mapper resource="mappers/UserMapper.xml"/>--><!--以包为单位引入映射文件要求:1、mapper接口所在的包要和映射文件所在的包一致2、mapper接口要和映射文件的名字一致--><package name="com.atguigu.mybatis.mapper"/></mappers>
</configuration>

3.2typeAliases讲解

作用:设置类型别名

<!-- 设置类型别名方式一:以某一个类为单位(不常用)方式二:以包为单位,将包下所有的类型设置为默认类型别名,即类型且不区分大小写(常用)
-->
<typeAliases><!--方式一:typeAlias:设置某个类型的别名属性:type:设置需要设置别名的类型alias:设置某个类型的别名,如果不设置该属性,那么该类型拥有默认的别名,即类名而且不区分大小写--><typeAlias type="com.peng.mybatis.pojo.User" alias="User"></typeAlias><!--方式二:--><package name="com.peng.mybatis.pojo.User"></package></typeAliases>

3.3mappers

3.3.1将UserMapper.xml转移到新目录下

image-20240304234039332

在 resources 包下面创建 directory(目录)创建 package(包) 是不一样的

不能用com.peng.mybatis.mapper 这种方式创建多个文件夹,这样创建出来的是一个包名;应该用 com/peng/mybatis/mapper 这种方式。

3.3.2在核心配置文件中引入映射文件

<!-- 引入映射文件以包为单位引入映射文件要求:mapper接口所在的包要和映射文件所在的包一致mapper接口要和映射文件的名字一致
-->
<mappers><package name="com.peng.mybatis.mapper"/>
</mappers>

4.MyBatis获取参数值的两种方式(重要)

4.1区分${}和#{}

4.4.1区分点

  1. MyBatis获取参数值的两种方式:${}和#{}

    ${}本质为字符串替换

    #{}本质为占位符赋值

    ${}和#{}的相同点为都能获取参数变量的值,在预编译语法上则不同

${}#{}
预编译不行将#{变量}编译成?,在执行时后再取值(自动加上引号),防止sql注入
应用场景传入的参数是sql片段的场景在sql映射文件中动态拼接sql时的开发场景(获取变量)

传入的参数是sql片段的场景

<select id="getUserPage" resultType="com.ymxx.oa.bean.User">${sql片段}
</select>
  • 对于这样外部传入的sql,就不能使用#{},上面也说了,#{}会进行预编译,检测到该sql片段是个字符串,就会加上引号,即’sql片段’,这样就是字符串了而不是sql,执行会报错。

4.4.2预编译过程

mybatis在预编译过程大体上可以分为 数据类型检查安全检查 两部分

数据类型检查若检测到为数值类型,就不加引号,即?若检测到位字符串类型,就加上引号,即’?'

安全检查:若变量的值带有引号,会对引号进行转义处理,这样可以防止sql注入

4.4.3 ${}的sql注入问题

用${}时要特别注意sql注入的风险,如果该sql片段是根据用户的输入拼接的,要注意检查sql注入的问题,防止数据的泄露与丢失!

案例:

//sql语句
select * from ${tableName} where name = ${name}

如果tableName的值为 user; delete user; –,该sql最终解析成

select * from user; delete user; -- where name = xxx

结果查询了整张表,然后把user表给删了

4.2获取参数值的各种情况

获取参数值的情况可以分为以下四种情况:

  • 参数为单个的字面量类型
  • 参数为多个
    • 使用原生的map
    • 使用自己的map(${}、#{})
  • 参数是实体类类型的参数
  • 使用@Param注解命名参数

4.2.1情况一:参数为单个的字面量类型

  • 可以通过KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}以任意的字符串获取参数值 …{}需要额外加上单引号

4.2.2情况二:参数为多个时

(1)使用原生的map
  • mybatis会把形参的值放在一个map集合中,以两种方式进行存储
  • arg0,arg1为键或者以param0,param1为键
  • 以参数值为值,可以混着用
(2)使用自己的map(${}、#{})
  • 使用自己的map可以通过KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}以键名的方式获取参数值==…{}需要额外加上单引号
  • 可以==通过KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}以自己设置的键名的方式获取…{}需要额外加上单引号

4.2.3参数是实体类类型的参数

  • 通过${}和#{}以自己设置的键名实体类里面的属性)的方式获取参数值
  • 使用${}需要额外加上单引号

4.2.4使用@Param注解命名参数(以这个和实体类类型两种情况为标准)

  • mybatis会把形参的值放在一个map集合中,以两种方式进行存储
  • 以自己使用的==@Param注解的参数名为键或者以param1,param2为键==,
  • 以参数值为值,可以混着用

4.3举例

4.3.1mapper接口

image-20240305084222152

4.3.2映射文件

image-20240305085039896

4.3.3测试

image-20240305090616441

4.4小结

  1. 有实体类的时候直接用属性值来访问

    例如,如果有一个 User 实体类,其中包含了 idname 两个属性,那么在 SQL 语句中就可以直接引用这些属性:

    <select id="getUserById" resultType="User">SELECT * FROM users WHERE id = #{id}
    </select>
    
  2. 没有实体类的时候用 @Param 注解命名参数,不管字面量单个还是多个,是不是 map 集合都可以使用自己用注解定义的参数来访问

    当没有实体类或需要额外命名参数时,可以使用 @Param 注解来命名参数。例如,假设我们需要在 SQL 中引用多个参数,可以这样做:

    • mapper接口:
    public interface UserMapper {List<User> getUsersByAgeRange(@Param("minAge") int minAge, @Param("maxAge") int maxAge);
    }
    
    • 映射文件:

      <select id="getUsersByAgeRange" resultType="User">SELECT * FROM users WHERE age BETWEEN #{minAge} AND #{maxAge}
      </select>
      

4.5@Param标识的源码解析

为啥我们能将我们想要的 key 值,以及对应的 value 值设置进去呢?

(1)首先看这个方法的第三步的内部是如何调用的?

在这里插入图片描述

(2) mapper 映射的底层使用了代理模式,通过反射执行当前命令对应的方法

  • MapperProxy.java

在这里插入图片描述

在这里插入图片描述

(3)当前命令中,name 对应的是要执行的 sql 语句唯一标识:mapper 映射文件中 namespace + id),方法对应的是 select 方法,所以 switch - case 直接跳到 select 方法去执行对应的方法:

  • MapperMethod.java

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

这边在 else 模块中,第一个方法是将 args 参数转换成 sql 要求的参数,点进这个方法看一下里面怎么写的?

在这里插入图片描述

再进入方法内部,这个方法是一个将注解设定的命名规则的名称设置成 map 容器的 key 值的方法

  • ParamNameResolver.java

在这里插入图片描述

第一步:name 是一个排序的 map 容器,其中 0 号位置放了我们通过注解命名的第一个参数名称1 号位置放置了我们通过注解命名的第二个参数名称:

在这里插入图片描述第二步:又因为我们有参数注解而且参数注解的个数不为1,所以跳到 else 中执行,新建一个 map 容器用来放置 (键值,参数值)

第三步遍历 names 这个 map 容器,取出其中第一个键值对

第四步:将它的 value 值即放置的自定义的 username 注解名称当作键值,将 args[当前键值对的键值] 即 args[0] 当作 value 值放进 params 这个 map 容器中

在这里插入图片描述

第五步定义一个字符串 param1,这里的 1 表示的是遍历第一个键值对即 i = 0;

第六步如果当前 names 这个 map 容器中没有包含当前的这个 param1 这个值(防止我们自己定义了,重复放置),那么我们就将(param1 ,args[0])这一个键值对放进 param 这个 map 容器中,也就是我们既可以用我们自己设定的 username 来访问对应的参数值,也可以用 param1 来访问对应的参数值。

第七步:i++,遍历 names 容器中的下一个键值对,重复执行 4 - 6;

第八步:最后将生成的 param 这个 map 容器返回,我们可以从中任意选择一个键值来访问对应的参数。

5.MyBatis的各种查询功能

5.1查询的数据只有一条

5.1.1接收情况

若查询的数据只有一条,那可以分为以下三种情况:

  1. 通过实体类对象接收
  2. 通过list集合接收(建议使用list集合接收
  3. 通过map集合接收

5.1.2举例

  • mapper 接口中方法的定义:

image-20240305091458001

  • mapper 映射文件中 sql 语句的编写:

    注意:通过map集合接收的sql语句的 resultType值 必须修改为map

image-20240305091816596

  • 测试类

image-20240305091824270

5.2查询的数据有多条

若查询的数据有多条,那可以分为以下三种情况:

  1. 通过实体类类型的list集合接收

  2. 通过map类型的list集合接收

  3. 通过注解@MapKey注解实现注入

    可以在mapper接口的方法上添加@MapKey注解,此时就可以将每条数据转换为map集合作为值,以某个字段的值作为键,放在同一个map集合中

  • mapper接口中方法的定义

image-20240305092035641

  • mapper 映射文件中 sql 语句的编写:

image-20240305092056982

  • 测试

image-20240305092312490

5.3查询单个数据(聚合函数)

  • mapper 接口中方法的定义:

image-20240305092355706

  • mapper 映射文件中 sql 语句的编写:

image-20240305092424526

  • 测试

image-20240305092501138

补充:MyBatis 中设置了默认的类型别名,可以在resultType使用别名

java.lang.Integer --> int,integer
int --> _int,_integer
Map --> map
String --> string

6.特殊SQL的执行

6.1模糊查询

模糊查询语句:

select * from tb_user where username like '%鹏%';

重点在如何解析出鹏字,由前面可知,${}本质为字符串替换、#{}本质为占位符(会进行预编译,若在数据类型检查中,检查为字符串类型,则会自动添加’‘引号)

mapper 映射文件中 sql 语句的编写,一共有三种方法可以实现:

  1. 使用${}
  2. 使用 concat#{} 进行字符串拼接(推荐)
  3. 使用"%#{}%"
  • mapper 接口中方法的定义:

image-20240305092616279

  • 映射文件:

image-20240305092943837

  1. 这里不可以使用 select * from t_user where username like '%#{username}%',即将 #{} 这种占位符赋值获取参数值的放在 单引号 里面;

  2. 这样直接将单引号里面的三个字符都当作字符串的一部分,而不会解析成占位符,看报错信息可以看出来,?直接放在单引号内部,当成一个==字符?==了,而不会被当成一个占位符

  3. 解析结果:

    image-20240305093102586

  • 测试

image-20240305095726057

6.2批量删除

  • mapper 接口中方法的定义:

image-20240305095817002

  • mapper 映射文件中 sql 语句的编写,这里只能用 ${} 这种字符串替换的方法来实现:

image-20240305095922782

  • 不能使用 #{}这种方式:#{} 这种占位符赋值的方式,会自动给参数加上单引号
delete from t_user where id in (#{ids});
# in (1,2,3,4)——>in('1,2,3,4'),结果必定报错
  • 测试

image-20240305100210905

6.3动态设置表名(会出现sql注入问题)

  • mapper 接口中方法的定义:

image-20240305100300248

  • mapper 映射文件中 sql 语句的编写

image-20240305100317945

  • 测试

image-20240305100344989

6.4添加功能获取自增的主键

  • mapper 接口中方法的定义:

image-20240305100738436

  • mapper 映射文件中 sql 语句的编写

image-20240305100801535

  • 测试

image-20240305100826298

7.自定义映射resultMap

7.1搭建mybatis框架

  • 数据库新建两张表t_emp和t_dept,并存入测试数据

    • t_emp表

      image-20240305100947447

    • t_dept表和数据

      image-20240305101049361

  • 新建两个类,其中emp_name对应的属性名为empName

    image-20240305101100400

7.2字段名和属性名不一致

解决字段名和属性名不一致的情况的三种方式

  1. 为字段名起别名
  2. 全局配置mapUnderscoreToCamelCase(驼峰映射)
  3. resultMap设置自定义映射关系(推荐)

7.2.1给字段名起别名

image-20240305101327430

7.2.2全局配置mapUnderscoreToCamelCase

  • mybatis-config.xml

image-20240305101342388

7.2.3resultMap(建议使用)

image-20240305101442659

7.3多对一(从员工到部门)映射关系

定义:多对一的映射关系指的是一个对象(或实体)在关联另一个对象时,该对象拥有多个对应关联对象的情况。具体来说,多对一关系表示多个对象共同指向同一个对象

举例:假设有两个实体类 DepartmentEmployee,一个部门可以有多名员工,而一名员工只能属于一个部门。在这种情况下,EmployeeDepartment 的关系就是多对一的映射关系,因为多名员工可以指向同一个部门

处理多对一的映射关系可以有以下几种方法:

  1. 通过 级联属性 赋值

  2. 通过 association标签

  3. 通过 分步查询

7.3.1通过级联属性(连接查询)赋值

  • 员工对象

image-20240305155201552

  • 部门对象

image-20240305155230176

  • mapper接口中方法定义

image-20240305155041400

  • mapper映射文件

image-20240305155116762

7.3.2通过association标签

  • mapper映射文件

image-20240305155704639

  • 测试

image-20240305155715928

7.3.3通过分步查询(推荐)

(1)通过id查询员工信息、并查出did
  • EmpMapper接口方法定义

image-20240305155729119

  • EmpMapper.xml映射文件

image-20240305155838408

解释:

  • association 标签中的 column 属性将两个查询到的信息关联了起来
  • select 属性中写的是 mapper 接口的全类名(唯一标识)
(2)通过did查询员工所对应的部门
  • DeptMapper接口方法定义

image-20240305160029531

  • DeptMapper.xml映射配置文件,注意字段名和属性名并不相同

image-20240305160047325

(3)测试

image-20240305160117304

7.3.4分步查询的好处:延迟加载

  1. 可以实现 延迟加载,但是必须在核心配置文件中设置全局配置信息(配置如下两个信息):没有全局设置的话,默认的是立即加载;

  2. lazyLoadingEnabled延迟加载的全局开关

    当开启时,所有关联对象都会延迟加载;

    需要 设置为true,默认为false。

  3. aggressiveLazyLoading设置为false,默认为false。当开启时,任何方法的调用都会加载该对象的所有属性 ,需要关闭他。关闭后每个属性会按需加载。

(1)开启延迟加载之前

image-20240305160614749

(2)开启全局延迟加载之后
  • mybatis-config.xml

image-20240305160630439

image-20240305160652120

(3)可以局部关闭延迟加载

条件:全局延迟加载开启

image-20240305160845187

7.4.一对多映射关系

  1. 定义:一对多关系表示一个对象指向多个相关联的对象
  2. 假设有两个实体类 DepartmentEmployee,一个部门可以有多名员工,而一名员工只能属于一个部门。在这种情况下,DepartmentEmployee 的关系就是一对多的映射关系,因为一个部门可以指向多名员工

7.4.1通过collection解决一对多映射关系

  • DeptMapper接口方法定义

image-20240305161128118

  • DeptMapper.xml映射配置文件

image-20240305161135178

  • 测试

image-20240305161209832

8.动态SQL

在 MyBatis 中,可以使用动态 SQL 来根据条件生成不同的 SQL 语句

  1. if:根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到 SQL 语句

  2. where

    • 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或者or去掉

    • 当where标签中没有内容时,此时where标签没有任何效果

    • 注意:where标签不能将其中内容后面多余的and或者or去掉,只能将内容前多余的and或者or去掉

  3. trim

    • prefix|suffix:将trim标签中内容前面或者后面添加指定内容
    • prefixOverrides|suffixOverrides:将trim标签中内容前面或者后面去掉指定内容
    • 若标签中没有任何内容时,trim标签也没有任何效果
  4. choose、when、otherwise

    • 相当于if…else if…else if…otherwise
    • 其中when至少要有一个,otherwise最多只能有一个
  5. foreach

  • collection:设置需要循环的数组或者集合
  • item:表示数组或者集合中的每一个数据
  • separator:循环体之间的分隔符\
  • open:foreach标签所循环的所有内容的开始符
  • close:foreach标签所循环的所有内容的结束符

8.1if-where-trim标签

8.1.1if标签

image-20240305162857172

8.1.2where标签

image-20240305162915829

8.1.3trim标签

image-20240305163028054

image-20240305163038846

8.2choose-when-ohterwise标签

choose、when、otherwise,相当于if…else if…else

image-20240305163118041

8.3.foreach标签

8.3.1实现批量删除方式一

image-20240305163209567

8.3.2实现批量删除方式二

image-20240305163238958

8.3.3实现批量添加

image-20240305163251101

image-20240305163315943

8.4SQL标签

  • 设置SQL片段:

    <sql id="empColumns">eid,emp_name,age,sex,email</sql>
    
  • 引用SQL片段:

    <include refid="empColumns"></include>
    

image-20240305163350471

9.MyBatis缓存

9.1介绍

MyBatis 中的缓存主要分为一级缓存和二级缓存,它们的作用是提高数据库访问效率,减少不必要的数据库查询操作。

9.1.1一级缓存

  • 一级缓存是指在同一个 SqlSession 中执行相同的查询操作时,第二次及以后的查询会直接从缓存中获取结果,而不会再次查询数据库。
  • 一级缓存是默认开启的,且无法关闭。它的范围是 SqlSession 级别的,即在同一个 SqlSession 中共享缓存。
  • 一级缓存可以通过清除缓存的方式来刷新数据,比如调用 clearCache() 方法。

9.1.2二级缓存

  • 二级缓存是指多个 SqlSession 共享相同的缓存,可以跨 SqlSession 进行数据共享。
  • 使用二级缓存需要在映射文件中配置 <cache> 标签,并在 MyBatis 配置文件中开启二级缓存功能
  • 二级缓存的范围是 Mapper 级别的,即同一个 Mapper 接口下的多个 SqlSession 可以共享缓存。
  • 二级缓存对于经常被访问且不经常改变的数据非常有效,但在数据频繁更新的情况下,需要考虑缓存的有效性和数据一致性。

9.2一级缓存

9.2.1一级缓存生效(默认生效)

一级缓存是 SqlSession 级别 的,通过 同一个 SqlSession 查询 的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。

  • mapper接口方法定义

image-20240305164155208

  • mapper接口映射文件

image-20240305164204852

  • 测试,同一个sqlSession是去缓存中取数据

image-20240305164226716

9.2.2一级缓存失效

使得一级缓存失效的四种情况

  • 不同的SqlSession对应不同的一级缓存
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作,数据发生了变化
  • 同一个SqlSession两次查询期间手动清空了缓存

image-20240305164256605

9.3二级缓存

二级缓存是 SqlSessionFactory 级别,通过 同一个 SqlSessionFactory 创建的 SqlSession 查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。

9.3.1二级缓存开启

(1)在核心配置文件中,设置全局配置属性 cacheEnabled=“true”,默认为 true,不需要设置;

(2)在映射文件中设置标签 <cache />

image-20240305164322284

(3)二级缓存必须在 SqlSession 关闭或提交之后有效;

(4)查询的数据所转换的实体类类型必须实现序列化的接口。

image-20240305164351626

  • 测试

image-20240305164420343

9.3.2二级缓存失效

失效情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

9.3.3二级缓存的相关配置

image-20240305164510303

9.4缓存查询的顺序

  1. 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  2. 如果二级缓存没有命中,再查询一级缓存
  3. 如果一级缓存也没有命中,则查询数据库
  4. SqlSession关闭之后,一级缓存中的数据会写入二级缓存

10_MyBaits的逆向工程

10.1创建逆向工程的步骤

(1)添加依赖和插件,这里的 mybatis 和 JDBC 换成你自己对应的版本:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.peng.mybatis</groupId><artifactId>MyBatis_demo04</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><!-- 依赖MyBatis核心包 --><dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!-- log4j日志 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.apache.ibatis</groupId><artifactId>ibatis-core</artifactId><version>3.0</version></dependency><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version></dependency></dependencies><!-- 控制Maven在构建过程中相关配置 --><build><!-- 构建过程中用到的插件 --><plugins><!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><!-- 插件的依赖 --><dependencies><!-- 逆向工程的核心依赖 --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><!-- 数据库连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency></dependencies></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build>

(2)创建 MyBatis 的核心配置文件 mybatis-config.xml

(3)创建逆向工程的配置文件,文件名必须是:generatorConfig.xml(修改数据库名称和密码、修改包名、修改对应的数据库表名)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration><!--targetRuntime: 执行生成的逆向工程的版本MyBatis3Simple: 生成基本的CRUD(清新简洁版),只有增删改查(查所有和根据 Id 查)5个方法MyBatis3: 生成带条件的CRUD(奢华尊享版)--><context id="DB2Tables" targetRuntime="MyBatis3"><!-- 数据库的连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"password="123456"></jdbcConnection><!-- javaBean的生成策略--><javaModelGenerator targetPackage="com.peng.mybatis.pojo"targetProject=".\src\main\java"><!--true生成的是子包,false生成的是一个文件夹名--><property name="enableSubPackages" value="true"/><!-- 去掉字符串前后的空格--><property name="trimStrings" value="true"/></javaModelGenerator><!-- SQL映射文件的生成策略 --><sqlMapGenerator targetPackage="com.peng.mybatis.mapper"targetProject=".\src\main\resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- Mapper接口的生成策略 --><javaClientGenerator type="XMLMAPPER"targetPackage="com.peng.mybatis.mapper" targetProject=".\src\main\java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 逆向分析的表 --><!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --><!-- domainObjectName属性指定生成出来的实体类的类名,会自动在后面补上Mapper --><table tableName="t_emp" domainObjectName="Emp"/><table tableName="t_dept" domainObjectName="Dept"/></context>
</generatorConfiguration>
  • MyBatis3Simple: 生成基本的CRUD(清新简洁版),只有增删改查(查所有和根据 Id 查)5个方法
  • MyBatis3: 生成带条件的CRUD(奢华尊享版)

(5)执行MBG插件的generate目标

在这里插入图片描述

10.2豪华尊享版两种函数的区别

在这里插入图片描述

10.3QBC查询

image-20240305164823124

  • 报了错误Error:(6, 37) java: 程序包org.apache.ibatis.annotations不存在,网上找不到解决方法,怀疑是配置文件里面版本问题

10.4QBC修改

image-20240305164840117

  • and 条件都是链式添加的;
  • or 条件需要换行,调用 or() 方法之后再调用 and() 方法。

11_MyBatis分页

11.1使用步骤

  • 核心配置文件中配置分页插件
<plugins><!--设置分页插件--><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
  • 在pom.xml中添加依赖
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version>
</dependency>

11.2使用

public class PageHelperTest {/*** limit index,pageSize* index:当前页的起始索引* pageSize:每页显示的条数* pageNum:当前页的页码** index=(pageNum-1)*pageSize** 使用MyBaits的分页插件实现分页功能* 1.需要在查询功能之前开启分页,2代表了当前页码,4代表当前页显示的数据* PageHelper.startPage(2,4);* 2.在查询功能之后获取分页相关信息* PageInfo<Emp> page=new PageInfo<>(list,5);* list代表分页数据* 5代表当前导航分页的数量*/@Testpublic void testPageHelper(){try {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession(true);EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);//开启分页功能//查询详细分页信息方式一:
//            Page<Object> page = PageHelper.startPage(2, 4);
//            System.out.println(page);PageHelper.startPage(2,4);//查询所有数据List<Emp> list = mapper.selectByExample(null);list.forEach(emp-> System.out.println(emp));//查询详细分页信息方式二,其中5代表导航数PageInfo<Emp> page=new PageInfo<>(list,5);System.out.println(page);} catch (IOException e) {e.printStackTrace();}}
}
  • Page<Object> page = PageHelper.startPage(2, 4); ,这个函数返回的 page 是包含少量信息的 page数据;
  • PageInfo<Emp> page = new PageInfo<>(list, 5);,展示非常详细的 pageInfo 信息,里面包含 page 信息。

在这里插入图片描述

常用数据:

  • pageNum:当前页的页码
  • pageSize:每页显示的条数
  • size:当前页显示的真实条数(有可能每页显示 5 条,但是最后一页只剩 2 条数据这样子)
  • total:总记录数
  • pages:总页数
  • prePage:上一页的页码
  • nextPage:下一页的页码
  • isFirstPage/isLastPage:是否为第一页/最后一页
  • hasPreviousPage/hasNextPage:是否存在上一页/下一页
  • navigatePages:导航分页的页码数
  • navigatepageNums:导航分页的页码,[1,2,3,4,5]

在这里插入图片描述

相关文章:

  • 2024.1.28 校招 实习 内推 面经
  • 【嵌入式——QT】Model/View
  • 【PHP】PHP通过串口与硬件通讯,向硬件设备发送数据并接收硬件返回的数据
  • 基于Springboot免费搭载轻量级阿里云OSS数据存储库(将本地文本、照片、视频、音频等上传云服务保存)
  • 揭秘共享旅游卡项目变现的6种方式,至少有4种适合创业者!
  • STM32/GD32——I2C通信协议
  • Nodejs web服务器之GET、POST请求初次体验
  • 2024《》
  • 论文研读_多目标部署优化:无人机在能源高效无线覆盖中的应用(ImMOGWO)精简版
  • 100个Linux操作命令和20个常用脚本
  • docker中的具名和匿名挂载
  • MySQL CTEs通用表表达式:进阶学习-递归查询
  • Qt将Unicode转换成UTF8中文
  • 哈希专题 - leetcode 1. 两数之和 - 简单难度
  • 代码随想录算法训练营day47|第九章 动态规划part09:198.打家劫舍、213.打家劫舍II、337.打家劫舍III
  • [笔记] php常见简单功能及函数
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 2017-09-12 前端日报
  • Apache Spark Streaming 使用实例
  • AWS实战 - 利用IAM对S3做访问控制
  • download使用浅析
  • eclipse(luna)创建web工程
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Kibana配置logstash,报表一体化
  • nginx 负载服务器优化
  • node入门
  • PHP 7 修改了什么呢 -- 2
  • Python十分钟制作属于你自己的个性logo
  • 检测对象或数组
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 离散点最小(凸)包围边界查找
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • python最赚钱的4个方向,你最心动的是哪个?
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​flutter 代码混淆
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • (14)Hive调优——合并小文件
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (2)STM32单片机上位机
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (转载)hibernate缓存
  • ... 是什么 ?... 有什么用处?
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @PreAuthorize注解
  • @Resource和@Autowired的区别
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • @WebService和@WebMethod注解的用法
  • [2024] 十大免费电脑数据恢复软件——轻松恢复电脑上已删除文件
  • [Asp.net MVC]Bundle合并,压缩js、css文件
  • [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
  • [C#] 如何调用Python脚本程序
  • [codeforces]Checkpoints
  • [Docker]五.Docker中Dockerfile详解