MyBatis源码解读

一、MyBatis回顾

我们先做一个MyBatis的简单回顾。

1.1、MyBatis是做什么

MyBatis是一个ORM框架,解决的的是数据库访问和操作的问题,是对现有的JDBC的封装。

1.2、搭建MyBatis环境

首先我们需要准备一下MyBatis所需要的依赖jar包。

xml 复制代码
<!-- myBatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
​
    <!-- mysql驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>

准备好依赖后我们就要去准备一下配置文件。MyBatis主要是有两类配置文件:

  1. 基本配置文件:mybatis-config.xml
  2. 写sql的文件:mapper.xml

1.2.1、mybatis-confi.xml

我们先来写一套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>
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/ydlclass?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>
​
    <typeAliases>
        <package name="com.ydlclass.mybatissourcestudy.entity"/>
    </typeAliases>
​
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
​
    <mappers>
        <mapper resource="mappers/AccountMapper.xml"/>
    </mappers>
</configuration>

我们首先来看environments这个标签。

ini 复制代码
    <environments default="myssql">
        <environment id="myssql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

environments标签意味着我们可以配置多个,我们只需要在environments标签里面多加几个environment即可,但是要确保id不同即可。

ini 复制代码
<environments default="myssql">
        <environment id="myssql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
       <environment id="orcal">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

在设置完多个数据源以后,我们还需要一个默认开启的数据源,此时我们就可以在environments标签的default属性中写上我们需要默认开启的数据源即可。一旦涉及到了多数据源的话,就会出现一个特别恶心的事情,那即是我们的事务不好控制

1.2.2、测试MyBatis

首先我们需要引入必须的依赖。

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>cn.linstudy</groupId>
    <artifactId>MyBatisSource</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
​
    <dependencies>
        <!-- myBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.13</version>
        </dependency>
​
        <!-- mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
​
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
​
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>6.0.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
​
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.13</version>
        </dependency>
    </dependencies>
​
</project>

然后简单的创建一张表dept。

sql 复制代码
CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

然后创建实体类。

kotlin 复制代码
package cn.linstudy.pojo;
​
import lombok.Data;
​
/**
 * @Description
 * @Date 2023/6/18
 * @Author XiaoLin
 */
@Data
public class Dept {
​
    private Integer id;
    private String name;
}
​

接着开始写mapper接口和mapper.xml

java 复制代码
package cn.linstudy.mapper;
​
import cn.linstudy.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
​
import java.util.List;
​
/**
 * @Description
 * @Date 2023/6/18
 * @Author XiaoLin
 */
@Mapper
public interface DeptMapper {
​
    List<Dept> listAllDept();
}
​
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 namespace="cn.linstudy.mapper.DeptMapper">
​
    <select id="listAllDept" resultType="cn.linstudy.pojo.Dept">
        select id , name from dept;
    </select>
</mapper>
​

最后就可以开始测试了。

java 复制代码
package cn.linstudy;
​
import cn.linstudy.mapper.DeptMapper;
import cn.linstudy.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
​
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
​
/**
 * @Description
 * @Date 2023/6/18
 * @Author XiaoLin
 */
public class TestMyBatis {
​
    @Test
    public void test1() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
        List<Dept> depts = deptMapper.listAllDept();
        for (Dept dept : depts) {
            System.out.println(dept);
        }
​
    }
​
}

运行测试类,出现了我们表中的数据即表示我们的环境搭建是成功的。

这段代码中比较重要的一句话就是通过IO获取输入流。

ini 复制代码
 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

通过IO方式打开输入流,获取mybatis-config.xml以及xxxMapper.xml,因为在mybatis-config.xml中已经配置好了mapper文件的路径,所以在以一次的IO中把两者的信息都读到了。

如果有知道ibatis(mybatis的前身)的话,还有另外一种比较古老的写法。他的区别是在于不再通过sqlSession.getMapper()方法去获取mapper,而是通过sqlSession.selectList(),里面传入对应的mapper的全路径以及对应的方法名来获取到对应的数组对象。

ini 复制代码
    @Test
    public void test2() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Dept> depts = sqlSession.selectList("cn.linstudy.mapper.DeptMapper.listAllDept");
        for (Dept dept : depts) {
            System.out.println(dept);
        }
    }

这两种方法的实现效果是一样的,但是哪一种比较好呢?当然是第一种比较好,因为我们平时写的就是第一种。答案是因为第一种表达的概念更加清晰,就更加直观,deptMapper.listAllDept()很明显就是deptMapper的listAllDept方法,而且是对部门进行操作的,这种方式更符合面向对象的概念。

那么第一种是如何实现的呢?其实很简单,其实第一种本质上是对第二种的进一步封装,封装的实现方法是使用了代理设计模式。

相关推荐
柏油6 小时前
MySQL InnoDB 行锁
数据库·后端·mysql
咖啡调调。6 小时前
使用Django框架表单
后端·python·django
白泽talk6 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师6 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
一只叫煤球的猫6 小时前
你真的会用 return 吗?—— 11个值得借鉴的 return 写法
java·后端·代码规范
Asthenia04126 小时前
HTTP调用超时与重试问题分析
后端
颇有几分姿色7 小时前
Spring Boot 读取配置文件的几种方式
java·spring boot·后端
AntBlack7 小时前
别说了别说了 ,Trae 已经在不停优化迭代了
前端·人工智能·后端
@淡 定7 小时前
Spring Boot 的配置加载顺序
java·spring boot·后端