第三章 MyBatis
一、MyBatis 简介
1. 简介
-  MyBatis 最初是 Apache 的一个开源项目 iBatis, 2010 年 6 月这个项目由 Apache Software Foundation 迁移到了 Google Code。随着开发团队转投 Google Code 旗下, iBatis3.x 正式更名为 MyBatis。代码于 2013 年 11 月迁移到 Github。 
-  MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。 

- 此处使用 3.5.11 版本
2. 持久层框架对比
-  JDBC - SQL 夹杂在 Java 代码中耦合度高,导致硬编码内伤
- 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
- 代码冗长,开发效率低
 
-  Hibernate 和 JPA - 操作简便,开发效率高
- 程序中的长难复杂 SQL 需要绕过框架
- 内部自动生成的 SQL,不容易做特殊优化
- 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
- 反射操作太多,导致数据库性能下降
 
-  MyBatis - 轻量级,性能出色
- SQL 和 Java 编码分开,功能边界清晰。Java 代码专注业务、SQL 语句专注数据
- 开发效率稍逊于 Hibernate,但是完全能够接受
 
-  开发效率:Hibernate>Mybatis>JDBC 
-  运行效率:JDBC>Mybatis>Hibernate 
3. 快速入门(基于 MyBatis3 方式)
3.1 准备数据模型
CREATE DATABASE `mybatis-example`;
USE `mybatis-example`;
CREATE TABLE `t_emp`(
  emp_id INT AUTO_INCREMENT,
  emp_name CHAR(100),
  emp_salary DOUBLE(10,5),
  PRIMARY KEY(emp_id)
);
INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("tom",200.33);
INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("jerry",666.66);
INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("andy",777.77);
3.2 项目搭建和准备
3.2.1 项目搭建

3.2.2 依赖导入
- pom.xml
<dependencies>
  <!-- mybatis依赖 -->
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.11</version>
  </dependency>
  <!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
  </dependency>
  <!--junit5测试-->
  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.3.1</version>
  </dependency>
</dependencies>
3.2.3 实体类准备
public class Employee {
    private Integer empId;
    private String empName;
    private Double empSalary;
    //getter | setter
}
3.3 准备 Mapper 接口和 MapperXML 文件
- MyBatis 框架下,SQL 语句编写位置发生改变,从原来的 Java 类,改成XML或者注解定义!
- 推荐在 XML 文件中编写 SQL 语句,让用户能更专注于 SQL 代码,不用关注其他的 JDBC 代码。
- 如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码!!
- 一般编写 SQL 语句的文件命名:XxxMapper.xml Xxx 一般取表名!!
- Mybatis 中的 Mapper 接口相当于以前的 Dao。但是区别在于,Mapper 仅仅只是建接口即可,我们不需要提供实现类,具体的 SQL 写到对应的 Mapper 文件,该用法的思路如下图所示:

3.3.1 定义 mapper 接口
- 包:com.alex.mapper
package com.alex.mapper;
import com.alex.pojo.Employee;
/**
 * t_emp表对应数据库SQL语句映射接口!
 *    接口只规定方法,参数和返回值!
 *    mapper.xml中编写具体SQL语句!
 */
public interface EmployeeMapper {
    /**
     * 根据员工id查询员工数据方法
     * @param empId  员工id
     * @return 员工实体对象
     */
    Employee selectEmployee(Integer empId);
}
3.3.2 定义 mapper xml
- 位置: resources/mappers/EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.alex.mapper.EmployeeMapper">
    <!-- 查询使用 select标签
            id = 方法名
            resultType = 返回值类型
            标签内编写SQL语句
     -->
    <select id="selectEmployee" resultType="com.alex.pojo.Employee">
        <!-- #{empId}代表动态传入的参数,并且进行赋值!后面详细讲解 -->
        select emp_id empId,emp_name empName, emp_salary empSalary from
           t_emp where emp_id = #{empId}
    </select>
</mapper>
- 注意: 
  - 方法名和 SQL 的 id 一致
- 方法返回值和 resultType 一致
- 方法的参数和 SQL 的参数一致
- 接口的全类名和映射配置文件的名称空间一致
 
3.4 准备 MyBatis 配置文件
- mybatis 框架配置文件: 数据库连接信息,性能配置,mapper.xml 配置等!
- 习惯上命名为 mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合 Spring 之后,这个配置文件可以省略,所以操作时可以直接复制、粘贴。
<?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>
  <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
  <environments default="development">
    <!-- environment表示配置Mybatis的一个具体的环境 -->
    <environment id="development">
      <!-- Mybatis的内置的事务管理器 -->
      <transactionManager type="JDBC"/>
      <!-- 配置数据源 -->
      <dataSource type="POOLED">
        <!-- 建立数据库连接的具体信息 -->
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
    <!-- mapper标签:配置一个具体的Mapper映射文件 -->
    <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
    <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
    <mapper resource="mappers/EmployeeMapper.xml"/>
  </mappers>
</configuration>
3.5 运行和测试
/**
 * projectName: com.alex.test
 *
 * description: 测试类
 */
public class MyBatisTest {
    @Test
    public void testSelectEmployee() throws IOException {
        // 1.创建SqlSessionFactory对象
        // ①声明Mybatis全局配置文件的路径
        String mybatisConfigFilePath = "mybatis-config.xml";
        // ②以输入流的形式加载Mybatis配置文件
        InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);
        // ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 2.使用SqlSessionFactory对象开启一个会话
        SqlSession session = sessionFactory.openSession();
        // 3.根据EmployeeMapper接口的Class对象获取Mapper接口类型的对象(动态代理技术)
        EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
        // 4. 调用代理类方法既可以触发对应的SQL语句
        Employee employee = employeeMapper.selectEmployee(1);
        System.out.println("employee = " + employee);
        // 4.关闭SqlSession
        session.commit(); //提交事务 [DQL不需要,其他需要]
        session.close(); //关闭会话
    }
}
-  说明: - SqlSession:代表 Java 程序和数据库之间的会话。(HttpSession 是 Java 程序和浏览器之间的会话)
- SqlSessionFactory:是“生产”SqlSession 的“工厂”。
- 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。
 
3.6 SqlSession 和 HttpSession 区别
- HttpSession:工作在 Web 服务器上,属于表述层。 
  - 代表浏览器和 Web 服务器之间的会话。
 
- SqlSession:不依赖 Web 服务器,属于持久化层。 - 代表 Java 程序和数据库之间的会话。
  




![web:[ACTF2020 新生赛]Exec](https://img-blog.csdnimg.cn/ccdcdf16992b42159516b68e35454ac0.png)













