MyBatis源码初始

学习参考 :

大家好,我是Leo🫣🫣🫣,从今天开始跟着孙帅老师一起学习MyBatis3的源码学习,这个系列记录着MyBatis3源码学习的笔记和思考,

让我们开始吧😎😎😎。

1. MyBatis回顾

1.1 关于开发环境

下面是笔者本次学习MyBatis源码的开发环境,大家可以进行参考。

lua 复制代码
 1. JDK8
 2. IDEA2023.2
 3. Maven3.8
 4. MySQL 8.0.32 --> MySQL 8 即可
 5. Mybatis 3.4.6

1.2 Mybatis开发的简单回顾

1. 什么是Mybatis

MyBatis 本是apache 的一个开源项目iBatis , 2010年这个项目由 apache software foundation 迁移到了google code,并且改名为MyBatis。MyBatis是一个基于Java的持久层框架Mybatis是一个ORM类型框架,解决的数据库访问和操作的问题,对现有JDBC技术的封装。

2. 为什么使用MyBatis?

我们以前在没有ORM框架的情况下,如果你要开发一个Web应用程序的话,你就必须要使用传统的JDBC代码来操作数据库,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet等,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,而这些代码写起来往往是重复的,写起来又繁琐又枯燥。

1.3 搭建MyBatis开发环境

1.导入依赖

xml 复制代码
  <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.4.6</version>
      </dependency>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.32</version>
 </dependency>

2.创建表以及编写实体类

表SQL

sql 复制代码
 CREATE TABLE `user` (
   `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
   `name` varchar(255) DEFAULT NULL COMMENT '名称',
   `password` varchar(255) DEFAULT NULL COMMENT '密码',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

编写实体类

typescript 复制代码
 package org.javatop.pojo;
 ​
 /**
  * @author : Leo
  * @version 1.0
  * @date 2023-10-17 21:22
  * @description : 用户实体类
  */
 public class User {
    private Integer id;
    
    private String name;
 ​
 ​
     public User() {
     }
 ​
     public User(Integer id, String name) {
         this.id = id;
         this.name = name;
     }
 ​
 ​
     public Integer getId() {
         return id;
     }
 ​
     public void setId(Integer id) {
         this.id = id;
     }
 ​
     public String getName() {
         return name;
     }
 ​
     public void setName(String name) {
         this.name = name;
     }
 ​
 ​
     @Override
     public String toString() {
         return "User{" +
                 "id=" + id +
                 ", name='" + name + ''' +
                 '}';
     }
 }

3.编写mapper文件以及mapper映射文件

mapper文件

java 复制代码
 package org.javatop.mapper;
 ​
 import org.javatop.pojo.User;
 ​
 import java.util.List;
 ​
 /**
  * @author : Leo
  * @version 1.0
  * @date 2023-10-17 21:27
  * @description : mapper文件
  */
 ​
 public interface UserMapper {
 ​
 ​
     /**
      * 查询所有用户信息
      * @return
      */
      List<User> selectUserList();
 }
 ​

mapper映射文件

sql 复制代码
 <select id="selectUserList" resultType="User">
         select id,name,password from user
 </select>

4.准备配置文件

编写mybatis-config.xml配置文件

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>
 ​
     <typeAliases>
         <typeAlias type="org.javatop.pojo.User" alias="User"/>
     </typeAliases>
 ​
 ​
     <environments default="default">
         <environment id="default">
             <transactionManager type="JDBC" />
             <dataSource type="POOLED">
                 <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                 <property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"/>
                 <property name="username" value="root"/>
                 <property name="password" value="root"/>
             </dataSource>
         </environment>
     </environments>
 ​
     <mappers>
         <!--<package name=""-->
         <mapper resource="UserMapper.xml"/>
     </mappers>
 ​
 </configuration>

5.编写测试类

编写测试类TestMyBatis

java 复制代码
 import org.apache.ibatis.session.SqlSession;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 import org.javatop.mapper.UserMapper;
 import org.javatop.pojo.User;
 import org.junit.Test;
 ​
 import org.apache.ibatis.io.Resources;
 ​
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
 ​
 /**
  * @author : Leo
  * @version 1.0
  * @date 2023-10-17 9:55
  * @description : MyBatis基本开发测试
  */
 public class TestMyBatis {
 ​
     /**
     * 用于测试: MyBatis基本开发的第一种
     */
     @Test
     public void test01() throws IOException {
         InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
         SqlSession sqlSession = sqlSessionFactory.openSession();
 ​
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 ​
         List<User> userList = userMapper.selectUserList();
 ​
         for (User user : userList) {
             System.out.println("user = " + user);
         }
     }
 }
 ​

运行结果:

5.总结MyBatis开发步骤

思考:除了这种方式,是否还有其它方式呢?

其实对于大家来说,很多是没有见过这种方式开发方式的,往远的说,其实就是MyBtis的前身了,ibatis ,笔者公司的老项目用的正是ibatis,话不多说,直接上代码。

ini 复制代码
/**
    * 用于测试:MyBatis 基本开发的第二种方式
    */
    @Test
    public void test02() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> userList =  sqlSession.selectList("org.javatop.mapper.UserMapper.selectUserList");
        userList.forEach(System.out::println);
    }

这种方式是通过每个mapper文件中的 namespace + 接口名称 来确定我们的mapper接口。虽然也能实现我们查询所有用户的功能,但是这样看起来可读性是不是太差了。其实两种方式功能等价 ,实现效果也是一样的。

区别:

第一种方式好 表达概念更清晰 第一种开发,本质上就是对第二种开发的封装。

markdown 复制代码
1. 编写实体类entity
2. 类型别名
3. 创建表table 
4. mapper接口
5. Mapper文件
6. Mapper文件的注册
7. JavaAPI编程 

2. MyBatis的核心对象

2.1 MyBatis的核心对象

1. 前言知识补充

Mybatis是对JDBC的封装,将JDBC封装成了一个核心的SQLSession对象。 JDBC当中的核心对象:Connection、Statement、ResultSet。

  • Statement:普通的Statement
  • PeparedStatement:预编译 Statement
  • CallableStatement:适用于存储过程Statement

注意:Mybatis中使用的是PeparedStatement预编译。

通过这些Statement与我们的数据库进行交互,然后由我们的结果集对象ResultSet对象进行封装。

SqlSession是对以上内容进行了封装。

相对于以上来讲,SQLSession是对JDBC的封装,SQLSessionFactory是创建SQLSession对象的工厂,我们还基于mybatis-config.xml配置

Mybatis,并且在Mapper.xml当中配置SQL,了解到这里我们对于Mybatis的认知就比较权限

在Java中,或者说在JVM当中对Mybatis相关的配置信息进行封装。这里边设计到很多的配置文件,我们不可能说用点就读一次文件,这样会有极大的

IO,IO是操作系统层面的资源,他的创建绝不是虚拟机单独完成的,是很耗时的,少操作或者能复用最好。 对于这种东西,我们都是在程序启动时一次性

读取,存储在Java对象当中

MyBatis当中的配置信息一共有两种:mybatis-config.xml和userMapper.xml。

其中mybatis-config.xml封装成了org.apache.ibatis.session.Configuration对象,DAOMapper.xml封装成了MapperdStatement部分数

据是在Configuration当中进行保存的。

基于以上,我们可以知道在Mybatis当中有两类对象:数据储存类对象 + 操作类对象。

2. 数据存储类对象

1.1 初始Configuration

概念:在Java中(JVM)对Mybatis相关的配置信息进行封装。

Configuration是数据存储类对象,是将Mybatis当中的mybatis-config.xml 封装成Configuration对象,Mapper.xml封装成了MappedStatement 对象,当然MappedStatement这样表述不是特别完整。

简单来讲Configuration的作用:

  1. 封装了mybatis-config.xml。

    1. 封装了mapper文件MappedStatement。
  2. 创建Mybatis其他相关的对象。

1.2 初始MapperSatement

对应的就是Mapper文件中的一个一个的配置标签

lua 复制代码
  <select id. -----> MappedStatement
  <insert id. -----> MappedStatement     
  注定 一个Mybatis应用中 N个MappedStament 对象 
  MappedStatment ---> Configuration 
1.3 mybatis-config.xml与Configuration属性的映射关系

我们打开Configuration的源码可以得知,在Configuration中定义了大量的mybatis-config.xml中的标签,比如: environmentssettingstypeAliasesMappers 等标签。

分析:

caches,parameterMaps,resultMaps,MapperdStatement,keyGenerators 这些是把Mapper.xml文件中的内容进行了封装。 resultMaps:所有的Mapper.xml文件中resultMap标签。 parameterMaps:是对sql标签上的parameterMap是属性做了处理。

上边这些属性都加了S都代表了是复数,也就是他的数量不只一个。这玩意存储的不是公共的,而是所有的。里边存储了对于所有的Mapper.xml文件中的这些属性都封装到这里边了。

这些不仅仅要存还要用,所以是将他们存入到了一个Map中,他是有key的,他的key就是namespace.id。所以你就发现这一组。这些对象封装到Configuration对象中之后都是采用的Map<String,xxx>这样的形式,key是namespace.id 的形式。

1.4 Configuration对象的作用

作用1: 封装Mybatis-Config.xml先关的内容。 environments属性,封装的environments标签 typeAliases标签(实体全限定类型和简称的映射)这个也在Configuration当中也有封装 Mappers标签,我们在Configuration当中也是有对象进行对应的。其中对应的是 Set loadResources 到这,Mybatis-config.xml所有的标签,我们在configuration对象当中就都可以找到了。

作用二: Configuration将xxxMapper.xml封装成了MapperStatment对象组放到了Configurantion对象中进行引用。 Configuration中的属性是Map<String,MappedStatement> mappedStatements 其中的String还是nameSpace.id Configuration对象还包括:还有其他的结果集,参数,使用返回参数key(caches,parameterMaps,resultMaps,MapperdStatement,keyGenerators )等等。

作用三: 他的第三个核心作用就是帮我们创建:Mybatis其他涉及到的核心对象也创建出来,所以我们认为他是Mybatis当中最为核心的对象。 在这里可以认为Configuration实现是这些对象的执行对象的工厂对象。

作用4: SQL映射配置管理:Configurationi对象负责管理应用程序的SQL映射配置信息。它可以读取和解析Mapper接口或XML文件,将SQL语句与数据库操作进行映射关联。Configuration对象维护了一个用于存储$QL映射配置的集合,其中包含了每个SQL语句的信息,如语句类型(INSERT、SELECT、UPDATE、DELETE)、参数映射、结果映射等。

总的来说,Configuration对象在MyBatis框架中承担着配置管理和资源管理的职责,负责管理数据源、SQL映射配置、对象工厂、对象包装器和插件等重要组件,以保证MyBatis的正常运行和提供灵活的配置和扩展能力。

1.5 MappedStatement对象

我们可以打开Configuration的源码中可以找到MapperStatement

通过ctrl + B 点进去查看

可以发现 MappedStatement对象,也是一个存储了对象,存储的是Mapper文件中的Statement也就是我们定义的SQL标签,其中封装的是我们Mapper文件中的一个个标签,举例来讲 其中一个标签就会被封装成MappedStatement对象

我们的标签当中肯定会有id的属性,在我们的MappedStatement当中也会有id的属性。id属性完全唯一,他存储的是namespace.id所以,也是唯一,注定了在一个Mabatis当中会有N个MapperStatement对象。

这里边的statementType是什么意思,指的就是普通,预编译,存储过程。默认使用的就是preparedStatement,所以在我们的SQL标签上也肯定有这个属性,这个属性默认一定是prepared。

注意:MappedStatement当中可以找到Configuration对象,Configurantion对象可以找到MapperdStatement对象,他俩互相引用,双向关联,可以互相找到。

3.总结

以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。

如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。

相关推荐
程序员大金30 分钟前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis
程序员大金40 分钟前
基于SpringBoot的旅游管理系统
java·vue.js·spring boot·后端·mysql·spring·旅游
Pandaconda1 小时前
【计算机网络 - 基础问题】每日 3 题(十)
开发语言·经验分享·笔记·后端·计算机网络·面试·职场和发展
程序员大金2 小时前
基于SpringBoot+Vue+MySQL的养老院管理系统
java·vue.js·spring boot·vscode·后端·mysql·vim
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS网上购物商城(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
Ylucius2 小时前
JavaScript 与 Java 的继承有何区别?-----原型继承,单继承有何联系?
java·开发语言·前端·javascript·后端·学习
ღ᭄ꦿ࿐Never say never꧂3 小时前
微服务架构中的负载均衡与服务注册中心(Nacos)
java·spring boot·后端·spring cloud·微服务·架构·负载均衡
.生产的驴3 小时前
SpringBoot 消息队列RabbitMQ 消息确认机制确保消息发送成功和失败 生产者确认
java·javascript·spring boot·后端·rabbitmq·负载均衡·java-rabbitmq
海里真的有鱼3 小时前
Spring Boot 中整合 Kafka
后端