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

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

相关推荐
千里码aicood37 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
程序员-珍1 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
liuxin334455661 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
架构师吕师傅2 小时前
性能优化实战(三):缓存为王-面向缓存的设计
后端·微服务·架构
bug菌2 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee
夜月行者4 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm
Yvemil74 小时前
RabbitMQ 入门到精通指南
开发语言·后端·ruby
sdg_advance4 小时前
Spring Cloud之OpenFeign的具体实践
后端·spring cloud·openfeign
猿java5 小时前
使用 Kafka面临的挑战
java·后端·kafka
碳苯5 小时前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os