MyBatis工作流程及源码码解析

MyBatis是一款持久层框架,简化了数据库操作。其工作流程包括:创建SqlSessionFactoryBuilder,加载配置文件,创建SqlSessionFactory,打开SqlSession,执行查询,最后关闭资源。源码中通过XMLConfigBuilder解析配置,构建SqlSessionFactory,再创建SqlSession,执行数据库操作。
  1. 什么是mybatis?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

  这段话告诉我们mybatis是就是对数据库进行增删查改的工具,方便我们对数据库进行操作。

mybatis的工作流程

// 第一步,创建SqlSessionFactoryBuilder对象 

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

// 第二步,加载配置文件 

InputStream inputStream = Resources.getResourceAsStream("spring-mybatis.xml");

// 第三步,创建SqlSessionFactory对象 

SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);

// 第四步,创建SqlSession对象 

SqlSession sqlSession = sqlSessionFactory.openSession();

// 第五步,使用SqlSession对象执行查询

List<TUser> list = sqlSession.getMapper(TUserMapper.class).queryAll();

// 第七步,释放资源

sqlSession.close();

 

源代码://
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.session;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;

public class SqlSessionFactoryBuilder {
    public SqlSessionFactoryBuilder() {
    }

    public SqlSessionFactory build(Reader reader) {
        return this.build((Reader)reader, (String)null, (Properties)null);
    }

    public SqlSessionFactory build(Reader reader, String environment) {
        return this.build((Reader)reader, environment, (Properties)null);
    }

    public SqlSessionFactory build(Reader reader, Properties properties) {
        return this.build((Reader)reader, (String)null, properties);
    }

    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                reader.close();
            } catch (IOException var13) {
            }

        }

        return var5;
    }

    public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }

    public SqlSessionFactory build(InputStream inputStream, String environment) {
        return this.build((InputStream)inputStream, environment, (Properties)null);
    }

    public SqlSessionFactory build(InputStream inputStream, Properties properties) {
        return this.build((InputStream)inputStream, (String)null, properties);
    }

    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
            }

        }

        return var5;
    }

    public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }
}

 

 

从源码可以看出,归根到底还是只执行了一下两个方法之一:两者区别在于输入的方式不一样(字节流和字符流)。

 public SqlSessionFactory build(Reader reader, String environment, Properties properties)

和  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)

 

public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

至于这个方法,是调用DefaultSqlSessionFactory,这个方法是SqlSessionFactory的实现类。

完整的一次创建sqlsession过程如下:

代码:

InputStream inputStream = Resources.getResourceAsStream("spring-mybatis.xml");

源代码:

  1. 读取配置文件输入流:

public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
    InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
    if (in == null) {
        throw new IOException("Could not find resource " + resource);
    } else {
        return in;
    }
}

该方法将配置文件转换成字节流。

代码:

sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

使用SqlSessionFactoryBuilder创建sqlSessionFactory 对象

源代码:SqlSessionFactoryBuilder.build

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    SqlSessionFactory var5;
    try {
        XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
        var5 = this.build(parser.parse());
    } catch (Exception var14) {
        throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    } finally {
        ErrorContext.instance().reset();

        try {
            inputStream.close();
        } catch (IOException var13) {
        }

    }

XMLConfigBuilder方法(将由配置文件转换来的字节流转变成Configuration 对象)

 

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

传入configuration对象,调用SqlSessionFactory 的实现类DefaultSqlSessionFactory。

以上是SqlSessionFactory 创建的过程。

值得注意的是在DefaultSqlSessionFactory源代码里

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;

Configuration 为final修饰的,这说明mybatis应该是单例的。

接下来是创建sqlsession对象。

在DefaultSqlSessionFactory对SqlSessionFactory 里的8个构造方法均进行了实现。

在DefaultSqlSessionFactory源码里可以看出,8个构造方法可以分为两种。

最终调用

openSessionFromDataSource

或者

openSessionFromConnection

这两种方法。

public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
    return this.openSessionFromDataSource(execType, (TransactionIsolationLevel)null, autoCommit);
}

openSessionFromDataSource方法

 

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;//定义事务对象

    DefaultSqlSession var8;
    try {

//读取 之前输入的 configuration形成 Environment对象
        Environment environment = this.configuration.getEnvironment();
        TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);

//通过环境environment作为入参,获取到事务工厂
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        Executor executor = this.configuration.newExecutor(tx, execType);

//Mtbayis执行器 Executor 执行器
        var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);

//对DefaultSqlSession进行赋值
    } catch (Exception var12) {
        this.closeTransaction(tx);
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
    } finally {
        ErrorContext.instance().reset();
    }

    return var8;
}

到此,一个sqlsession对象就实例化好了,实际上openSession 就是对DefaultSqlSession类中的成员变量赋值。

接下来是用sqlsession对象对数据库进行操作。

如果使用sqlsession.getMapper( )进行接口绑定。

getMapper()方法会返回一个map对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值