Mybatis源码剖析---第一讲

Mybatis源码剖析

基础环境搭建
  1. JDK8
    在这里插入图片描述

  2. Maven3.6.3(别的版本也可以…)
    在这里插入图片描述

  3. MySQL 8.0.28 --> MySQL 8
    在这里插入图片描述

  4. Mybatis 3.4.6
    在这里插入图片描述

  5. 准备jar,准备数据库数据
    把依赖导入pom.xml

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <!--   <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.4.6</version>
           </dependency>-->

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <!--<dependency>
          <groupId>org.javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.27.0-GA</version>
        </dependency>

        <dependency>
          <groupId>ognl</groupId>
          <artifactId>ognl</artifactId>
          <version>3.2.18</version>
        </dependency>-->

        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-beta2</version>
        </dependency>

        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>3.1</version>
        </dependency>


    </dependencies>


    <build></build>

数据库中放置俩张表

CREATE TABLE `t_user` (
  `id` int DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

往里面加入数据
在这里插入图片描述

CREATE TABLE `t_account` (
  `id` int DEFAULT NULL,
  `accountNo` varchar(255) DEFAULT NULL,
  `balance` double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

往里面加入数据
在这里插入图片描述
2. 准备配置文件
a. 基本配置文件 mybatis-config.xml

  1. 数据源的设置 environments
  2. 类型别名
  3. mapper文件的注册
<?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>

    <!-- <settings>
         <setting name="cacheEnabled" value="true"/>
     </settings>-->


    <typeAliases>
        <typeAlias type="com.baizhiedu.entity.User" alias="User"/>
        <typeAlias type="com.baizhiedu.entity.Account" alias="Account"/>
    </typeAliases>


<!--    <plugins>-->
<!--        &lt;!&ndash;<plugin interceptor="com.baizhiedu.plugins.MyMybatisInterceptor">-->
<!--            <property name="test" value="111111"/>-->
<!--        </plugin>&ndash;&gt;-->
<!--        &lt;!&ndash;<plugin interceptor="com.baizhiedu.plugins.MyMybatisInterceptor2"/>&ndash;&gt;-->
<!--        &lt;!&ndash;<plugin interceptor="com.baizhiedu.plugins.MyMybatisInterceptor3"/>&ndash;&gt;-->
<!--      &lt;!&ndash;  <plugin interceptor="com.baizhiedu.plugins.PageHelperInterceptor1">-->
<!--            <property name="queryMethodPrefix" value="query"/>-->
<!--            <property name="queryMethodSuffix" value="ByPage"/>-->
<!--        </plugin>&ndash;&gt;-->
<!--&lt;!&ndash;        <plugin interceptor="com.baizhiedu.plugins.LockInterceptor"/>&ndash;&gt;-->
<!--    </plugins>-->

    <environments default="default">
        <environment id="default">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/suns?useSSL=false"></property>
                <property name="username" value="root"></property>
                <property name="password" value="123xxx"></property>
            </dataSource>
        </environment>
        <!--    <environment id="oracle">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="oracle.jdbc.OracleDriver"></property>
                    <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property>
                    <property name="username" value="hr"/>
                    <property name="password" value="hr"/>
                </dataSource>
            </environment>-->
    </environments>

    <mappers>
        <!--<package name=""-->
        <mapper resource="UserDAOMapper.xml"/>
        <mapper resource="AccountDAOMapper.xml"/>
    </mappers>


</configuration>

-默认IDEA配置,MySQL环境搭建大家都懂,略过,不会的可以关注私聊评论-

Mybatis回顾

1. Mybatis做什么?

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

2. 核心代码分析

首先看看项目结构
在这里插入图片描述
interface

public interface AccountDAO {
    public void save(Account account);
}
public interface UserDAO {
    //public void save(User user); //SqlSession.insert()

    public void save(User user);

    public List<User> queryAllUsersByPage();//SqlSesson.select()

    public User queryUserById(@Param("id") Integer id);

    public void update(User user);

}



entity

package com.baizhiedu.entity;

import java.io.Serializable;

public class Account implements Serializable {
    private Integer id;
    private String accountNo;
    private double balance;

    public Account() {
        System.out.println("---------account----------");
    }

    public Account(Integer id, String accountNo, double balance) {
        this.id = id;
        this.accountNo = accountNo;
        this.balance = balance;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAccountNo() {
        return accountNo;
    }

    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", accountNo='" + accountNo + '\'' +
                ", balance=" + balance +
                '}';
    }
}

package com.baizhiedu.entity;

import java.io.Serializable;

public class User implements Serializable {
    private Integer id;
    private String name;
    private Integer version;

    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;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

现在让我们测试一下是否可以查到数据

import com.baizhiedu.dao.UserDAO;
import com.baizhiedu.entity.User;
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;

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();

        UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
        User user = userDAO.queryUserById(4);
        System.out.println(user);
    }
    // 方式二
    @Test
    public void test2() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
        // User user = userDAO.queryUserById(4);
        //System.out.println( "类型是" + sqlSession.selectOne("com.baizhiedu.dao.UserDAO.queryUserById", 4).getClass());
        User user = (User)sqlSession.selectOne("com.baizhiedu.dao.UserDAO.queryUserById", 4);
        System.out.println(user);
    }

}

在这里插入图片描述
测试类中,哪一种方法好?

功能 :两种方式功能等价
实现效果: 都有耦合性,更改sql字段,俩者都需要更改
那种方式好:第一种方式好 表达概念更清晰 ,第一种封装定义类型,第二种字符串不能表示类型,就好比 String name = "张三"new User().getName()第一个可以表示人,也可以表示狗,但第二个表示人清晰可见
第一种开发,本质上就是对第二种开发的封装。(代理设计模式)后续再聊

Mybatis核心对象

大家先看这张图有个印像

对于我们来讲。我们在对mybatis进行定义或者进行初步接触的过程当中,我们一直且反复都在强调的一个概念是什么呢?就是mybatis
它是一个JDBC的封装。它是通过什么来进行的封装?它是通过sqlsession这个对象。来进行的封装。那封装的是什么呢?那既然封装的是JDBC,那JDBC无外乎也就会涉及到这么几个核心的类型,一个是connection。一个是statement,一个是resultset。所以在这块儿呢,我们自然而然的就会得到这样一个信息,就是mybits这个框架。

通过sqlsession封装了JDBC。那封装了JDBC的连接connection。封装了statement,当然这个statement就包括我们所说的三种statement,一种是最普通的statement。一种是预编译statement,一种是coablestatement,而coablestatement,它主要应用在哪呢?主要应用在存储过程层面上。那通过这些statement与我们的数据库进行交互,最后它的结果由result进行封装,进而返回给我。所以circlesession它实际上应该封装的是这些东西。那这是我们最初在接触mybatis的时候,
给大家的一个最最基本的概念。但是如果我们仔细分析的话,你就会发现,作为mybatis来讲,它其实不仅仅包括sqlsession。它还包括什么呢?它还包括sqlsession。前面的什么?他的父亲,也就是他的工厂。sqlsessionfactory.它还包括什么?还包括mybatis-config.xml以及我们的mapper.xml这些东西。所以你如果仅认为它封装了JDBC进行使用的话,那实际上理解上是没有问题的。但是细节有很多的偏差。那它至少要包括的是四个环节。sqlsession封装了JDBC的使用。而它还提供了sqlsession factory来创建sqlsession。那还需要我们在配置文件当中去书写相关的配置,进而最终由sqlsession帮我们基于mapper文件。生成dao。哎,那么这一套东西才构成了mybatis,所以显然我们曾经的分析是不到位的,是不透彻的。是有问题的。

它实际上是有两大类核心对象的一类,我们叫做数据存储类对象。一类我们叫做的是操作类型的对象。哎,这是整个mybatis的两块儿内容。那什么是数据存储类的对象呢?它的概念是什么呢?它最为核心的概念就是在JAVA中。或者说,在虚拟机当中。对。mybatis.相关的配置信息。进行封装。因为我们知道文件,它存了很多东西。它存了很多配置的内容,我们不可能用点儿就读一次文件,用点儿就读一次文件,因为什么呢?因为它会频繁产生IO。而你要知道,作为IO来讲,它是操作系统层面上的资源,它的一个创建绝不是虚拟机单独来完成的。它一定是要虚拟机来与操作系统进行交互和交流来完成的。所以注定IO在我们的开发过程当中一定是越少越好,能复用最好。那所以我们说这些mybatis的相关的配置信息,它不可能是随用随读的,它一定是一次性读取。进而封装在JAVA的对象当中。这是火星。能听得明白我的意思吗?好,那这就涉及到了两个问题了,哪两个问题呢?第一个问题就是它的配置信息要封装对象,它有几种配置信息呢?两种一种,刚才我们说过了,叫做mybatis-config.xml,另外一种,我们叫做xxxdaomapper.xml。
由这两个。那这两种信息最终都要进行JAVA的封装,那么这个mybatis-config.xml封装成了什么呢?封装成了一个叫做configuration的对象。那换句话说,我们可以认为configuration对象。它封装的就是mybatis相关的内容呃。而这个xxxDaomapper.xml,它对应的是怎么进行的封装呢?它对应的是一个叫做mappedstatement。对象的风格。当然这块儿仅仅是一个形象上的认知。呃,那不准确。后面呢,我们还会再剖析。那所以呢,首先第一个层面上,我们就要去验证,什么验证我们所说的。这个configuration这个类是对mybatis.config.xml的封装。那怎么来验证呢?
在这里插入图片描述

在这里插入图片描述
这个是开启二级缓存,我们后续会继续剖析
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. 数据存储类对象
   概念:在Java中(JVM)对Mybatis相关的配置信息进行封装
   mybatis-config.xml ----> Configuration
   Configuration 
      1. 封装了mybatis-config.xml
      2. 封装了mapper 文件  MappedStatement
      3. 创建Mybatis其他相关的对象 
   XXXDAOMapper.xml ----> MappedStatement(形象的认知,不准确)
  操nt对象 
      对应的就是 Mapper文件中的一个一个的 配置标签 
      <select id. -----> MappedStatement
      <insert id. -----> MappedStatement 
      
      注定 一个Mybatis应用中 N个MappedStament 对象 
      MappedStatment ---> Configuration 
   
      MappedStatment 中 封装SQL语句 ---> BoundSql
2. 操作类对象 (SqlSession) ---> 门面 
    Excutor
      Excutor 是Mybatis中处理功能的核心
              1. 增删改update  查query
              2. 事务操作 
                 提交 回滚
              3. 缓存相关的操作
            
      Excutor接口 (适配器模式) 操作相关都要设计成接口
           BatchExcutor
               JDBC中批处理的操作, BatchExcutor 
           ReuseExcutor
               目的:复用 Statement (需要sql一样)
               insert into t_user(ID,name)values(1,‘孙帅’);
               insert into t_user(ID,name)values(2,‘孙帅1’);
           SimpleExcutor
               常用Excutor Mybatis推荐 默认 
               Configuration protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
           
    StatmentHandler
       StatementHandler是Mybatis封装了JDBC Statement,真正Mybatis进行数据库访问操作的核心
                  功能:增删改差
       StatementHandler接口
                  SimpleStatementHandler
                      JDBC 操作 
                  PreparedStatementHandler
                  CallableStatementHandler 
    
    ParameterHandler
        目的:Mybatis参数 ---》 JDBC 相关的参数 
             @Param ---> #{} --- > ?
    ResultSetHandler
        目的:对JDBC中查询结果集 ResultSet 进行封装 
        
    TypeHandler
        Java程序操作 数据库
        Java类型   数据库类型
        String    varchar
        int       number
        int       int 
    excutor和statementhandler都用到了适配器模式



在这里插入图片描述

在这里插入图片描述
在configuration里面,它是不是专门有这么一个内容?是来存所有的mappedstatement的。也就是configuration是可以找到谁的。是可以找到所有的mappedstatement的。那同样按照我们刚才所关注的mappedstatement里面是不是也存了configuration啊?那也就是mappedstatement是不是也可以找到对应的configuration,因为configuration只是一个,所以它就存了一个,所以它们两个人的关系是什么是?是双向的关联关系,你中有我,我中有你,我既可以通过configuration找到所有的mappedstatement。

那么当然,我也可以通过mappedstatement找到对应的configuration,这样的话它会方便后续mybatis内部在运行的过程当中。可以去解决一些核心的问题。所以。在这儿你一定要注意,它封装的是这些标签,那这些标签\的内容是和mybatis的mappedstatement一一对应的,而且哎。在一个mybatis应用当中,它可以有n个mappedstatement,并且mappedstatement.它是可以找到什么呢?
可以找到configuration。这样我们就把mybatis当中所涉及到的所有的配置文件的数据通过。这两个类型彻底都封装完成了。那换句话说,日后你想要这些相关的内容,比如说mybatis-config.xml,想要所有的mappedstatement。和其他相关的对象,你用configuration就可以了,你要想获得某一个具体的标签,它相关的内容你是不是有map pedstatement对象就够了?而且他们彼此是可以互相找到对方的,那你在编程的时候灵活度就更高了。这就是我们所说的在mybatis核心对象当中的第一类对象数据存储类对象。那这也就是在整个我的这张图里面。这块的内容。任何一个mybatis应用都有configuration和n个mappedstatement,而每一个mappedstatement,它对应的就是一个一个的标签至此,核心对象数据存储这块的内容,我就给大家分析完了。当然,这块还是死的。就是比如说什么时候创建configuration?什么时候创建mappedstatement以及这些数据和mybatis核心的功能,它该怎么交互啊?这都是我们后续要讲解的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值