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方法,而且是对部门进行操作的,这种方式更符合面向对象的概念。

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

相关推荐
追逐时光者34 分钟前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
Jagger_34 分钟前
敏捷开发流程-精简版
前端·后端
苏打水com1 小时前
数据库进阶实战:从性能优化到分布式架构的核心突破
数据库·后端
间彧2 小时前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧2 小时前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧2 小时前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧2 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧3 小时前
Spring Cloud Gateway详解与应用实战
后端
EnCi Zheng4 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6014 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring