• MyBatis


    目录 

    一、MyBatis介绍

    1.MyBatis特性

    2. MyBatis下载

    ⭐地址

    3.和其它持久化层技术的对比

    ①JDBC

    ②Hibernate与JPA

    ③MyBatis

    二、搭建MyBatis

    1.开发环境

    2.创建maven工程

    ①打包方式

    ②引入依赖

    ③创建MyBatis的核心配置文件

    ④创建mapper接口

    ⑤创建MyBatis的映射文件(写sql语句)

    ⑥测试

    ⑦功能优化

    ⑧加入log4j日志功能

    ⑨log4j日志的级别

    😊文件目录结构

    ⑩测试修改、删除和查询功能

    🐟UserMapper接口 

    三、Mybatis核心配置文件

    1.environments

    ⚪environment

    ⚪transactionManager

    ⚪dataSource

    3.typeAliases

    🐟Mybatis核心配置文件中的标签必须按照指定的顺序配置

    4.mappers

    ⭐以包的方式引入映射文件,但是必须满足两个条件:

     5.在idea中能够创建mybatis核心配置文件和映射文件的模板

    ①核心配置文件

    ②映射文件 

    三、获取参数值的两种方式

    1.mapper接口方法的参数是单个字面量类型的参数

    ①字面量

    ②例:根据用户名查询用户信息

    2.多个字面量类型的参数

    ⭐验证登录

    3.map集合类型的参数

    ⭐验证登录(以map集合作为参数)

    4.实体类类型的参数

    ⭐添加用户信息

    5.使用@Param标识参数

    ① @Param注解

    ②查询用户信息

    四、Mybatis的各种查询功能

    1.查询一个实体类对象

    2.查询一个list集合

    3.查询单个数据 

    ⭐Mybatis提供的类型别名 

    4.查询一条数据为map集合

    5.查询多条数据为map集合

    解决方案一:放在list集合中

    解决方案二:使用@MapKey注解

    五、特殊SQL的执行

    1.模糊查询

    2.批量删除

    3.动态设置表名

    4.添加功能获取自增的主键

    ⚪useGeneratedKeys

    ⚪keyProperty

    六、自定义映射resultMap

    ⭐准备工作

    例:根据id查询员工信息

    1.resultMap处理字段和属性的映射关系(字段和属性不一致)

    2.多对一映射处理

    ⭐获取员工以及所对应的部门信息

    ①级联方式处理映射关系

    ②使用association处理映射关系

    ③ 分步查询

    3.一对多映射处理

    ①collection

    ②分步查询

    ⭐分步查询的优点

    七、Mybatis动态SQL 

    1.if

    2.where

    3.trim

    4.choose、when、otherwise

    5.foreach

    6.SQL片段        

    八、MyBatis的缓存

    1.MyBatis的一级缓存

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

    2.MyBatis的二级缓存

    ⭐二级缓存开启的条件

    ⭐使二级缓存失效的情况

    3.二级缓存的相关配置

    ①eviction属性:缓存回收策略,默认为 LRU。

    ②flushInterval属性:刷新间隔,单位毫秒

    ③size属性:引用数目

    ④readOnly:只读, true/false

    4.MyBatis缓存查询的顺序

    5.整合第三方缓存EHCache

    ①添加依赖

    ②各jar包功能

    ③创建EHCache的配置文件ehcache.xml

    ④设置二级缓存的类型

    ⑤加入logback日志

    ⑥EHCache配置文件说明

    九、MyBatis的逆向工程

    1.创建逆向工程的步骤

    ①添加依赖和插件

    ②创建MyBatis的核心配置文件

    ③创建逆向工程的配置文件

    ④执行MBG插件的generate目标

    ⑤效果

    2.QBC查询

    十、分页插件

    1.分页插件的使用步骤

    ①添加依赖

    ②配置分页插件

    2.分页插件的使用


    一、MyBatis介绍

    1.MyBatis特性

    • MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
    • MyBatis 避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
    • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和ava的POJO(Plain Old Javaobjects,普通的Java对象)映射成数据库中的记录
    • MyBatis是一个半自动的ORM (Object Relation Mapping —— 对象关系映射)框架

    2. MyBatis下载

    ⭐地址

    GitHub - mybatis/mybatis-3: MyBatis SQL mapper framework for Java

    3.和其它持久化层技术的对比

    ①JDBC

    • SQL夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
       

    ②Hibernate与JPA

    • 操作简便,开发效率高
    • 程序中的长难复杂SQL需要绕过框架
    • 内部自动生产的SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。
    • 反射操作太多,导致数据库性能下降
       

    ③MyBatis

    • 轻量级,性能出色
    • SQL和Java编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于HIbernate,但是完全能够接受

    二、搭建MyBatis

    1.开发环境

    MySOL不同版本注意事项:

    MySOL 5MySOL 8
    驱动类
    • 使用jdbc5驱动
    • 驱动类:com.mysql.jdbc.Driver
    • 使用jdbc8驱动
    • 驱动类:com.mysql.cj.jdbc.Driver
    连接地址urljdbc:mysql://localhost:3306/数据库名称jdbc:mysql://localhost:3306/数据库名称?serverTimezone=UTC

    2.创建maven工程

    ①打包方式

    jar包

    ②引入依赖

    1. <project xmlns="http://maven.apache.org/POM/4.0.0"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <groupId>com.atguigu.mybatisgroupId>
    6. <artifactId>mybatis_helloWorldartifactId>
    7. <version>1.0-SNAPSHOTversion>
    8. <packaging>jarpackaging>
    9. <properties>
    10. <maven.compiler.source>8maven.compiler.source>
    11. <maven.compiler.target>8maven.compiler.target>
    12. properties>
    13. <dependencies>
    14. <dependency>
    15. <groupId>org.mybatisgroupId>
    16. <artifactId>mybatis-springartifactId>
    17. <version>2.0.4version>
    18. dependency>
    19. <dependency>
    20. <groupId>junitgroupId>
    21. <artifactId>junitartifactId>
    22. <version>4.12version>
    23. <scope>testscope>
    24. dependency>
    25. <dependency>
    26. <groupId>mysqlgroupId>
    27. <artifactId>mysql-connector-javaartifactId>
    28. <version>8.0.22version>
    29. dependency>
    30. dependencies>
    31. project>

    创建User类

    1. package com.atguigu.mybatis.pojo;
    2. public class User {
    3. private Integer id;
    4. private String user_name;
    5. private String password;
    6. private Integer age;
    7. private String gender;
    8. private String email;
    9. public User() {
    10. }
    11. public User(Integer id, String user_name, String password, Integer age, String gender, String email) {
    12. this.id = id;
    13. this.user_name = user_name;
    14. this.password = password;
    15. this.age = age;
    16. this.gender = gender;
    17. this.email = email;
    18. }
    19. public Integer getId() {
    20. return id;
    21. }
    22. public void setId(Integer id) {
    23. this.id = id;
    24. }
    25. public String getUser_name() {
    26. return user_name;
    27. }
    28. public void setUser_name(String user_name) {
    29. this.user_name = user_name;
    30. }
    31. public String getPassword() {
    32. return password;
    33. }
    34. public void setPassword(String password) {
    35. this.password = password;
    36. }
    37. public Integer getAge() {
    38. return age;
    39. }
    40. public void setAge(Integer age) {
    41. this.age = age;
    42. }
    43. public String getGender() {
    44. return gender;
    45. }
    46. public void setGender(String gender) {
    47. this.gender = gender;
    48. }
    49. public String getEmail() {
    50. return email;
    51. }
    52. public void setEmail(String email) {
    53. this.email = email;
    54. }
    55. @Override
    56. public String toString() {
    57. return "User{" +
    58. "id=" + id +
    59. ", user_name='" + user_name + '\'' +
    60. ", password='" + password + '\'' +
    61. ", age=" + age +
    62. ", gender='" + gender + '\'' +
    63. ", email='" + email + '\'' +
    64. '}';
    65. }
    66. }

    ③创建MyBatis的核心配置文件

    • 习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。
    • 核心配置文件主要用:配置连接数据库的环境 & MyBatis的全局配置信息
    • 核心配置文件存放的位置src/main/resources目录下
    1. configuration
    2. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    4. <configuration>
    5. <environments default="development">
    6. <environment id="development">
    7. <transactionManager type="JDBC"/>
    8. <dataSource type="POOLED">
    9. <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    10. <property name="url" value="jdbc:mysql://localhost:3306/ssm?ServerTimezone=UTC"/>
    11. <property name="username" value="root"/>
    12. <property name="password" value="${password}"/>
    13. dataSource>
    14. environment>
    15. environments>
    16. <mappers>
    17. <mapper resource="mapper/UserMapper.xml"/>
    18. mappers>
    19. configuration>

    ④创建mapper接口

    • MyBatis中的mapper接口相当于以前的dao。
    • 区别:mapper仅仅是接口,不需要提供实现类。

    1. package com.atguigu.mybatis.mapper;
    2. public interface UserMapper {
    3. //添加功能
    4. int insertUser();
    5. }

    ⑤创建MyBatis的映射文件(写sql语句)

    1. 映射文件的命名规则: 表所对应的实体类的类名+Mapper.xml
    2. 一个映射文件对应一个实体类,对应一张表的操作
    3. MyBatis映射文件用于编写SQL,访问以及操作表中的数据
    4. MyBatis映射文件存放的位置是src/main/resources/mappers目录下
    5. MyBatis中可以面向接口操作数据,要保证两个一致:
    • a>mapper接口的全类名和映射文件的命名空间(namespace)保持一致
    • b>mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致 

    1. mapper
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. <mapper namespace="com.atguigu.mybatis.mapper.UserMapper">
    5. <insert id="insertUser">
    6. insert into t_user values (1,'admin','123456',23,'男','12345@qq.com')
    7. insert>
    8. mapper>

    ⑥测试

    1. package com.atguigu.mybatis.test;
    2. import com.atguigu.mybatis.mapper.UserMapper;
    3. import org.apache.ibatis.session.SqlSession;
    4. import org.apache.ibatis.session.SqlSessionFactory;
    5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    6. import org.junit.Test;
    7. import org.apache.ibatis.io.Resources;
    8. import java.io.IOException;
    9. import java.io.InputStream;
    10. public class MybatisTest {
    11. @Test
    12. public void testInsert() throws IOException {
    13. //获取核心配置文件的输入流
    14. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    15. //获取SqlSessionFactoryBuilder对象
    16. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    17. //获取SqlSessionFactory对象
    18. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    19. //获取sql的会话对象SqlSession,是Mybatis提供的操作数据库的对象
    20. SqlSession sqlSession = sqlSessionFactory.openSession();
    21. //执行sql语句,获取UserMapper的代理实现类对象
    22. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    23. //调用mapper接口中的方法,实现添加用户的功能
    24. int i = mapper.insertUser();
    25. sqlSession.commit();
    26. System.out.println(i);
    27. sqlSession.close();
    28. }
    29. }

    ⑦功能优化

    1. package com.atguigu.mybatis.test;
    2. import com.atguigu.mybatis.mapper.UserMapper;
    3. import org.apache.ibatis.session.SqlSession;
    4. import org.apache.ibatis.session.SqlSessionFactory;
    5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    6. import org.junit.Test;
    7. import org.apache.ibatis.io.Resources;
    8. import java.io.IOException;
    9. import java.io.InputStream;
    10. public class MybatisTest {
    11. @Test
    12. public void testInsert() throws IOException {
    13. //获取核心配置文件的输入流
    14. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    15. //获取SqlSessionFactoryBuilder对象
    16. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    17. //获取SqlSessionFactory对象
    18. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    19. //获取sql的会话对象SqlSession(不会自动提交事务),是Mybatis提供的操作数据库的对象
    20. //SqlSession sqlSession = sqlSessionFactory.openSession();
    21. //获取sql的会话对象SqlSession(自动提交事务),是Mybatis提供的操作数据库的对象
    22. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    23. //方式一
    24. // //执行sql语句,获取UserMapper的代理实现类对象
    25. // UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    26. // //调用mapper接口中的方法,实现添加用户的功能
    27. // int i = mapper.insertUser();
    28. //方式二
    29. //提供sql以及唯一标识找到sql并执行,唯一标识是namespace.sqlId
    30. int i = sqlSession.insert("com.atguigu.mybatis.mapper.UserMapper.insertUser");
    31. //提交事务
    32. //sqlSession.commit();
    33. System.out.println(i);
    34. sqlSession.close();
    35. }
    36. }

    ⑧加入log4j日志功能

    Ⅰ.加入依赖

    1. <dependency>
    2. <groupId>log4jgroupId>
    3. <artifactId>log4jartifactId>
    4. <version>1.2.12version>
    5. dependency>

    Ⅱ.加入log4j的配置文件

    1. log4j:configuration SYSTEM "log4j.dtd">
    2. <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    3. <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
    4. <param name="Encoding" value="UTF-8" />
    5. <layout class="org.apache.log4j.PatternLayout">
    6. <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
    7. %m (%F:%L) \n" />
    8. layout>
    9. appender>
    10. <logger name="java.sql">
    11. <level value="debug" />
    12. logger>
    13. <logger name="org.apache.ibatis">
    14. <level value="info" />
    15. logger>
    16. <root>
    17. <level value="debug" />
    18. <appender-ref ref="STDOUT" />
    19. root>
    20. log4j:configuration>

    控制台输出: 

    1. DEBUG 07-23 13:48:44,169 ==> Preparing: insert into t_user values (1,'admin','123456',23,'男','12345@qq.com') (BaseJdbcLogger.java:143)
    2. DEBUG 07-23 13:48:44,197 ==> Parameters: (BaseJdbcLogger.java:143)
    3. DEBUG 07-23 13:48:44,202 <== Updates: 1 (BaseJdbcLogger.java:143)
    4. 1
    5. 进程已结束,退出代码为 0

    ⑨log4j日志的级别

    • FATAL(致命) > ERROR(错误) > WARN(警告) > INFO(信息) > DEBUG(调试)
    • 从左到右打印的内容越来越详细 

    😊文件目录结构

    ⑩测试修改、删除和查询功能

    为方便测试,创建SqlSessionUtil 类:

    1. package com.atguigu.mybatis.utils;
    2. import org.apache.ibatis.io.Resources;
    3. import org.apache.ibatis.session.SqlSession;
    4. import org.apache.ibatis.session.SqlSessionFactory;
    5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    6. import java.io.IOException;
    7. import java.io.InputStream;
    8. public class SqlSessionUtil {
    9. public static SqlSession getSqlSession(){
    10. SqlSession sqlSession = null;
    11. try {
    12. //获取核心配置文件的输入流
    13. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    14. //获取sqlSessionFactoryBuilder对象
    15. SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    16. //获取SqlSessionFactory对象
    17. SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    18. //获取SqlSession对象
    19. sqlSession = sqlSessionFactory.openSession(true);
    20. } catch (IOException e) {
    21. e.printStackTrace();
    22. }
    23. return sqlSession;
    24. }
    25. }

    ⚪修改功能:

    UserMapper.xml:

    1. <update id="updateUser">
    2. update t_user set user_name='root',password='123' where id=1;
    3. update>

    测试代码: 

    1. @Test
    2. public void testUpdate(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. mapper.updateUser();
    6. sqlSession.close();
    7. }

    ⚪删除功能:

    UserMapper.xml:

    1. <delete id="deleteUser">
    2. delete from t_user where id=1
    3. delete>

    测试代码: 

    1. @Test
    2. public void testDelete(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. mapper.deleteUser();
    6. sqlSession.close();
    7. }

    ⚪查询功能:

    ⭐resultType:设置结果类型,即查询的数据要转换为的Java类型
    ⭐resultMap :自定义映射,处理多对一或一对多的映射关系

    (1) 根据用户id查询用户信息

    UserMapper.xml:

    1. <select id="getUserById" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user where id=1
    3. select>

    测试代码: 

    1. @Test
    2. public void testGetUserById(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. User user = mapper.getUserById();
    6. System.out.println(user);
    7. }

    (2)查询所有用户信息

    UserMapper.xml:

    1. <select id="getAllUser" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user
    3. select>

    测试代码:  

    1. @Test
    2. public void testGetAllUser(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. List allUser = mapper.getAllUser();
    6. allUser.forEach(System.out::println);
    7. }

    🐟UserMapper接口 

    三、Mybatis核心配置文件

    1.environments

    配置数据库的环境

    default:设置默认使用的环境的id

    ⚪environment

    设置一个具体的连接数据库的环境

    id:设置环境的唯一标识,不能重复

    ⚪transactionManager

    设置事务管理器

    type:设置事务管理的方式

    type=“JDBC / MANAGED”

    • JDBC:表示使用JDBC中原生的事务管理方式
    • MANAGED:被管理,例如Spring

    ⚪dataSource

    设置数据源

    type:设置数据源的类型

    type="POOLED / UNPOLLED / JNDI"

    • POOLED:表示使用数据库连接池
    • UNPOLLED:表示不使用数据库连接池
    • JNDI:表示使用上下文中的数据源

    2.properties

    创建配置文件

    配置文件内容: 

    1. jdbc.driver=com.mysql.cj.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
    3. jdbc.username=root
    4. jdbc.password=123456

    mybatis-config.xml中修改:

    3.typeAliases

    设置类型别名,即为某一个具体的类型设置一个别名,在Mybatis的范围中,就可以使用别名表示一个具体的类型

    1. <typeAliases>
    2. <typeAlias type="com.atguigu.mybatis.pojo.User" alias="abc">typeAlias>
    3. typeAliases>
    • type:设置需要起别名的类型
    • alias: 设置某个类型的别名,不设置时当前类型默认别名为类名,且不区分大小写
    • 通过包设置类型别名,指定包下所有的类型将全部拥有默认的别名

    🐟Mybatis核心配置文件中的标签必须按照指定的顺序配置

    properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?

    4.mappers

    ⭐以包的方式引入映射文件,但是必须满足两个条件:

    mapper接口和映射文件所在的包必须一致(mapper接口文件在mapper包下,mapper接口映射文件在mappers包下,因此mapper接口和映射文件加载完成后在同一个包下)

    mapper接口的名字和映射文件的名字必须一致

    1. <mappers>
    2. <package name="com.atguigu.mybatis.mapper"/>
    3. mappers>

     5.在idea中能够创建mybatis核心配置文件和映射文件的模板

    ①核心配置文件

    1. configuration
    2. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    4. <configuration>
    5. <properties resource="jdbc.properties"/>
    6. <typeAliases>
    7. <package name="com.atguigu.mybatis.pojo"/>
    8. typeAliases>
    9. <environments default="development">
    10. <environment id="development">
    11. <transactionManager type="JDBC"/>
    12. <dataSource type="POOLED">
    13. <property name="driver" value="${jdbc.driver}"/>
    14. <property name="url" value="${jdbc.url}"/>
    15. <property name="username" value="${jdbc.username}"/>
    16. <property name="password" value="${jdbc.password}"/>
    17. dataSource>
    18. environment>
    19. environments>
    20. <mappers>
    21. <package name=""/>
    22. mappers>
    23. configuration>

    ②映射文件 

    1. mapper
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. <mapper namespace="">
    5. mapper>

    三、获取参数值的两种方式

    • MyBatis获取参数值的两种方式:${} 和 #{}
    • ${}的本质:字符串拼接
    • #{}的本质:占位符赋值
    • ${}使用字符串拼接的方式拼接sql。若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号
    • #{}使用占位符赋值的方式拼接sql。此时为字符串类型或日期类型的字段进行赋值时, 可以自动添加单引号

    1.mapper接口方法的参数是单个字面量类型的参数

    ①字面量

    例如int a = 1; 这个1就是字面量 ,a是变量名

    字面量(literal)用于表达源代码中一个固定值的表示法(notation),整数、浮点数以及字符串等等

    字面量就是没有用标识符封装起来的量,是“值”的原始状态。

    可以使用 ${} 和 #{} 以任意的名称获取参数值(建议使用有意义的)

    注意:${}需要加单引号

    ②例:根据用户名查询用户信息

    1. public interface UserMapper {
    2. //根据用户名查询用户信息
    3. User getUserByUserName(String user_name);
    4. }

    UserMapper.xml 

    1. mapper
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. <mapper namespace="com.atguigu.mybatis.mapper.UserMapper">
    5. <select id="getUserByUserName" resultType="com.atguigu.mybatis.pojo.User">
    6. select * from t_user where user_name = '${user_name}'
    7. select>
    8. mapper>

    测试

    1. public class ParameterTest {
    2. @Test
    3. public void testGetUserByUserName(){
    4. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    5. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    6. User user = mapper.getUserByUserName("admin");
    7. System.out.println(user);
    8. }
    9. }

    2.多个字面量类型的参数

    若mapper接口中的方法参数为多个

    此时MyBatis会自动将这些参数放在一个map集合中

    • 以arg0,arg1...为键,以参数为值
    • 以 param1,param2...为键,以参数为值

    因此只需要通过${}和#{}访问map集合的键,就可以获取相对应的值

    注意:${}需要手动加单引号

    ⭐验证登录

    1. <select id="checkLogin" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user where user_name = #{param1} and password = #{param2}
    3. select>

    测试 

    1. @Test
    2. public void testCheckLogin(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. User user = mapper.checkLogin("admin","123456");
    6. System.out.println(user);
    7. }

    3.map集合类型的参数

    如果mapper接口中的方法需要的参数是多个时,需要手动创建map集合,将这些数据放在 map中

    只需要通过${}和#{}访问map集合的键就可以获取相对应的值

    注意${}需要手动加单引号

    ⭐验证登录(以map集合作为参数)

    1. <select id="checkLoginByMap" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user where user_name=#{user_name} and password=#{password}
    3. select>

    测试 

    1. @Test
    2. public void testCheckLoginByMap(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. Map map = new HashMap<>();
    6. map.put("user_name","admin");
    7. map.put("password","123456");
    8. User user = mapper.checkLoginByMap(map);
    9. System.out.println(user);
    10. }

    4.实体类类型的参数

    若mapper接口中的方法参数为实体类对象时

    此时可以使用${}和#{},通过访问实体类对象中的属性名获取属性值

    注意:${}需要手动加单引号

    ⭐添加用户信息

    1. <insert id="insertUser">
    2. insert into t_user values(null,#{user_name},#{password},#{age},#{gender},#{email})
    3. insert>

    测试

    1. @Test
    2. public void testInsertUser(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. Map map = new HashMap<>();
    6. User user = new User(null,"root","123456",33,"女","123456@qq.com");
    7. mapper.insertUser(user);
    8. }

    5.使用@Param标识参数

    ① @Param注解

    命名参数

    可以通过@Param注解标识mapper接口中的方法参数

    此时,mybatis会将这些参数放在map集合中,

    • 情况一:以@Param注解的value属性值为键以参数为值
    • 情况二:以 param1,param2...为键以参数为值

    只需要通过${}和#{}访问map集合的键就可以获取相对应的值

    注意:${}需要手动加单引号

    ②查询用户信息

    1. <select id="checkLoginByParam" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user where user_name=#{user_name} and password=#{password}
    3. select>

    测试

    1. @Test
    2. public void testCheckLoginByParam(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    5. User user = mapper.checkLoginByParam("admin", "123456");
    6. System.out.println(user);
    7. }

    四、Mybatis的各种查询功能

    1.查询一个实体类对象

    1. <select id="getUserById" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user where id=#{id}
    3. select>
    1. @Test
    2. public void testGetUserById(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. User user = mapper.getUserById(1);
    6. System.out.println(user);
    7. }

    2.查询一个list集合

    1. //查询所有的用户信息
    2. List getAllUser();

    当查询的数据为多条时,不能使用实体类作为返回值

    否则会抛出异常 TooManyResultsException;

    但是若查询的数据只有一条,可以使用实体类或集合(list)作为返回值

    1. <select id="getAllUser" resultType="com.atguigu.mybatis.pojo.User">
    2. select * from t_user
    3. select>
    1. @Test
    2. public void testGetAllUser(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. List user = mapper.getAllUser();
    6. user.forEach(System.out::println);
    7. }

    3.查询单个数据 

    1. //查询用户的总数量
    2. Integer getCount();
    1. <select id="getCount" resultType="java.lang.Integer">
    2. select count(*) from t_user
    3. select>
    1. @Test
    2. public void testGetCount(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. Integer count = mapper.getCount();
    6. System.out.println(count);
    7. }

    ⭐Mybatis提供的类型别名 

    常用类型别名:

    • Integer:Integer、int
    • int:_int、integer
    • Map:map
    • String:string

    4.查询一条数据为map集合

    1. //通过id查询一个用户,以map方式获取
    2. Map getUserByIdToMap(@Param("id") Integer id);
    1. <select id="getUserByIdToMap" resultType="map">
    2. select * from t_user where id = #{id}
    3. select>
    1. @Test
    2. public void testGetUserByIdToMap(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. Map map = mapper.getUserByIdToMap(1);
    6. System.out.println(map);
    7. }

    如果值为NULL,则查询结果不会显示  

    5.查询多条数据为map集合

    1. //查询所有的用户信息为map集合
    2. Map getAllUserToMap();

    直接查询会报错,需要把查询出来的结果放在能够存储map集合的list集合中 

    解决方案一:放在list集合中

    将表中的数据以map集合的方式查询,一条数据对应一个map;

    若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取 

    1. //查询所有的用户信息为map集合
    2. List> getAllUserToMap();
    1. <select id="getAllUserToMap" resultType="map">
    2. select * from t_user
    3. select>
    1. @Test
    2. public void testGetAllUserToMap(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. List> allUserToMap = mapper.getAllUserToMap();
    6. System.out.println(allUserToMap);
    7. }

    解决方案二:使用@MapKey注解

    将表中的数据以map集合的方式查询,一条数据对应一个map;

    若有多条数据,就会产生多个map集合,并且最终要以一个map的方式返回数据,此时通过@MapKey注解设置map集合的键,值是每条数据所对应的 map集合 

    1. //查询所有的用户信息为map集合
    2. @MapKey("id")
    3. Map getAllUserToMap();
    1. @Test
    2. public void testGetAllUserToMap(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    5. // List> allUserToMap = mapper.getAllUserToMap();
    6. Map allUserToMap = mapper.getAllUserToMap();
    7. System.out.println(allUserToMap);
    8. }

    查询结果:

    1. DEBUG 07-25 12:31:16,444 ==> Preparing: select * from t_user (BaseJdbcLogger.java:143)
    2. DEBUG 07-25 12:31:16,475 ==> Parameters: (BaseJdbcLogger.java:143)
    3. DEBUG 07-25 12:31:16,498 <== Total: 2 (BaseJdbcLogger.java:143)
    4. {1={password=123456, gender=男, user_name=admin, id=1, age=20, email=123456@qq.com}, 2={password=123456, gender=女, user_name=root, id=2, age=33, email=123456@qq.com}}
    5. 进程已结束,退出代码为 0

    五、特殊SQL的执行

    1.模糊查询

    1. //根据用户名进行模糊查询
    2. List getUserByLike(@Param("mohu") String mohu);
    1. <select id="getUserByLike" resultType="user">
    2. select * from t_user where user_name like "%"#{mohu}"%"
    3. select>
    1. @Test
    2. public void testGetUserByLike(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    5. List list = mapper.getUserByLike("a");
    6. list.forEach(System.out::println);
    7. }

    2.批量删除

    1. //批量删除
    2. void deleteMoreUser(@Param("ids") String ids);
    1. <delete id="deleteMoreUser">
    2. delect from t_user where id in (${ids})
    3. delete>
    1. @Test
    2. public void testDeleteMoreUser(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    5. mapper.deleteMoreUser("1,2");
    6. }

    3.动态设置表名

    只能使用${}

    1. //动态设置表名,查询用户信息
    2. List getUserList(@Param("tableName") String tableName);
    1. <select id="getUserList" resultType="user">
    2. select * from ${tableName}
    3. select>
    1. @Test
    2. public void testGetUserList(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    5. List user = mapper.getUserList("t_user");
    6. user.forEach(System.out::println);
    7. }

    4.添加功能获取自增的主键

    1. //添加用户信息并获取自增的主键
    2. void insertUser(User user);

    因为增删改的返回值固定,只能是受影响的行数

    ⚪useGeneratedKeys

    当前添加功能使用自增的主键

    ⚪keyProperty

    将添加的数据的自增主键为实体类类型的参数的属性赋值

    1. <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    2. insert into t_user values (null,#{user_name},#{password},#{age},#{gender},#{email})
    3. insert>
    1. @Test
    2. public void testInsertUser(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    5. User user = new User(null,"Tom","142356",25,"男","142356@123.com");
    6. mapper.insertUser(user);
    7. System.out.println(user);
    8. }

    六、自定义映射resultMap

    ⭐准备工作

    实体类和表的创建

    1. package com.atguigu.mybatis.pojo;
    2. public class Emp {
    3. private Integer empId;
    4. private String empName;
    5. private Integer age;
    6. private String gender;
    7. public Emp() {
    8. }
    9. public Emp(Integer empId, String empName, Integer age, String gender) {
    10. this.empId = empId;
    11. this.empName = empName;
    12. this.age = age;
    13. this.gender = gender;
    14. }
    15. public Integer getEmpId() {
    16. return empId;
    17. }
    18. public void setEmpId(Integer empId) {
    19. this.empId = empId;
    20. }
    21. public String getEmpName() {
    22. return empName;
    23. }
    24. public void setEmpName(String empName) {
    25. this.empName = empName;
    26. }
    27. public Integer getAge() {
    28. return age;
    29. }
    30. public void setAge(Integer age) {
    31. this.age = age;
    32. }
    33. public String getGender() {
    34. return gender;
    35. }
    36. public void setGender(String gender) {
    37. this.gender = gender;
    38. }
    39. @Override
    40. public String toString() {
    41. return "Emp{" +
    42. "empId=" + empId +
    43. ", empName='" + empName + '\'' +
    44. ", age=" + age +
    45. ", gender='" + gender + '\'' +
    46. '}';
    47. }
    48. }
    1. package com.atguigu.mybatis.pojo;
    2. public class Dept {
    3. private Integer deptId;
    4. private String deptName;
    5. public Dept() {
    6. }
    7. public Dept(Integer deptId, String deptName) {
    8. this.deptId = deptId;
    9. this.deptName = deptName;
    10. }
    11. public Integer getDeptId() {
    12. return deptId;
    13. }
    14. public void setDeptId(Integer deptId) {
    15. this.deptId = deptId;
    16. }
    17. public String getDeptName() {
    18. return deptName;
    19. }
    20. public void setDeptName(String deptName) {
    21. this.deptName = deptName;
    22. }
    23. @Override
    24. public String toString() {
    25. return "Dept{" +
    26. "deptId=" + deptId +
    27. ", deptName='" + deptName + '\'' +
    28. '}';
    29. }
    30. }

    例:根据id查询员工信息

    1. public class EmpMapper {
    2. //根据id查询员工信息
    3. Emp getEmpByEmpId(@Param("empId") Integer empId);
    4. }
    1. <mapper namespace="com.atguigu.mybatis.mapper.EmpMapper">
    2. <select id="getEmpByEmpId" resultType="Emp">
    3. select * from t_emp where emp_id=#{empId}
    4. select>
    5. mapper>
    1. @Test
    2. public void testGetEmpById(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp emp = mapper.getEmpByEmpId(1);
    6. System.out.println(emp);
    7. }

    字段和属性不一致时的查询结果

    解决方式一:为查询的字段设置别名,和属性名保持一致

    1. <select id="getEmpByEmpId" resultType="Emp">
    2. select emp_id empId,emp_name empName,age,gender from t_emp where emp_id=#{empId}
    3. select>

    解决方式二: 当字段复合MySQL的要求使用_,而属性复合Java的要求使用驼峰,此时可以在MyBatis的核心配置文件中设置一个全局配置,可以自动将下划线映射为驼峰

    1. <settings>
    2. <setting name="mapUnderscoreToCamelCase" value="true"/>
    3. settings>

    1.resultMap处理字段和属性的映射关系(字段和属性不一致)

    若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射

    resultMap:设置自定义映射

    属性:

    • id:表示自定义映射的唯一标识
    • type:查询的数据要映射的实体类的类型

    子标签:

    • id:设置主键和实体类种属性的映射关系
    • result:设置普通字段和实体类种属性的映射关系
    • association:设置多对一的映射关系(处理实体类类型的属性)
    • collection:设置一对多的映射关系

    属性:

    • property:设置映射关系中实体类中的属性名,必须是处理的实体类类型中的属性名
    • column:设置映射关系中表中的字段名,必须是sql查询出的某个字段

    1. <resultMap id="empResultMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. resultMap>
    7. <select id="getEmpByEmpId" resultMap="empResultMap">
    8. select * from t_emp where emp_id=#{empId}
    9. select>

    2.多对一映射处理

    ⭐获取员工以及所对应的部门信息

    1. //获取员工以及所对应的部门信息
    2. Emp getEmpAndDeptByEmpId(@Param("empId") Integer empId);

    ①级联方式处理映射关系

    1. <resultMap id="empAndDeptResultMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. <result column="dept_id" property="dept.deptId">result>
    7. <result column="dept_name" property="dept.deptName">result>
    8. resultMap>
    9. <select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
    10. select t_emp.*,t_dept.* from t_emp
    11. left join t_dept
    12. on t_emp.dept_id = t_dept.dept_id
    13. where t_emp.emp_id=#{empId}
    14. select>

    测试: 

    1. @Test
    2. public void testGetEmpAndDeptByEmpId(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp emp = mapper.getEmpAndDeptByEmpId(1);
    6. System.out.println(emp);
    7. }

    ②使用association处理映射关系

    1. <resultMap id="empAndDeptResultMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. <association property="dept" javaType="Dept">
    7. <id column="dept_id" property="deptId">id>
    8. <result column="dept_name" property="deptName">result>
    9. association>
    10. resultMap>
    • association:处理多对一的映射关系(处理实体类类型的属性)
    • property:设置需要处理映射关系的属性的属性名
    • javaType:设置要处理的属性的类型  

    ③ 分步查询

    1. import com.atguigu.mybatis.pojo.Dept;
    2. import org.apache.ibatis.annotations.Param;
    3. public interface DeptMapper {
    4. //通过分步查询查询员工以及所对应的部门信息的第二步
    5. Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);
    6. }
    1. mapper
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. <mapper namespace="com.atguigu.mybatis.mapper.DeptMapper">
    5. <select id="getEmpAndDeptByStepTwo" resultType="Dept">
    6. select * from t_dept where dept_id=#{deptId}
    7. select>
    8. mapper>

    EmpMapper: 

    • property:设置需要处理映射关系的属性的属性名
    • select:设置分步查询的sql的唯一标识
    • column:将查询出的某个字段作为分步查询的sql的条件
    • fetchType:在开启了延迟加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载
    • fetchType=“eager(延迟加载)/lazy(立即加载)”
    1. //通过分步查询查询员工以及所对应的部门信息的第一步
    2. Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);
    1. <resultMap id="empAndDeptByStepResultMap" type="Emp">
    2. <id column="emp_id" property="empId">id>
    3. <result column="emp_name" property="empName">result>
    4. <result column="age" property="age">result>
    5. <result column="gender" property="gender">result>
    6. <association property="dept" fetchType="eager"
    7. select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    8. column="dept_id">
    9. association>
    10. resultMap>
    11. <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
    12. select * from t_emp where emp_id=#{empId}
    13. select>
    1. @Test
    2. public void testGetEmpAndDeptByStep(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. Emp emp = mapper.getEmpAndDeptByStepOne(1);
    6. System.out.println(emp);
    7. }

    3.一对多映射处理

    1. //查询部门以及部门中的员工信息
    2. Dept getDetptAndEmpByDeptId(@Param("deptId") Integer deptId);

    ①collection

    collection:处理一对多的映射关系(处理集合类型的属性)

    ofType:设置集合类型的属性中存储的数据类型

    1. <resultMap id="deptAndEmpResultMap" type="Dept">
    2. <id column="dept_id" property="deptId">id>
    3. <result column="dept_name" property="deptName">result>
    4. <collection property="emps" ofType="Emp">
    5. <id column="emp_id" property="empId">id>
    6. <result column="emp_name" property="empName">result>
    7. <result column="age" property="age">result>
    8. <result column="gender" property="gender">result>
    9. collection>
    10. resultMap>
    11. <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
    12. select *
    13. from t_dept
    14. left join t_emp
    15. on t_dept.dept_id = t_emp.dept_id
    16. where t_dept.dept_id = #{deptId}
    17. select>
    1. @Test
    2. public void testGetDeptAndEmpByDeptId(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
    5. Dept dept = mapper.getDeptAndEmpByDeptId(1);
    6. System.out.println(dept);
    7. }

    输出结果:

    1. DEBUG 07-28 13:54:49,919 ==> Preparing: select * from t_dept left join t_emp on t_dept.dept_id = t_emp.dept_id where t_dept.dept_id = ? (BaseJdbcLogger.java:143)
    2. DEBUG 07-28 13:54:49,949 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:143)
    3. DEBUG 07-28 13:54:49,970 <== Total: 2 (BaseJdbcLogger.java:143)
    4. Dept{deptId=1, deptName='A', emps=[Emp{empId=1, empName='Tom', age=20, gender='男', dept=null}, Emp{empId=4, empName='Jeny', age=25, gender='男', dept=null}]}
    5. 进程已结束,退出代码为 0

    ②分步查询

    DeptMapper:
    1. //通过分步查询查询部门以及部门中的员工信息的第一步
    2. Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);
    1. <resultMap id="deptAndEmpResultMapByStep" type="Dept">
    2. <id column="dept_id" property="deptId">id>
    3. <result column="dept_name" property="deptName">result>
    4. <collection property="emps"
    5. select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
    6. column="dept_id">collection>
    7. resultMap>
    8. <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
    9. select * from t_dept where dept_id = #{deptId}
    10. select>
    EmpMapper:
    1. //通过分步查询查询部门以及部门中的员工信息的第二步
    2. List getDeptAndEmpByStepTwo(@Param("deptId")Integer deptId);
    1. <select id="getDeptAndEmpByStepTwo" resultType="Emp">
    2. select * from t_emp where dept_id = #{deptId}
    3. select>

    ⭐分步查询的优点

    可以实现延迟加载

    但是必须在核心配置文件中设置全局配置信息:

    • lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
    • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载

    此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。

    此时可通过association和 collection中的fetchType属性设置当前的分步查询是否使用延迟加载

    fetchType="lazy(延迟加载) / eager(立即加载)"

    1. <settings>
    2. <setting name="mapUnderscoreToCamelCase" value="true"/>
    3. <setting name="lazyLoadingEnabled" value="true"/>
    4. <setting name="aggressiveLazyLoading" value="false"/>
    5. settings>

    七、Mybatis动态SQL 

    Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能

    意义:解决拼接SQL语句字符串时的痛点问题

    1.if

    if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之,标签中的内容不会执行

    1. public interface dynamicSQLMapper {
    2. //根据条件查询员工信息
    3. List getEmpByCondition(Emp emp);
    4. }
    1. <select id="getEmpByCondition" resultType="Emp">
    2. select * from t_emp where
    3. <if test="empName != null and empName != ''">
    4. emp_name = #{empName}
    5. if>
    6. <if test="age != null and age != ''">
    7. and age = #{age}
    8. if>
    9. <if test="gender != null and gender != ''">
    10. and gender = #{gender}
    11. if>
    12. select>
    1. @Test
    2. public void testGetEmpByCondition(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. dynamicSQLMapper mapper = sqlSession.getMapper(dynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"Tom",20,"男");
    6. List list = mapper.getEmpByCondition(emp);
    7. list.forEach(System.out::println);

    2.where

    where和if一般结合使用:

    • 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
    • 若where标签中有条件成立,则会自动生成where关键字
    • 会将条件最前方多余的and去掉

    注意:where标签不能去掉条件最后多余的and

    1. <select id="getEmpByCondition" resultType="Emp">
    2. select * from t_emp
    3. <where>
    4. <if test="empName != null and empName != ''">
    5. emp_name = #{empName}
    6. if>
    7. <if test="age != null and age != ''">
    8. and age = #{age}
    9. if>
    10. <if test="gender != null and gender != ''">
    11. and gender = #{gender}
    12. if>
    13. where>
    14. select>

    3.trim

    trim用于去掉或添加标签中的内容

    常用属性:

    • prefix:在标签中内容的前面添加某些内容
    • prefixOverrides:在标签中内容的前面去掉某些内容
    • suffix:在标签中内容的后面添加某些内容
    • suffixOverrides:在标签中内容的后面去掉某些内容

    1. <select id="getEmpByCondition" resultType="Emp">
    2. select * from t_emp
    3. <trim prefix="where" suffixOverrides="and">
    4. <if test="empName != null and empName != ''">
    5. emp_name = #{empName} and
    6. if>
    7. <if test="age != null and age != ''">
    8. age = #{age} and
    9. if>
    10. <if test="gender != null and gender != ''">
    11. gender = #{gender}
    12. if>
    13. trim>
    14. select>

    4.choose、when、otherwise

    choose、when、otherwise相当于if...else if..else

    • when至少设置一个,otherwise最多设置一个
    1. //使用choose查询员工信息
    2. List getEmpByChoose(Emp emp);
    1. <select id="getEmpByChoose" resultType="Emp">
    2. select * from t_emp
    3. <where>
    4. <choose>
    5. <when test="empName != null and empName !=''">
    6. emp_name = #{empName}
    7. when>
    8. <when test="age != null and age != ''">
    9. age = #{age}
    10. when>
    11. <when test="gender != null and gender != ''">
    12. gender = #{gender}
    13. when>
    14. choose>
    15. where>
    16. select>
    1. @Test
    2. public void testGetEmpByChoose(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. dynamicSQLMapper mapper = sqlSession.getMapper(dynamicSQLMapper.class);
    5. Emp emp = new Emp(null,"",null,"");
    6. List list = mapper.getEmpByChoose(emp);
    7. list.forEach(System.out::println);
    8. }

    5.foreach

    • collection:设置要循环的数组或集合
    • item:用一个字符串表示数组或集合中的每一个数据
    • separator:设置每次循环的数据之间的分隔符
    • open:循环的所有内容以什么开始
    • close:循环的所有内容以什么结束

    批量添加

    1. //批量添加员工信息
    2. void insertMoreEmp(@Param("emps") List emps);
    1. <insert id="insertMoreEmp">
    2. insert into t_emp values
    3. <foreach collection="emps" item="emp" separator=",">
    4. (null,#{emp.empName},#{emp.age},#{emp.gender},null)
    5. foreach>
    6. insert>
    1. @Test
    2. public void testInsertMoreEmp(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. dynamicSQLMapper mapper = sqlSession.getMapper(dynamicSQLMapper.class);
    5. Emp emp1 = new Emp(null,"小明1",20,"男");
    6. Emp emp2 = new Emp(null,"小明2",20,"男");
    7. Emp emp3 = new Emp(null,"小明3",20,"男");
    8. List list = Arrays.asList(emp1, emp2, emp3);
    9. mapper.insertMoreEmp(list);
    10. }

    批量删除 

    1. //批量删除
    2. void deleteMoreEmp(@Param("empIds") Integer[] empIds);

    方式一: 

    1. <delete id="deleteMoreEmp">
    2. delete
    3. from t_emp
    4. where emp_id in (
    5. <foreach collection="empIds" item="empId" separator=",">
    6. #{empId}
    7. foreach>
    8. );
    9. delete>

    方式二: 

    1. <delete id="deleteMoreEmp">
    2. delete
    3. from t_emp
    4. where emp_id in
    5. <foreach collection="empIds" item="empId" separator="," open="(" close=")">
    6. #{empId}
    7. foreach>
    8. delete>

    方式三:

    1. <delete id="deleteMoreEmp">
    2. delete
    3. from t_emp
    4. where
    5. <foreach collection="empIds" item="empId" separator="or">
    6. emp_id = #{empId}
    7. foreach>
    8. delete>

    测试: 

    1. @Test
    2. public void testDeleteMoreEmp(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. dynamicSQLMapper mapper = sqlSession.getMapper(dynamicSQLMapper.class);
    5. Integer[] empIds = new Integer[]{6,7};
    6. mapper.deleteMoreEmp(empIds);
    7. }

    6.SQL片段        

    sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引用

    八、MyBatis的缓存

    1.MyBatis的一级缓存

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

    MyBatis的一级缓存默认开启

    1. //根据员工id查询员工信息
    2. Emp getEmpById(@Param("empId") Integer empId);
    1. <select id="getEmpById" resultType="Emp">
    2. select * from t_emp where emp_id = #{empId}
    3. select>
    1. @Test
    2. public void testGetEmpById(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
    5. Emp emp1 = mapper.getEmpById(1);
    6. System.out.println(emp1);
    7. Emp emp2 = mapper.getEmpById(1);
    8. System.out.println(emp2);
    9. SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
    10. CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    11. Emp emp3 = mapper1.getEmpById(1);
    12. System.out.println(emp3);
    13. }

    查询结果:可以看出,同一个SqlSession查询的数据会被缓存,查询语句只执行一次

    1. DEBUG 07-29 11:56:46,274 ==> Preparing: select * from t_emp where emp_id = ? (BaseJdbcLogger.java:143)
    2. DEBUG 07-29 11:56:46,304 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:143)
    3. DEBUG 07-29 11:56:46,325 <== Total: 1 (BaseJdbcLogger.java:143)
    4. Emp{empId=1, empName='Tom', age=20, gender='男'}
    5. Emp{empId=1, empName='Tom', age=20, gender='男'}
    6. DEBUG 07-29 11:56:46,369 ==> Preparing: select * from t_emp where emp_id = ? (BaseJdbcLogger.java:143)
    7. DEBUG 07-29 11:56:46,370 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:143)
    8. DEBUG 07-29 11:56:46,372 <== Total: 1 (BaseJdbcLogger.java:143)
    9. Emp{empId=1, empName='Tom', age=20, gender='男'}
    10. 进程已结束,退出代码为 0

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

    1. 不同的SqlSession对应不同的一级缓存
    2. 同一个SqlSession但是查询条件不同
    3. 同一个SqlSession两次查询期间执行了任何一次增删改操作(增删改会改变数据库中原有的数据,因此需要重新查询)
    4. 同一个SqlSession两次查询期间手动清空了缓存(sqlSession.clearCache()) 

    2.MyBatis的二级缓存

    二级缓存是SqlSessionFactory级别

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

    ⭐二级缓存开启的条件

    • 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
    • 映射文件中设置标签
    • 二级缓存必须在SqlSession关闭或提交之后有效
    • 查询的数据所转换的实体类类型必须实现序列化的接口

    1. @Test
    2. public void testCache() throws IOException {
    3. //测试二级缓存不可以使用工具类
    4. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    6. SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
    7. CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    8. Emp emp1 = mapper1.getEmpById(1);
    9. System.out.println(emp1);
    10. sqlSession1.close();
    11. SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
    12. CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
    13. Emp emp2 = mapper2.getEmpById(1);
    14. System.out.println(emp2);
    15. sqlSession2.close();
    16. }

    ⭐使二级缓存失效的情况

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

    3.二级缓存的相关配置

    在mapper配置文件中添加的cache标签可以设置一些属性:

    ①eviction属性:缓存回收策略,默认为 LRU。

    • LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    ②flushInterval属性:刷新间隔,单位毫秒

    默认情况是不设置,即没有刷新间隔,缓存仅仅调用语句时刷新

    ③size属性:引用数目

    正整数

    代表缓存最多可以存储多少个对象,太大容易导致内存溢出

    ④readOnly:只读, true/false

    • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
    • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

    4.MyBatis缓存查询的顺序

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

    5.整合第三方缓存EHCache

    ①添加依赖

    1. <dependency>
    2. <groupId>org.mybatis.cachesgroupId>
    3. <artifactId>mybatis-ehcacheartifactId>
    4. <version>1.2.2version>
    5. dependency>
    6. <dependency>
    7. <groupId>ch.qos.logbackgroupId>
    8. <artifactId>logback-classicartifactId>
    9. <version>1.2.3version>
    10. dependency>

    ②各jar包功能

    ③创建EHCache的配置文件ehcache.xml

    1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    2. xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    3. <diskStore path="E:\atguigu\ehcache"/>
    4. <defaultCache
    5. maxElementsInMemory="1000"
    6. maxElementsOnDisk="10000000"
    7. eternal="false"
    8. overflowToDisk="true"
    9. timeToIdleSeconds="120"
    10. timeToLiveSeconds="120"
    11. diskExpiryThreadIntervalSeconds="120"
    12. memoryStoreEvictionPolicy="LRU">
    13. defaultCache>
    14. ehcache>

    ④设置二级缓存的类型

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

    ⑤加入logback日志

    存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日 志。 创建logback的配置文件logback.xml

    1. <configuration debug="true">
    2. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    3. <encoder>
    4. <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
    5. [%msg]%npattern>
    6. encoder>
    7. appender>
    8. <root level="DEBUG">
    9. <appender-ref ref="STDOUT" />
    10. root>
    11. <logger name="com.atguigu.mybatis.mapper" level="DEBUG"/>
    12. configuration>

    ⑥EHCache配置文件说明

    九、MyBatis的逆向工程

    正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。 Hibernate是支持正向工程的。

    逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:

    • Java实体类
    • Mapper接口
    • Mapper映射文件

    1.创建逆向工程的步骤

    ①添加依赖和插件

    1. <build>
    2. <plugins>
    3. <plugin>
    4. <groupId>org.mybatis.generatorgroupId>
    5. <artifactId>mybatis-generator-maven-pluginartifactId>
    6. <version>1.3.0version>
    7. <dependencies>
    8. <dependency>
    9. <groupId>org.mybatis.generatorgroupId>
    10. <artifactId>mybatis-generator-coreartifactId>
    11. <version>1.3.2version>
    12. dependency>
    13. <dependency>
    14. <groupId>mysqlgroupId>
    15. <artifactId>mysql-connector-javaartifactId>
    16. <version>8.0.22version>
    17. dependency>
    18. dependencies>
    19. plugin>
    20. plugins>
    21. build>

    ②创建MyBatis的核心配置文件

    1. configuration
    2. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    4. <configuration>
    5. <properties resource="jdbc.properties"/>
    6. <settings>
    7. <setting name="mapUnderscoreToCamelCase" value="true"/>
    8. <setting name="lazyLoadingEnabled" value="true"/>
    9. <setting name="aggressiveLazyLoading" value="false"/>
    10. settings>
    11. <typeAliases>
    12. <package name="com.atguigu.mybatis.pojo"/>
    13. typeAliases>
    14. <environments default="development">
    15. <environment id="development">
    16. <transactionManager type="JDBC"/>
    17. <dataSource type="POOLED">
    18. <property name="driver" value="${jdbc.driver}"/>
    19. <property name="url" value="${jdbc.url}"/>
    20. <property name="username" value="${jdbc.username}"/>
    21. <property name="password" value="${jdbc.password}"/>
    22. dataSource>
    23. environment>
    24. environments>
    25. <mappers>
    26. <package name="com.atguigu.mybatis.mapper"/>
    27. mappers>
    28. configuration>

    ③创建逆向工程的配置文件

    文件名必须是:generatorConfig.xml

    1. generatorConfiguration
    2. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    3. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    4. <generatorConfiguration>
    5. <context id="DB2Tables" targetRuntime="MyBatis3">
    6. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    7. connectionURL="jdbc:mysql://localhost:3306/mybatis?
    8. serverTimezone=UTC"
    9. userId="root"
    10. password="123456">
    11. jdbcConnection>
    12. <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo"
    13. targetProject=".\src\main\java">
    14. <property name="enableSubPackages" value="true" />
    15. <property name="trimStrings" value="true" />
    16. javaModelGenerator>
    17. <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
    18. targetProject=".\src\main\resources">
    19. <property name="enableSubPackages" value="true" />
    20. sqlMapGenerator>
    21. <javaClientGenerator type="XMLMAPPER"
    22. targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
    23. <property name="enableSubPackages" value="true" />
    24. javaClientGenerator>
    25. <table tableName="t_emp" domainObjectName="Emp"/>
    26. <table tableName="t_dept" domainObjectName="Dept"/>
    27. context>
    28. generatorConfiguration>

    ④执行MBG插件的generate目标

    ⑤效果

    2.QBC查询

    1. @Test
    2. public void testMBG(){
    3. SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    4. EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    5. // Emp emp = mapper.selectByPrimaryKey(1); 根据主键id查询数据
    6. // System.out.println(emp);
    7. // List list = mapper.selectByExample(null); 根据条件查询,五条件即查询所有数据
    8. // list.forEach(System.out::println);
    9. //根据条件查询
    10. EmpExample example = new EmpExample();
    11. example.createCriteria().andEmpNameEqualTo("Tom").andAgeGreaterThanOrEqualTo(15);
    12. example.or().andGenderEqualTo("男");
    13. List list = mapper.selectByExample(example);
    14. list.forEach(System.out::println);
    15. }

    十、分页插件

    limit index,pageSize
    • index:当前页的起始索引,index = (pageNum-1) * pageSize 
    • pageSize:每页显示的条数
    • pageNum:当前页的页码
    • count:总记录数
    • totalPage:总页数 totalPage = count / pageSize;
    1. if(count % pageSize != 0){
    2. totalPage += 1;
    3. }
    4. pageSize=4,pageNum=1,index=0 limit 0,4
    5. pageSize=4,pageNum=3,index=8 limit 8,4
    6. pageSize=4,pageNum=6,index=20 limit 8,4

    首页 上一页 2 3 4 5 6 下一页 末页

    1.分页插件的使用步骤

    ①添加依赖

    1. <dependency>
    2. <groupId>com.github.pagehelpergroupId>
    3. <artifactId>pagehelperartifactId>
    4. <version>5.2.0version>
    5. dependency>

    ②配置分页插件

    在MyBatis的核心配置文件中配置插件

    1. <plugins>
    2. <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    3. plugins>

    2.分页插件的使用

    • 在查询功能之前使用PageHelper.startPage(int pageNum, int pageSize)开启分页功能
    • pageNum:当前页的页码
    • pageSize:每页显示的条数
    • 在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据
    • list:分页之后的数据
    • navigatePages:导航分页的页码数

    😵分页相关数据

    PageInfo{

    pageNum=8, pageSize=4, size=2,

    startRow=29, endRow=30, total=30,

    pages=8, list = Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,

    pages=8, reasonable=false, pageSizeZero=false},

    prePage(上一页页码)=7, nextPage(下一页页码)=0,

    isFirstPage=false, isLastPage=true, hasPreviousPage=true, hasNextPage=false,

    navigatePages=5, navigateFirstPage4, navigateLastPage8, navigatepageNums=[4, 5, 6, 7, 8] }

    • pageNum:当前页的页码
    • pageSize:每页显示的条数
    • size:当前页显示的真实条数
    • total:总记录数 pages:总页数
    • prePage:上一页的页码
    • nextPage:下一页的页码
    • isFirstPage/isLastPage:是否为第一页/最后一页
    • hasPreviousPage/hasNextPage:是否存在上一页/下一页
    • navigatePages:导航分页的页码数
    • navigatepageNums:导航分页的页码,[1,2,3,4,5]
  • 相关阅读:
    SAP物料分类账的简单理解
    .NET应用如何防止被反编译
    Maven 官网查找依赖包
    nodejs midway+typeorm搭建后台方案
    ChatGPT在虚拟旅游和文化体验中的潜在作用如何?
    ElasticSearch集群搭建及启动异常的问题
    MySQL 流程控制 的详细讲解
    代码审查单
    IDEA配置
    【安鸾靶场】实战渗透
  • 原文地址:https://blog.csdn.net/m0_52982868/article/details/125902508