vlambda博客
学习文章列表

Mybatis3源码分析:前期准备

回复“1024”获取最新大厂面试资料



背景

Mybatis应该是国内最流行的ORM框架,大多项目中我们应该都是使用的 Mybatis。Mybatis 中的 sql 大多都是配置在 xml 文件中的,我们为了方便 dba 对 sql 统一的管理需要将 sql 保存在数据库中。这样就要求 Mybatis 从数据库中加载配置,同时 dba 优化 sql 之后还得实现让 Mybatis 在不重启应用的情况下动态加载。要实现这些功能,需要对 Mybatis 进行扩展,所以本人花了一些时间分析一 Mybatis3 源码,在此记录。

分析计划

主要分析如下三大内容:

  1. 分析 Mybatis 是怎么解析配置文件
  2. 分析 Mybatis 是如何执行 Sql 并映射结果
  3. 分析 Mybatis 是如何使用缓存的

技术要求

  1. core java。尤其是 jdbc 部分。
  2. 基本的 xml 知识。
  3. 以上都具备的话,还需要花点时间看看 Mybatis

环境准备

在 IDEA 中新建一个普通的 maven 工程,并加上 Mybatis 的依赖

<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>com.zzw</groupId>
      <artifactId>mybatis</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <dependencies>
            <dependency>
                  <groupId>org.mybatis</groupId>
                  <artifactId>mybatis</artifactId>
                  <version>3.5.5</version>
            </dependency>
            <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>5.1.26</version>
            </dependency>
            <dependency>
                  <groupId>commons-lang</groupId>
                  <artifactId>commons-lang</artifactId>
                  <version>2.5</version>
            </dependency>
      </dependencies>
</project>

数据模型

用户定义

package com.zzw.mybatis.entity;

import java.util.List;

public class User {
    private long id;
    private String username;
    private List<Account> accounts;

    public long getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
}

账户定义

package com.zzw.mybatis.entity;

public class Account {
    private String id;
    private String payName;
    private String bankNo;

    public String getId() {
        return id;
    }

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

    public String getPayName() {
        return payName;
    }

    public void setPayName(String payName) {
        this.payName = payName;
    }

    public String getBankNo() {
        return bankNo;
    }

    public void setBankNo(String bankNo) {
        this.bankNo = bankNo;
    }
}

Mybatis 配置

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>
    <!--引入mysql配置-->
    <properties resource="db.properties"></properties>

    <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/UserMapper.xml"/>
    </mappers>
</configuration>

UserMapper.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="com.zzw.mybatis.dao.UserMapper">

    <resultMap id="UserMap" type="com.zzw.mybatis.entity.User">
        <id property="id" column="uid"/>
        <result property="username" column="username"/>
        <collection property="accounts" ofType="com.zzw.mybatis.entity.Account">
            <id property="id" column="aid"/>
            <result property="payName" column="payName"/>
            <result property="bankNo" column="bankNo"/>
        </collection>
    </resultMap>

    <select id="get" resultMap="UserMap">
        SELECT u.id uid, u.username,a.id as aid,a.payName,a.bankNo FROM t_user u,t_account a where u.id=#{id} and u.acctid = a.id
    </select>

</mapper>

跑跑试试看有没有问题

package com.zzw.mybatis;

import com.google.gson.Gson;
import com.zzw.mybatis.dao.UserMapper;
import com.zzw.mybatis.entity.User;
import com.zzw.mybatis.utils.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;

import java.io.IOException;

public class SqlSessionFactoryTest {
    public static void main(String[] args) throws IOException {
        SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSession();
        //获取对应的mapper
        UserMapper paymentMapper = sqlSession.getMapper(UserMapper.class);
        User user = paymentMapper.get(1);
        System.out.println(new Gson().toJson(user));

    }
}

SqlSessionFactoryUtil

package com.zzw.mybatis.utils;

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 java.io.IOException;
import java.io.InputStream;

public class SqlSessionFactoryUtil {

    private static SqlSessionFactory sqlSessionFactory;

    //静态代码块,保证线程安全
    static {
        String resource = "mybatis-config.xml";
        try {
            InputStream is = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

}

运行没有异常说明配置 OK!

其他说明

搭建这个环境的作用是为了在分析代码过程中进行 Debuger,有些时候源代码很难明白,Debuger 一下能知道代码的走向,有时源代码看明白了,Debuger 一下也能帮助验证自己的理解是否有错。Debuger 对分析源码非常有用。

使用 Maven 构建这个工程除了方便 jar 导入之后,还有一个用处就是在 eclipse 中查看源代码非常方便。在 eclipse 使用 maven 工程,eclipse 会自动下载并关联源代码。