Mybatis框架学习

MyBatis(简化数据库操作的持久层框架)

1 MyBatis 介绍

官方文档

MyBatis 中 文 手 册
Maven 仓库

需要什么 jar 包,搜索得到对应的 maven dependency
在这里插入图片描述
在这里插入图片描述

为什么需要 MyBatis

● 传统的 Java 程序操作 DB 分析
在这里插入图片描述

Mybatis基本介绍

  1. MyBatis 是一个持久层框架
  2. 前身是 ibatis, 在 ibatis3.x 时,更名为 MyBatis
  3. MyBatis 在 java 和 sql 之间提供更灵活的映射方案
  4. mybatis 可以将对数据表的操作(sql,方法)等等直接剥离,写到 xml 配置文件,实现和 java代码的解耦
  5. mybatis 通过 SQL 操作 DB, 建库建表的工作需要程序员完成

MyBatis 工作原理

在这里插入图片描述

2 MyBatis 快速入门

快速入门需求说明

要求: 开发一个 MyBatis 项目,通过 MyBatis 的方式可以完成对 monster 表的 crud 操作

快速入门-代码实现

  1. 创建 mybatis 数据库 - monster 表
CREATE DATABASE `mybatis`
USE `mybatis`

CREATE TABLE `monster` (
	`id` INT NOT NULL AUTO_INCREMENT,
	`age` INT NOT NULL,
	`birthday` DATE DEFAULT NULL,
	`email` VARCHAR(255) NOT NULL,
	`gender` TINYINT NOT NULL, 	# TINYINT 的 0 1分别表示男女 
	`salary` DOUBLE NOT NULL,
	PRIMARY KEY(`id`)
) CHARSET=utf8
  1. 创建 maven 项目, 方便项目需要 jar 包管理

在这里插入图片描述

导入依赖
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <!--表示该jar包作用范围在test目录下, 在src目录下没法使用-->
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.7</version>
    </dependency>

  </dependencies>

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

在这里插入图片描述

  1. 创建 resources/mybatis-config.xml

这个是作为mybatis的配置文件。从mybatis官方文档中找出,直接复制粘贴在这里插入图片描述在这里插入图片描述

mybatis-config.xml: (不一定非得叫这个名)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--下面的这些配置的顺序还是有讲究的-->

    <properties resource="application.properties"/>         <!-- 告诉mybatis-config.xml我的外部的properties文件在哪里 -->

    <!--配置Mybatis自带的日志输出, 查看原声的sql-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--设置类型别名-->
    <typeAliases>
        <typeAlias type="com.maven.quickstart.entity.Monster" alias="Monster"/>
    </typeAliases>
    


    <environments default="development">
        <environment id="development">
            <!--配置事务管理器-->
            <transactionManager type="JDBC"/>
            <!--配置数据源-->
            <dataSource type="POOLED">
                <!--配置驱动-->
                <property name="driver" value="${driver}"/>
                <!--配置连接mysql-url
                老韩解读:
                1. jdbc:mysql 协议
                2. 127.0.0.1:3306 : 指定连接mysql的ip+port
                3. mybatis: 连接的DB
                4. useSSL=true 表示使用安全连接
                5. &amp; 表示 & 防止解析错误
                6. useUnicode=true : 使用unicode 作用是防止编码错误
                7. characterEncoding=UTF-8 指定使用utf-8, 防止中文乱码
                8. 老韩温馨提示:不要背,直接使用即可
                -->
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--这里我们配置需要关联的Mapper.xml文件-->
    <mappers>
        <mapper resource="com/maven/quickstart/mapper/MonsterMapper.xml"/>
    </mappers>
</configuration>

上面的某些东西如果不想配置的非常死,可能需要从外面导入properties配置文件。
这里注意,properties配置文件需要在下面的特定的路径下:项目名/src/main/resources/xxx.properties

application.properties (作为mybatis-config.properties的属性文件)

driver=com.mysql.cj.jdbc.Driver
username=root
password=输入密码
  1. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\entity\Monster.java

要求大家这里的实体类属性名和表名字段保持一致。

public class Monster {
    private Integer id;
    private Integer age;
    private String name;
    private String email;
    private Date birthday;
    private double salary;
    private Integer gender;
....方法....
}
  1. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\mapper\MonsterMapper.java

这里的mapper是一个接口,写了很多的方法, 是用于声明操作monster表的方法. 这些方法可以通过注解或xml文件来实现.

/**
 * @Author: GQLiu
 * @DATE: 2024/3/7 22:29
 * 接口, 用于生命操作monster表的方法
 * 这些方法可以通过注解或xml文件来实现。
 */
public interface MonsterMapper {
    // 添加monster
    public void addMonster(Monster monster);

    // 根据id删除monster
    public void delMonster(Integer id);

    // 修改Monster
    public void updateMonster(Monster monster);

    // 根据id查询
    public Monster getMonsterById(Integer id);

    // 查询所有的Monster
    public List<Monster> findAllMonster();
}

  1. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\mapper\MonsterMapper.xml

这是一个mapper xml文件
该文件可以去实现对应的接口的方法。
namespace 指定该xml文件和哪个接口对应

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
这是一个mapper xml文件
该文件可以去实现对应的接口的方法。
namespace 指定该xml文件和哪个接口对应
-->


<mapper namespace="com.maven.quickstart.mapper.MonsterMapper">
    <!--
    配置addMonster
    id=addMonster 就是接口的方法名
    parameterType=“com.maven.quickstart.entity.Monster" 就是放入的形参的类型
    注意com.maven.quickstart.entity.Monster 可以简写
    写sql语句 => 建议先在navicat中写,测试通过后再拿过来

     (`age`, `birthday`, `email`, `gender`, `name`, `salary`) 表示表的数据

     (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary}) 表示传入的monster的对象属性
     #{age} 表示monster的属性名。
     useGeneratedKeys="true" 表示取出mysql自己设置的主键
     keyProperty="id" 表示主键为 id
    -->
    <insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `monster`
        (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
        VALUES (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary})

    </insert>

    <!--
    配置实现delMonster方法, 根据id删除Monster
    这里的 java.lang.Integer 是java类型, 可以简写成Integer

    -->
    <delete id="delMonster" parameterType="Integer">
        DELETE FROM `monster` WHERE id=#{id};
    </delete>

    <!--配置实现updateMonster-->
    <update id="updateMonster" parameterType="Monster">
        UPDATE `monster` SET `age`=#{age}, `birthday` = #{birthday}, `email`=#{email}, `gender`=#{gender}, `name`=#{name}, `salary` = #{salary} WHERE id=#{id}
    </update>

    <!--配置实现根据id查询monster-->
    <select id="getMonsterById" resultType="Monster">
        SELECT * FROM `monster` WHERE id = #{id}
    </select>

    <!--配置实现查询所有的Monster. 返回所有 monster, resultType也是Monster而不是List<Monster>-->
    <select id="findAllMonster" resultType="Monster">
        SELECT * FROM `monster`
    </select>



</mapper>
  1. 修 改D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\resources\mybatis-config.xml
</environments>
<mappers>
	<!-- 这里会引入(注册)我们的 Mapper.xml 文件 -->
	<mapper resource="com/hspedu/mapper/MonsterMapper.xml"/>
</mappers>

  1. 创 建 工 具 类D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\util\MyBatisUtils.java

工具类提供了获取SqlSession实例的方法. SqlSession可以提供对数据库执行sql命令所需的所有方法. 因此可以通过SqlSession实例来执行已映射的SQL语句.

/**
 *  工具类, 用于得到SqlSession
 */
public class MyBatisUtils {
    // 会话工厂属性
    private static SqlSessionFactory sqlSessionFactory;
    // 编写静态代码块, 读取资源配置文件.
    static {
        try {
            // 指定资源文件, 配置文件mybatis-config.xml
            String resource = "mybatis-config.xml";
            // 获取到配置文件mybatis-config.xml 对应的输入流inputstream
            // 这里在加载文件时, 默认到resouces目录 => 运行后的工作目录 classes
            InputStream resourceAsStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            System.out.println("sqlSessionFactory=" + sqlSessionFactory.getClass());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 编写方法, 返回SqlSession对象会话
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();     // 返回会话 是通过openSession方法得到的.
    }
}
  1. 创 建D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\test\java\com\hspedu\mapper\MonsterMapperTest.java

是在test目录下创建的.
在这里插入图片描述

public class MonsterMapperTest  {
    // 属性
    private SqlSession sqlSession;
    private MonsterMapper monsterMapper;
    // 编写方法完成初始化
    @Before         // @Before标注的方法会在 JTest执行前就执行的方法
    public void init() {
        // 获取到sqlSession
        sqlSession = MyBatisUtils.getSqlSession();
        // 获取到MonsterMapper对象 (代理对象:MapperProxy)
        // 底层使用了动态代理机制
        monsterMapper = sqlSession.getMapper(MonsterMapper.class);
        System.out.println("monsterMapper=" + monsterMapper);
    }

    @Test
    public void addMonster() {
        for(int i=0;i<2;i++) {
            Monster monster = new Monster();
            monster.setAge(10 + i);
            monster.setBirthday(new Date());
            monster.setEmail("kate@qq.com");
            monster.setGender(1);
            monster.setName("松鼠精#" + i);
            monster.setSalary(1000 + i * 10);
            monsterMapper.addMonster(monster);
            System.out.println("添加对象--" + monster);
        }

        // 如果是增删改, 需要提交事务
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close(); //把获取的连接释放给连接池,不是真正关闭
        }

        System.out.println("添加成功");
    }

    @Test
    public void delMonster() {
        monsterMapper.delMonster(20);

        // 如果是增删改, 需要提交事务
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close();
        }
        System.out.println("删除成功");
    }

    @Test
    public void updateMonster() {
        for(int i=0;i<2;i++) {
            Monster monster = new Monster();
            monster.setAge(550 + i);
            monster.setBirthday(new Date());
            monster.setEmail("2222@qq.com");
            monster.setGender(1);
            monster.setName("老鼠精#" + i);
            monster.setSalary(100000 + i * 10);
            monster.setId(22+i);
            monsterMapper.updateMonster(monster);
            System.out.println("修改对象--" + monster);
        }
        // 如果是增删改, 需要提交事务
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close(); //把获取的连接释放给连接池,不是真正关闭
        }

        System.out.println("修改成功");
    }


    @Test
    public void getMonsterById() {
        Monster monster = monsterMapper.getMonsterById(24);
        System.out.println("monster=" + monster);

        // 查询语句不需要提交, 但是需要释放连接
        if(sqlSession != null) {
            sqlSession.close();     // 释放连接到连接池
        }
        System.out.println("查询成功");
    }

    @Test
    public void findAllMonster(){
        List<Monster> allMonster = monsterMapper.findAllMonster();
        for (Monster monster : allMonster) {
            System.out.println(monster);
        }
        if(sqlSession != null) {
            sqlSession.close();
        }
        System.out.println("查询成功");
    }
    @Test
    public void t1(){
        System.out.println("t1()....");
    }

    @Test
    public void t2(){
        System.out.println("t2()....");
    }
}

  1. 测试,看看是否可以添加成功, 这时会出现找不到 Xxxxmapper.xml 错误, 分析了原因
    (实际执行的东西是在target目录下.)
    在这里插入图片描述

  2. 解决找不到 Mapper.xml 配置文件问题, 老韩提示:如果顺利,你会很快解决,不顺利,你 会 干 到 怀 疑 人 生
    在这里插入图片描述
    //在父工程的 pom.xml 加入 build 配置

    <!--
    在build种配置resources, 防止我们资源导出失败的问题.
    1. 不同idea/maven版本可能提示错误不一样.
    2. 以不变应万变, 少什么文件, 就增加相应的配置即可.
    3. 含义是将 src/main/java目录和子目录以及 src/main/resources目录和子目录下的资源文件xml和properties在build项目时,导出到对应target目录下

    -->


    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>

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

  1. 修改 MonsterMapper.java, 增加方法接口
//根据 id 删除一个 Monster
public void delMonster(Integer id);
  1. 修改 MonsterMapper.xml, 实现方法接口
<!--
    配置实现delMonster方法, 根据id删除Monster
    这里的 java.lang.Integer 是java类型, 可以简写成Integer

    -->
    <delete id="delMonster" parameterType="Integer">
        DELETE FROM `monster` WHERE id=#{id};
    </delete>
  1. 完 成 测 试 , 修 改D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\test\java\com\hspedu\mapper\MonsterMapperTest.java, 增加测试方法
    @Test
    public void delMonster() {
        monsterMapper.delMonster(20);

        // 如果是增删改, 需要提交事务
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close();
        }
        System.out.println("删除成功");
    }

改 查

  1. 修改 MonsterMapper.java, 增加方法接口
//修改 Monster
public void updateMonster(Monster monster);
//查询-根据 id
public Monster getMonsterById(Integer id);
//查询所有的 Monster
public List<Monster> findAllMonster();
  1. 修改 MonsterMapper.xml, 实现方法接口
 <!--配置实现updateMonster-->
    <update id="updateMonster" parameterType="Monster">
        UPDATE `monster` SET `age`=#{age}, `birthday` = #{birthday}, `email`=#{email}, `gender`=#{gender}, `name`=#{name}, `salary` = #{salary} WHERE id=#{id}
    </update>

    <!--配置实现根据id查询monster-->
    <select id="getMonsterById" resultType="Monster">
        SELECT * FROM `monster` WHERE id = #{id}
    </select>

    <!--配置实现查询所有的Monster. 返回所有 monster, resultType也是Monster而不是List<Monster>-->
    <select id="findAllMonster" resultType="Monster">
        SELECT * FROM `monster`
    </select>
  1. 为了配置方便,在 mybatis-config.xml 配置 Monster 的别名

找到Mybatis中文官网, 配置类型别名:
在这里插入图片描述
在这里插入图片描述

    <!--设置类型别名-->
    <typeAliases>
        <typeAlias type="com.maven.quickstart.entity.Monster" alias="Monster"/>
    </typeAliases>
  1. 修改 MonsterMapper.xml, 实现方法接口, 可以使用 Monster 别名了.
    parameterType="Monster"写的是Monster而不是com.maven.quickstart.entity.Monster
    <!--配置实现updateMonster-->
    <update id="updateMonster" parameterType="Monster">
        UPDATE `monster` SET `age`=#{age}, `birthday` = #{birthday}, `email`=#{email}, `gender`=#{gender}, `name`=#{name}, `salary` = #{salary} WHERE id=#{id}
    </update>

    <!--配置实现根据id查询monster-->
    <select id="getMonsterById" resultType="Monster">
        SELECT * FROM `monster` WHERE id = #{id}
    </select>

    <!--配置实现查询所有的Monster. 返回所有 monster, resultType也是Monster而不是List<Monster>-->
    <select id="findAllMonster" resultType="Monster">
        SELECT * FROM `monster`
    </select>
  1. 完成测试, 修改 MonsterMapperTest.java , 增加测试方法
    @Test
    public void getMonsterById() {
        Monster monster = monsterMapper.getMonsterById(24);
        System.out.println("monster=" + monster);

        // 查询语句不需要提交, 但是需要释放连接
        if(sqlSession != null) {
            sqlSession.close();     // 释放连接到连接池
        }
        System.out.println("查询成功");
    }

    @Test
    public void findAllMonster(){
        List<Monster> allMonster = monsterMapper.findAllMonster();
        for (Monster monster : allMonster) {
            System.out.println(monster);
        }
        if(sqlSession != null) {
            sqlSession.close();
        }
        System.out.println("查询成功");
    }

日志输出-查看 SQL

  1. 在开发 MyBatis 程序时,比如执行测试方法,程序员往往需要查看 程序底层发给 MySQL的 SQL 语句, 到底长什么样, 怎么办?

在这里插入图片描述
2. 解决方案: 日志输出
日志文档 https://mybatis.org/mybatis-3/zh/logging.html
配置日志 https://mybatis.org/mybatis-3/zh/configuration.html#settings

配置日志-具体操作

  1. 查看文档 : https://mybatis.org/mybatis-3/zh/configuration.html#settings
    在这里插入图片描述

  2. 修 改
    D:\java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\resources\mybatis-config.xml, 加入日志输出配置, 方便分析 SQL 语句

    <!--配置Mybatis自带的日志输出, 查看原声的sql-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

在这里插入图片描述

在这里插入图片描述

SqlSession原生API的调用

创建E:\JavaCode\mybatis\mybatits_quickstart\src\test\java\com\maven\quickstart\com\mapper\MyBatisNativeTest.java,演示SqlSession原生API的调用

这里虽然是调用的原生API,但是还是需要到MonsterMapper.xml文件中去找对应方法的实现语句。所以本质前面的是一样的。方法先到MonsterMapper.java接口中,然后再到MonsterMapper.xml文件中找具体的实现。

/**
 * @Author: GQLiu
 * @DATE: 2024/3/10 11:17
 * 演示使用MyBatis原生API操作DB
 */
public class MyBatisNativeTest {
    private SqlSession sqlSession;
    private MonsterMapper monsterMapper;

    @Before
    public void init(){
         sqlSession = MyBatisUtils.getSqlSession();
        System.out.println("sqlSession==" + sqlSession.getClass());    // DefaultSqlSession
    }

    // 使用SqlSession原生的API调用我们编写的方法【了解】
    @Test
    public void myBatisNativeCrud() {
        // 添加
        /**
         *   @Override
         *   public int insert(String statement, Object parameter) {
         *     return update(statement, parameter);
         *   }
         *   statement 就是接口方法的完整声明
         *   parameter: 入参
         *
         * */
        Monster monster = new Monster();
        monster.setAge(1099);
        monster.setBirthday(new Date());
        monster.setEmail("kat他e@qq.com");
        monster.setGender(1);
        monster.setName("松鼠精安抚#");
        monster.setSalary(1000);

        // 返回受影响的行数
        int insert = sqlSession.insert("com.maven.quickstart.mapper.MonsterMapper.addMonster", monster);
        System.out.println(insert);

        // 删除
        sqlSession.delete("com.maven.quickstart.mapper.MonsterMapper.delMonster", 26);

        // 修改
        Monster monster1 = new Monster();
        monster1.setAge(1099);
        monster1.setBirthday(new Date());
        monster1.setEmail("kat他e@qq.com");
        monster1.setGender(1);
        monster1.setName("松鼠精安抚#");
        monster1.setSalary(1000);
        monster1.setId(27);
        sqlSession.update("com.maven.quickstart.mapper.MonsterMapper.updateMonster", monster1);

        // 查询
        List<Monster> monsters = sqlSession.selectList("com.maven.quickstart.mapper.MonsterMapper.findAllMonster");
        for (Monster monster2 : monsters) {
            System.out.println("monseter-" + monster2);
        }


        if(sqlSession != null) {
            sqlSession.commit();    // 增删改一定要提交。
            sqlSession.close();
        }
        System.out.println("操作成功");
    }
}

MyBatis使用注解方式操作

  1. 创建文件E:\JavaCode\mybatis\mybatits_quickstart\src\main\java\com\maven\quickstart\mapper\MonsterAnnotation.java
/**
 * @Author: GQLiu
 * @DATE: 2024/3/10 15:40
 * 使用注解方式配置接口方法
 */
public interface MonsterAnnotation {


    // 添加monster
    /*
    * MonsterMapper.xml中的配置方法
    *
    * <insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `monster`
        (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
        VALUES (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary})
    </insert>
    * 这里注解的方式addMonster不用配置, parameter不用写,只需要写上要进行处理的语句即可。
    * */
    @Insert(value = "INSERT INTO `monster` " +
            "(`age`, `birthday`, `email`, `gender`, `name`, `salary`) " +
            "VALUES (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary})")
    public void addMonster(Monster monster);


    // 根据id删除monster
    /* MonsterMapper.xml中的配置方法:
    *  <delete id="delMonster" parameterType="Integer">
        DELETE FROM `monster` WHERE id=#{id};
    </delete>
    * */
    @Delete(value = "DELETE FROM `monster` WHERE id=#{id}")
    public void delMonster(Integer id);

    // 修改Monster
    /*
    * MonsterMapper.xml中的配置方法:
    <update id="updateMonster" parameterType="Monster">
        UPDATE `monster` SET `age`=#{age}, `birthday` = #{birthday}, `email`=#{email}, `gender`=#{gender}, `name`=#{name}, `salary` = #{salary} WHERE id=#{id}
    </update>
    * */
    @Update(value = "UPDATE `monster` SET `age`=#{age}, `birthday` = #{birthday}, `email`=#{email}, `gender`=#{gender}, `name`=#{name}, `salary` = #{salary} WHERE id=#{id}")
    public void updateMonster(Monster monster);

    // 根据id查询
    /*
    * MonsterMapper.xml中的配置方法:
    * <select id="getMonsterById" resultType="Monster">
        SELECT * FROM `monster` WHERE id = #{id}
    </select>
    * */
    @Select(value = "SELECT * FROM `monster` WHERE id = #{id}")
    public Monster getMonsterById(Integer id);

    // 查询所有的Monster
    /*
    * MonsterMapper.xml中的配置方法:
    * <select id="findAllMonster" resultType="Monster">
        SELECT * FROM `monster`
    </select>
    * */
    @Select(value = "SELECT * FROM `monster`")
    public List<Monster> findAllMonster();

}
  1. 修改mybatis-config.xml, 对MonsterAnnotation进行注册
<!--这里我们配置需要关联的Mapper.xml文件-->
    <mappers>
        <!--<mapper resource="com/maven/quickstart/mapper/MonsterMapper.xml"/>-->
        <!--
        如果使用注解的方式, 可以不再使用MonsterMapper.xml, 上面这行可以注释掉
        但是需要在mybatis-config.xml中注册/引入含注解的类
        如果没有引入,不能使用
        -->
        <mapper class="com.maven.quickstart.mapper.MonsterAnnotation"/>
    </mappers>
  1. 创建E:\JavaCode\mybatis\mybatits_quickstart\src\test\java\com\maven\quickstart\com\mapper\MonsterAnnotationTest.java, 完成使用注解的测试。
/**
 * @Author: GQLiu
 * @DATE: 2024/3/10 15:52
 * 使用注解方式完成各种对DB的操作
 */
public class MonsterAnnotationTest {
    private SqlSession sqlSession;
    private MonsterAnnotation monsterAnnotation;
    @Before
    public void init(){
        sqlSession = MyBatisUtils.getSqlSession();
        monsterAnnotation = sqlSession.getMapper(MonsterAnnotation.class);
        System.out.println("monsterAnnotation=" + monsterAnnotation);   // 依然是一个代理对象:org.apache.ibatis.binding.MapperProxy@853265
    }

    @Test
    public void addMonsterTest() {
        Monster monster1 = new Monster();
        monster1.setAge(109139);
        monster1.setBirthday(new Date());
        monster1.setEmail("kat@qq.com");
        monster1.setGender(1);
        monster1.setName("狐狸安抚#");
        monster1.setSalary(1000);

        monsterAnnotation.addMonster(monster1);

        if(sqlSession != null) {
            sqlSession.commit();    //提交
            sqlSession.close();
        }
        System.out.println("添加成功");
    }

    // 使用注解方式完成查询
    @Test
    public void findAllMonster() {
        List<Monster> allMonster = monsterAnnotation.findAllMonster();
        for (Monster monster : allMonster) {
            System.out.println(monster);
        }

        if(sqlSession != null) {
            sqlSession.close();
        }
    }
}

注意事项和说明

  1. 如果是通过注解的方式,就不再使用MonsterMapper.xml文件。但是需要在mybatis-config.xml文件中 注册 含注解的类 / 接口。
  2. 使用注解方式,如果要返回自增长的id值,可以使用@Option 注解,组合使用:
    @Insert(value = "INSERT INTO `monster` " +
            "(`age`, `birthday`, `email`, `gender`, `name`, `salary`) " +
            "VALUES (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary})")
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") // useGeneratedKeys=true 表示返回自增的值. keyProperty="id" 表示 自增值对应的对象属性. keyColumn="id" 表示 自增值对应的表的字段.
    public void addMonster(Monster monster);

成功拿到:

monster1=Monster{id=35, age=109139, name='狐狸安抚#', email='kat@qq.com', birthday=Sun Mar 10 16:16:58 CST 2024, salary=1000.0, gender=1}

mybatis-config.xml配置文件详解

在这里插入图片描述

1.(properties)属性

在mybatis-config.xml文件中,如果需要一些从外部文件引入的属性来当作在mybatis-config.xml文件中的某个属性,就需要用到这个。eg:下面的 d r i v e r 、 {driver}、 driver{username}

<environments default="development">
        <environment id="development">
            <!--配置事务管理器-->
            <transactionManager type="JDBC"/>
            <!--配置数据源-->
            <dataSource type="POOLED">
                <!--配置驱动-->
                <property name="driver" value="${driver}"/>
                <!--配置连接mysql-url
                老韩解读:
                1. jdbc:mysql 协议
                2. 127.0.0.1:3306 : 指定连接mysql的ip+port
                3. mybatis: 连接的DB
                4. useSSL=true 表示使用安全连接
                5. &amp; 表示 & 防止解析错误
                6. useUnicode=true : 使用unicode 作用是防止编码错误
                7. characterEncoding=UTF-8 指定使用utf-8, 防止中文乱码
                8. 老韩温馨提示:不要背,直接使用即可
                -->
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

使用步骤

  1. 在src的resources目录下建立XX.properties文件:
    在这里插入图片描述
    编写相应的需要的内容:
    在这里插入图片描述
  2. 修改mybatis-config.xml,引入properties文件源:
    <properties resource="application.properties"/>         <!-- 告诉mybatis-config.xml我的外部的properties文件在哪里 -->

  1. 修改父项目的pom.xml(如果已经配置了 *.properties 就不用再配置)
    在这里插入图片描述
    <!--
    在build种配置resources, 防止我们资源导出失败的问题.
    1. 不同idea/maven版本可能提示错误不一样.
    2. 以不变应万变, 少什么文件, 就增加相应的配置即可.
    3. 含义是将 src/main/java目录和子目录以及 src/main/resources目录和子目录下的资源文件xml和properties在build项目时,导出到对应target目录下

    -->


    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>

2. 设置(settings)

一些基本的设置
在这里插入图片描述
我是在MonsterMapper.xml文件中使用的,也就是mybatis-config.xml管理的多个xxMapper中使用的。

MonsterMapper.xml:

    <insert id="addMonster" parameterType="Monster" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO `monster`
        (`age`, `birthday`, `email`, `gender`, `name`, `salary`)
        VALUES (#{age},#{birthday}, #{email}, #{gender}, #{name}, #{salary})
    </insert>

3. 类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:


    <!--设置类型别名-->
    <typeAliases>
        <typeAlias type="com.maven.quickstart.entity.Monster" alias="Monster"/>
    </typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:


    <!--设置类型别名-->
    <typeAliases>
        <!--<typeAlias type="com.maven.quickstart.entity.Monster" alias="Monster"/>-->
        <package name="com.maven.quickstart.entity"/>
    </typeAliases>

4. 类型处理器(typeHandlers)

在这里插入图片描述

5. 环境配置(environments)

  1. resource 注册Mapper文件:XXXMapper.xml(常见)
    <!--这里我们配置需要关联的Mapper.xml文件-->
    <mappers>
        <mapper resource="com/maven/quickstart/mapper/MonsterMapper.xml"/>
    </mappers>
  1. class:接口注解实现

    <!--这里我们配置需要关联的Mapper.xml文件-->
    <mappers>
        <!--<mapper resource="com/maven/quickstart/mapper/MonsterMapper.xml"/>-->
        <!--
        如果使用注解的方式, 可以不再使用MonsterMapper.xml
        但是需要在mybatis-config.xml中注册/引入含注解的类
        如果没有引入,不能使用
        -->
        <mapper class="com.maven.quickstart.mapper.MonsterAnnotation"/>
    </mappers>
  1. package 方式注册:直接把一个包下的所有的mapper全部都注册
    方便省事,省时省力
    <!--这里我们配置需要关联的Mapper.xml文件-->
    <mappers>
        <!--<mapper resource="com/maven/quickstart/mapper/MonsterMapper.xml"/>-->
        <!--
        如果使用注解的方式, 可以不再使用MonsterMapper.xml
        但是需要在mybatis-config.xml中注册/引入含注解的类
        如果没有引入,不能使用
        -->
        <!--<mapper class="com.maven.quickstart.mapper.MonsterAnnotation"/>-->
        <package name="com.maven.quickstart.mapper"/>
    </mappers>

6. SQL映射文件——XXXMapper.xml

在这里插入图片描述
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出)

  • cache – 该命名空间的缓存配置。
  • cache-ref – 引用其它命名空间的缓存配置。
  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
  • sql – 可被其它语句引用的可重用语句块。
  • insert – 映射插入语句。
  • update – 映射更新语句。
  • delete – 映射删除语句。
  • select – 映射查询语句。

XxxMapper.xml-详细说明

新建 Module xml-mapper

1、在原来的项目中,新建 xml-mapper 项目演示 xml 映射器的使用
2、新建 Module 后,先创建需要的包,再将需要的文件/资源拷贝过来(这里我们拷贝 Monster.java、resources/jdbc.properties 和 mybatis-config.xml)
3、创建 MonsterMapper.java MonsterMapper.xml 和 MonsterMapperTest.java
在这里插入图片描述

基本使用
  1. insert、delete、update、select 这个我们在前面讲解过,分别对应增删改查的方法和 SQL语句的映射.
  2. 如何获取到刚刚添加的 Monster 对象的 id 主键
    在这里插入图片描述
parameterType

● parameterType(输入参数类型)

  1. 传入简单类型,比如按照 id 查 Monster(前讲过)
  2. 传入 POJO 类型,查询时需要有多个筛选条件
  3. 当有多个条件时,传入的参数就是 Pojo 类型的 Java 对象,比如这里的 Monster 对象
  4. 当传入的参数类是 String 时,也可以使用 ${} 来接收参数

● parameterType-应用案例

案例 1:请查询 id = 1 或者 name = ‘白骨精’ 的妖怪
案例 2:请查询 name 中 包含 “牛魔王” 的妖怪

  1. 修改 MonsterMapper.java, 增加方法接口
//通过 id 或者名字查询
public List<Monster> findMonsterByNameORId(Monster monster);

//查询名字中含义'精'妖怪
public List<Monster> findMonsterByName(String name);
  1. 修改 MonsterMapper.xml

<!-- 实现 findMonsterByNameORId -->
<select id="findMonsterByNameORId" parameterType="Monster"
resultType="Monster">
SELECT * FROM monster
WHERE id=#{id} OR name=#{name}
</select>
<!-- 看看模糊查询的使用 取值 需要 ${value} 取值-->
<select id="findMonsterByName" parameterType="String" resultType="Monster">
SELECT * FROM monster
WHERE name LIKE '%${value}%' </select>
  1. 修改 MonsterMapperTest.java ,完成测试
    @Test
    public void findMonsterByNameORIdTest() {
        Monster monster = new Monster();
        monster.setId(25);
        monster.setName("老鼠精#1");

        List<Monster> monsters = monsterMapper.findMonsterByNameORId(monster);

        for (Monster monster1 : monsters) {
            System.out.println(monster1);
        }

        // 释放连接回连接池
        if(sqlSession != null) {
            sqlSession.close();
        }
    }
    //  模糊查询
    @Test
    public void findMonsterByNameTest() {
        String name = "松鼠精";
        List<Monster> monsters = monsterMapper.findMonsterByName(name);
        for (Monster monster : monsters) {
            System.out.println(monster);
        }
    }
传入 HashMap

● 传入 HashMap(重点)

  1. HashMap 传入参数更加灵活,比如可以灵活的增加查询的属性,而不受限于 Monster 这个 Pojo 属性本身
  2. 演示如何遍历一个 List<Map<String,Object>> 的数据类型

● 传入 HashMap- 应用实例 1
要求:声明一个方法,按传入参数是 HashMap 的方式,查询 id > 10 并且 salary 大于 40的所有妖怪

  1. 修改 MonsterMapper.java, 增加方法接口
//查询 id > 10 并且 salary 大于 40, 要求传入的参数是 HashMap
public List<Monster>
	findMonsterByIdAndSalary_PrameterHashMap(Map<String, Object> map);
  1. 修改 MonsterMapper.xml
    <!--
    如果是以map形式传入参数, 当你写`id` > #{id} 时,表示你的map中有一个k-v中 key是id
    -->
    <select id="findMonsterByIdAndSalary_PrameterHashMap" parameterType="map" resultType="Monster">
        SELECT * FROM `monster` WHERE `id` > #{id} AND `salary` > #{salary}
    </select>
  1. 修改 MonsterMapperTest.java 进行测试
    @Test
    public void findMonsterByIdAndSalary_PrameterHashMapTest() {
        // 报错:Diamond types are not supported at language level '5'
        // 因为目前只支持jdk5. 在父项目的pom中指定maven的编译器和jdk版本
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", 10);
        map.put("salary", 1000);

        List<Monster> monsters = monsterMapper.findMonsterByIdAndSalary_PrameterHashMap(map);
        for (Monster monster : monsters) {
            System.out.println(monster);    // 是对象形式 : Monster{id=21, age=11, name='松鼠精#1', email='kate@qq.com', birthday=Fri Mar 08 00:00:00 CST 2024, salary=1010.0, gender=1}
        }

        if(sqlSession != null) {
            sqlSession.close(); // 关闭连接
        }
    }

● 传入和返回 HashMap- 应用实例
要求:将上面的方法的改成返回参数也以 HashMap 的类型

  1. 修改 MonsterMapper.java
//查询 id > 10 并且 salary 大于 40, 要求传入的参数是 HashMap
public List<Map<String, Object>>
	findMonsterByIdAndSalary_PrameterHashMap_ReturnHashMap(Map<String, Object> map);
  1. 修改 MonsterMapper.xml
    <select id="findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap" parameterType="map" resultType="map">
        SELECT * FROM `monster` WHERE `id` > #{id} AND `salary` > #{salary}
    </select>
  1. 修改 MonsterMapperTest.java
 @Test
    public void findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMapTest() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("id", 10);
        map.put("salary", 1000);
        List<Map<String, Object>> monsterList = monsterMapper.findMonsterByIdAndSalary_ParameterHashMap_ReturnHashMap(map);
        // 取出返回的结果,以map方式
        for (Map<String, Object> monsterMap : monsterList) {
            //    System.out.println("monsterMap=" + monsterMap); // 是kv形式 : {birthday=2024-03-09, gender=1, name=老鼠精#0, id=22, salary=100000.0, age=550, email=2222@qq.com}

            // 取出 kv
            Set<String> keySet = monsterMap.keySet();
            for(String key : keySet) {
                System.out.println(key + " ===> " + monsterMap.get(key));
            }
            System.out.println("===================");

            // entry方法
            // Set<Map.Entry<String, Object>> entries = monsterMap.entrySet();
            // Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
            // while (iterator.hasNext()) {
            //     Map.Entry<String, Object> next = iterator.next();
            //     System.out.println(next.getKey() + " ===> " + entry.getValue());
            // }
            // System.out.println("===================");
        }

        if(sqlSession != null) {
            sqlSession.close(); // 关闭连接
        }
    }
resultMap(结果集映射)

应用实例

● 基本介绍
当实体类的属性和表的字段名字不一致时,我们可以通过 resultMap 进行映射,从而屏蔽实体类属性名和表的字段名的不同.

● 案例演示

  1. 创建表 user

在这里插入图片描述
在这里插入图片描述
2. 创 建 entity
D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\entity\User.java

public class User {
    private Integer userid;
    private String username;
    private String useremail;
}
  1. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\mapper\UserMapper.java
public interface UserMapper {

    //添加方法
    public void addUser(User user);


    //查询所有的 User
    public List<User> findAllUser();

}

  1. 修 改
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\resources\mybatis-config.xml, 改变别名的写法
    在这里插入图片描述
  2. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\main\java\com\hspedu\mapper\UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
这是一个mapper xml文件
该文件可以去实现对应的接口的方法。
namespace 指定该xml文件和哪个接口对应
-->


<mapper namespace="com.maven.quickstart.mapper.UserMapper">

     <!--
     配置方法
     注意user属性和表的字段不一致。
     user_email 和 user_name 是表的字段
     useremail 和 username 是javabean的字段。
     -->

    <insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="userid">
        INSERT INTO `user` (`user_email`, `user_name`) VALUES (#{useremail},#{username});
    </insert>


    <!--
    用默认方法resultType="User",如果对象属性名和表的字段名一样的话,就会设置值。如果不一样就会使默认值。
    这里可以使用resultMap解决。
    resultMap : 表示要定义一个resultMap
    id="findAllUserMap" id就是程序员指定的resultMap的id,后面可以通过id使用这个resultM ap
    type="User" 就是你需要返回的对象类型。
    column="user_email" 表示表的字段名
    property="useremail" 表示javabean的值。
    -->
    <resultMap id="findAllUserMap" type="User">
        <result column="user_email" property="useremail"/>
        <result column="user_name" property="username"/>
    </resultMap>
    <select id="findAllUser" resultMap="findAllUserMap">
        SELECT * FROM `user`;
    </select>
</mapper>
  1. 创 建
    D:\idea_java_projects\HSP_MyBatis\01_mybatis_quickstart\src\test\java\com\hspedu\mapper\UserMapperTest.java 完成测试
/**
 * @Author: GQLiu
 * @DATE: 2024/3/12 20:59
 */
public class UserMapperTest {

    public SqlSession sqlSession;
    public UserMapper userMapper;

    @Before
    public void init(){
        sqlSession = MyBatisUtils.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void addUserTest() {
        User user = new User();
        user.setUserid(123);
        user.setUseremail("123@qq.com");
        user.setUsername("a1a1");

        userMapper.addUser(user);

        // 如果是增删改,需要提交事务
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close();
        }
        System.out.println("提交User成功");
    }

    @Test
    public void findAllUserTest() {
        List<User> users = userMapper.findAllUser();
        for (User user : users) {
            System.out.println("user=" + user);
        }

        if(sqlSession != null) {
            sqlSession .close();
        }
    }
}

注意事项和细节
2、老韩说明:如果是 MyBatis-Plus 处理就比较简单, 可以使用 注解@TableField 来解决实体字段名和表字段名不一致的问题,还可以使用@TableName 来解决 实体类名和表名不一致的问题

7. 动态 SQL 语句-更复杂的查询业务需求

动态 SQL-官方文档

为什么需要动态 SQL?

1、动态 SQL 是 MyBatis 的强大特性之一
2、使用 JDBC 或其它类似的框架,根据不同条件拼接 SQL 语句非常麻烦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号等
3、 SQL 映射语句中的强大的动态 SQL 语言, 可以很好的解决这个问题.

动态 SQL-基本介绍

  1. 在一个实际的项目中,sql 语句往往是比较复杂的
  2. 为了满足更加复杂的业务需求,MyBatis 的设计者,提供了动态生成 SQL 的功能。

● 动态 SQL 必要性

  1. 比如我们查询Monster 时,如果程序员输入的age 不大于0, 我们的sql语句就不带age 。
  2. 更新 Monster 对象时,没有设置的新的属性值,就保持原来的值,设置了新的值,才更新

● 动态 SQL 常用标签
动态 SQL 提供了如下几种常用的标签,类似我们 Java 的控制语句:

  1. if [判断]
  2. where [拼接 where 子句]
  3. choose/when/otherwise [类似 java 的 switch 语句, 注意是单分支]
  4. foreach [类似 in ]
  5. trim [替换关键字/定制元素的功能] (用的少,没学)
  6. set [在 update 的 set 中,可以保证进入 set 标签的属性被修改,而没有进入 set 的,保持原来的值]

动态 SQL-案例演示

1 新建 Module dynamic-sql

1、在原来的项目中,新建 dynamic-sql 项目演示动态 SQL 的使用
2、新建 Module 后,先创建需要的包,再将需要的文件/资源拷贝过来(这里我们拷贝Monster.java、resources/jdbc.properties 和 mybatis-config.xml)
3、创建 MonsterMapper.java MonsterMapper.xml 和 MonsterMapperTest.java
在这里插入图片描述

if 标签应用实例

● 需求:请查询 age 大于 10 的所有妖怪,如果程序员输入的 age 不大于 0, 则输出所有的妖怪!

  1. 修改 MonsterMapper.java
/**
 * @Author: GQLiu
 * @DATE: 2024/3/7 22:29
 * 接口, 用于生命操作monster表的方法
 * 这些方法可以通过注解或xml文件来实现。
 */
public interface MonsterMapper {

    // 根据age查询结果
    // 加上 @Param(value = "age") 防止xml中想要取出age取不出。
    public List<Monster> findMonsterByAge(@Param(value = "age") Integer age);

    // 根据id和名字来查询结果
    public List<Monster> findMonsterByIdAndName(Monster monster);

    // 测试 choose标签的使用
    // 如果name不为空,就按照name查找
    // 如果id>0 就按照id查询妖怪
    // 如果前两个条件都不满足,就默认查询salary > 100
    public List<Monster> findMonsterByIdOrName_choose(Map<String, Object> map);

    //测试foreach标签的使用
    public List<Monster> findMonsterById_forEach(Map<String, Object> map);

    // 测试Set标签
    public void updateMonster_set(Map<String, Object> map);
}

  1. 修改 MonsterMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
这是一个mapper xml文件
该文件可以去实现对应的接口的方法。
namespace 指定该xml文件和哪个接口对应
-->


<mapper namespace="org.example.mapper.MonsterMapper">

    <!--
    查询age 大于 10 的所有妖怪, 如果程序员输入的age不大于0,则输出所有的妖怪
    使用#{age} 表达式是取不出值的。 解决方法是使用@Param(value) = "age"

     如果入参是Monster对象,则在test中直接使用对象的属性名即可。

     where 标签会在组织动态sql时加上where。
     mybatis 会去掉多余的 AND
    -->
    <select id="findMonsterByAge" parameterType="Integer" resultType="Monster">
        SELECT * FROM `monster` WHERE 1 = 1
        <if test="age >= 0">
            AND age > #{age}
        </if>
    </select>

    <!--会自动过滤掉多余的 AND-->
    <select id="findMonsterByIdAndName" parameterType="Monster" resultType="Monster">
        SELECT * FROM `monster`
        <where>
            <if test="id >= 0">
                AND `id` > #{id}
            </if>
            <if test="name != null and name != ''">
                AND `name` = #{name}
            </if>
        </where>
    </select>


    <!--// 如果name不为空,就按照name查找-->
    <!--// 如果id>0 就按照id查询妖怪-->
    <!--// 如果前两个条件都不满足,就默认查询salary > 100-->
    <select id="findMonsterByIdOrName_choose" parameterType="map" resultType="Monster">
        SELECT * FROM `monster`
        <choose>
            <when test="name != null and name!=''">
                WHERE `name` = #{name}
            </when>
            <when test="id > 0">
                WHERE `id` > #{id}
            </when>
            <otherwise>
                WHERE `salary` > 100
            </otherwise>
        </choose>
    </select>

    <!--
    测试forEach
    map入参中应当由 ids-101214-->
    <select id="findMonsterById_forEach" parameterType="map" resultType="Monster">
        SELECT  * FROM `monster`
        <!--
        where标签
        首先判断 ids是否为空——使用if
        如果ids不为空,则使用foreach标签进行遍历
        collection="ids" 对应你的入参map的key-ids    对应你的入参map的key
        item="id" 表示在遍历ids集合(map集合对应的value的list。)时,每次取出的值对应的变量为id    在遍历map对应的value时每次取出的项。
        open="(" 对应的就是sql 中IN后面的左括号 (
        separator="," 表示使用 , 作为间隔符
        close=")" 对应的就是sql 中IN后面的右括号 )
        #{id} 对应的就是item="id"
        -->
        <if test="ids != null and ids !=''">
            <where>
                id IN
                <foreach collection="ids" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>

            </where>
        </if>
    </select>


    <!--
    配置实现updateMonster_set
    -->
    <update id="updateMonster_set" parameterType="map">
        update `monster` 
        <set>
            <if test="age != null and age != ''">
                `age` = #{age},
            </if>
            <if test="email != null and email != ''">
                `email` = #{email},
            </if>
            <if test="birthday != null and birthday != ''">
                `birthday` = #{birthday},
            </if>
            <if test="salary != null and salary != ''">
                `salary` = #{salary},
            </if>
            <if test="name != null and name != ''">
                `name` = #{name},
            </if>
            <if test="gender != null and gender != ''">
                `gender` = #{gender},
            </if>
        </set>
        WHERE id = #{id}
    </update>

</mapper>
  1. 修改 MonsterMapperTest.java 并完成测试
public class MonsterMapperTest {
    // 属性
    private SqlSession sqlSession;
    private MonsterMapper monsterMapper;
    // 编写方法完成初始化
    @Before         // @Before标注的方法会在 JTest执行前就执行的方法
    public void init() {
        // 获取到sqlSession
        sqlSession = MyBatisUtils.getSqlSession();
        // 获取到MonsterMapper对象 (代理对象:MapperProxy)
        // 底层使用了动态代理机制
        monsterMapper = sqlSession.getMapper(MonsterMapper.class);
        System.out.println("monsterMapper=" + monsterMapper);
    }

    @Test
    public void findMonsterByAgeTest() {
        // List<Monster> monsters = monsterMapper.findMonsterByAge(-1100);
        List<Monster> monsters = monsterMapper.findMonsterByAge(1100);
        for (Monster monster : monsters) {
            System.out.println("monster=" + monster);
        }
    }

    @Test
    public void t1(){
        System.out.println("t1()....");
    }

    @Test
    public void t2(){
        System.out.println("t2()....");
    }
}

where 标签应用实例

● where 标签应用实例

需求:查询 id 大于 20 的,并且名字是 “牛魔王” 的所有妖怪, 注意,如果名字为空,或者输入的 id 小于 0, 则不拼接 sql 语句(老师梳理:如果名字为空 , 就不带名字条件, 如果输入的 id 小于 0, 就不带 id 的条件)

  1. 修改 MonsterMapper.java, 添加:
    // 根据id和名字来查询结果
    public List<Monster> findMonsterByIdAndName(Monster monster);
  1. 修改 MonsterMapper.xml, 添加:
<!--会自动过滤掉多余的 AND-->
    <select id="findMonsterByIdAndName" parameterType="Monster" resultType="Monster">
        SELECT * FROM `monster`
        <where>
            <if test="id >= 0">
                AND `id` > #{id}
            </if>
            <if test="name != null and name != ''">
                AND `name` = #{name}
            </if>
        </where>
    </select>
  1. 修改 MonsterMapperTest.java 并完成测试
    @Test
    public void findMonsterByIdAndNameTest() {
        Monster monster = new Monster();
        monster.setName("松鼠精#1");
        monster.setId(1);

        List<Monster> monsters = monsterMapper.findMonsterByIdAndName(monster);
        for (Monster monster1 : monsters) {
            System.out.println("monster=" + monster1);
        }

        if(sqlSession != null) {
            sqlSession.close();
        }
    }

choose/when/otherwise 应用实例

● 需求:如果给的 name 不为空,就按名字查询妖怪,如果指定的 id>0,就按 id 来查询妖怪, 要求使用 choose/when/otherwise 标签实现, 传入参数要求使用 Map

  1. 修改 MonsterMapper.java
//测试 choose 标签的使用
public List<Monster>
	findMonsterByIdAndName_choose(Map<String, Object> map);
  1. 修改 MonsterMapper.xml
 <!--// 如果name不为空,就按照name查找-->
    <!--// 如果id>0 就按照id查询妖怪-->
    <!--// 如果前两个条件都不满足,就默认查询salary > 100-->
    <select id="findMonsterByIdOrName_choose" parameterType="map" resultType="Monster">
        SELECT * FROM `monster`
        <choose>
            <when test="name != null and name!=''">
                WHERE `name` = #{name}
            </when>
            <when test="id > 0">
                WHERE `id` > #{id}
            </when>
            <otherwise>
                WHERE `salary` > 100
            </otherwise>
        </choose>
    </select>

  1. 修改 MonsterMapperTest.java 并完成测试
    public void findMonsterByIdOrName_chooseTest() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "松鼠精#1");
        map.put("id", 1100);
        map.put("salary", 12112);

        List<Monster> monsters = monsterMapper.findMonsterByIdOrName_choose(map);
        for (Monster monster : monsters) {
            System.out.println(monster);
        }
        if(sqlSession != null) {
            sqlSession.close();
        }

    }

forEach 标签应用实例

● 需求:查询 monster_id 为 20, 22, 34 的妖怪

  1. 修改 MonsterMapper.java
//测试 foreach 的标签使用
public List<Monster>
 	findMonsterById_forEach(Map<String, Object> map);
  1. 修改 MonsterMapper.xml
<!--
    测试forEach
    map入参中应当由 ids-【10,12,14】-->
    <select id="findMonsterById_forEach" parameterType="map" resultType="Monster">
        SELECT  * FROM `monster`
        <!--
        where标签
        首先判断 ids是否为空——使用if
        如果ids不为空,则使用foreach标签进行遍历
        collection="ids" 对应你的入参map的key-ids
        item="id" 表示在遍历ids集合时,每次取出的值对应的变量为id
        open="(" 对应的就是sql 中IN后面的左括号 (
        separator="," 表示使用 , 作为间隔符
        close=")" 对应的就是sql 中IN后面的右括号 )
        #{id} 对应的就是item="id"
        -->
        <if test="ids != null and ids !=''">
            <where>
                id IN
                <foreach collection="ids" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>

            </where>
        </if>
    </select>
  1. 修改 MonsterMapperTest.java 并完成测试
    @Test
    public void findMonsterById_forEach() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("ids", Arrays.asList(24, 25, 26));
        List<Monster> monsters = monsterMapper.findMonsterById_forEach(map);
        for (Monster monster : monsters) {
            System.out.println("monster=" + monster);
        }

        if(sqlSession != null) {
            sqlSession.close();
        }
    }

set 标签应用实例[重点]

● 需求: 请对指定 id 的妖怪进行 修改,如果没有设置新的属性,则保持原来的值

  1. 修改 MonsterMapper.java
//测试 Set 标签
public void
	updateMonster_set(Map<String, Object> map);
  1. 修改 MonsterMapper.xml
  <!--
    配置实现updateMonster_set
    -->
    <update id="updateMonster_set" parameterType="map">
        update `monster` 
        <set>
            <if test="age != null and age != ''">
                `age` = #{age},
            </if>
            <if test="email != null and email != ''">
                `email` = #{email},
            </if>
            <if test="birthday != null and birthday != ''">
                `birthday` = #{birthday},
            </if>
            <if test="salary != null and salary != ''">
                `salary` = #{salary},
            </if>
            <if test="name != null and name != ''">
                `name` = #{name},
            </if>
            <if test="gender != null and gender != ''">
                `gender` = #{gender},
            </if>
        </set>
        WHERE id = #{id}
    </update>
  1. 修改 MonsterMapperTest.java 并完成测试
    @Test
    public void updateMonster_setTest() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "我是你aaabbba爹");
        map.put("id", 28);
        monsterMapper.updateMonster_set(map);

        // 修改需要提交sqlSession
        if(sqlSession != null) {
            sqlSession.commit();
            sqlSession.close();
        }
        System.out.println("操作成功");
    }

注意事项

  1. 在这里插入图片描述
  2. 在这里插入图片描述
  3. 在这里插入图片描述

8 映射关系一对一

映射关系-官方文档

映射关系 1 对 1-基本介绍

● 基本介绍

  1. 项目中 1 对 1 的关系是一个基本的映射关系,比如:Person(人) — IDCard(身份证)
  2. 我们看看再 MyBatis 中如何实现 1 对 1 的处理.

1 对 1 ,我们这里就研究一下单向 1 对 1 即可

映射关系 1 对 1-映射方式

  1. 通过配置 XxxMapper.xml 实现 1 对 1 [配置方式]
  2. 通过注解的方式实现 1 对 1 [注解方式]

配置 Mapper.xml 的方式-应用实例

● 老韩说明:通过配置 XxxMapper.xml 的方式来实现下面的 1 对 1 的映射关系,实现级联查询,通过 person 可以获取到对应的 idencard 信息

  1. 创建 person 表和 idencard 表
-- 创建person表
CREATE TABLE person (
	`id` INT PRIMARY KEY AUTO_INCREMENT,
	`name` VARCHAR(32) NOT NULL DEFAULT '',
	`card_id` INT,	-- 对应idencard的主键id
	FOREIGN KEY (card_id) REFERENCES idencard(id)
) CHARSET utf8;

-- 创建 idencard 表
CREATE TABLE idencard(
	id INT PRIMARY KEY AUTO_INCREMENT,
	card_sn VARCHAR(32) NOT NULL DEFAULT ''
) CHARSET utf8;

INSERT INTO idencard VALUES(1, '124124321432423');
INSERT INTO person VALUES(1, '张三', 3434);

SELECT * FROM person;
SELECT * FROM idencard;

注意事项和细节

  1. 表是否设置外键, 对 MyBatis 进行对象/级联映射没有影响
  2. 举例: 去掉 person 表的外键 , 进行测试, 依然可以获取相应的级联对象

9. 映射关系多对一

映射关系-官方文档

● 基本介绍

  1. 项目中多对 1 的关系是一个基本的映射关系, 多对 1, 也可以理解成是 1 对多.
  2. Dep —Emp : 一个部门可以有多个员工
  3. User — Pet: 一个用户可以养多只宠物

● 注意细节

  1. 我们直接讲双向的多对一的关系,单向的多对一比双向的多对一简单。
  2. 在实际的项目开发中, 要求会使用双向的多对一的映射关系
  3. 老韩说明:什么是双向的多对一的关系 : 比如通过 User 可以查询到对应的 Pet, 反过来,通过 Pet 也可以级联查询到对应的 User 信息.
  4. 多对多的关系,是在多对 1 的基础上扩展即可.

映射关系多对 1-映射方式

  1. 方式 1:通过配置 XxxMapper.xml 实现多对 1
  2. 方式 2:通过注解的方式实现 多对 1

配置Xml方式应用实例:

  • 需求说明: 实现级联查询,通过 user 的 id 可以查询到用户信息,并可以查询到关联的 pet信息,反过来,通过 Pet 的 id 可以查询到 Pet 的信息,并且可以级联查询到它的主人 User对象信息
  1. 创建 mybatis_user 和 mybatis_pet 表
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值