`

MyBatis源码解析系列(三)--从诞下SqlSession说起

阅读更多

上一篇MyBatis源码解析系列中,我们说完了SqlSessionFactory的诞生过程。这一篇中,我们要根据SqlSessionFactory工厂去得到SqlSession。那么,在这个过程中,究竟做了些什么?我们一一去解读。

一、SqlSession怎么来的

SqlSession是一个接口类,继承了Closeable(只有一个从AutoCloseable接口类继承来的方法close)。在SqlSession接口类中,提供了各种查询、删除、更新、提交、回滚等等方法。我们看类图:


 

 既然是个接口类,那么总要有实现类去做这些事情,才能显示出接口类的价值。那么SqlSession是怎么来的?实现类是谁?

在篇二中,我们得到了SqlSessionFactory,它的默认实现类是DefaultSqlSessionFactory,既然是工厂实现类,那么DefaultSqlSessionFactory这里就是生产SqlSession的工厂车间。从这里,我们就可以找到SqlSession的来源。我们去看看。


 从类图中我们可以看到,DefaultSqlSessionFactory提供了很多openSession方法,返回的对象类型就是SqlSession。

我们看下源码,源码中分为两种方式生产SqlSession,一种是使用方法private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit),一种是使用重载的private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection)。

 

    public SqlSession openSession() {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

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

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

    public SqlSession openSession(TransactionIsolationLevel level) {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), level, false);
    }

    public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return this.openSessionFromDataSource(execType, level, false);
    }

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

    public SqlSession openSession(Connection connection) {
        return this.openSessionFromConnection(this.configuration.getDefaultExecutorType(), connection);
    }

    public SqlSession openSession(ExecutorType execType, Connection connection) {
        return this.openSessionFromConnection(execType, connection);
    }

 那我们就分开来看下这两方法。

 

1、private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit):

源码如下:

 

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

 我们一行行来解释。结合我们的debug过程。

 

①在Environment environment = this.configuration.getEnvironment();中,根据我们在得到SqlSessionFactory过程中设置的对象configuration来获取在解析<element>元素时候设置的环境信息environment,设置后的信息如下:


 

 

②在TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);中,根据environment环境信息去获取environment对象中的TransactionFactory,这里是JdbcTransactionFactory,源码如下:

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
        return (TransactionFactory)(environment != null && environment.getTransactionFactory() != null ? environment.getTransactionFactory() : new ManagedTransactionFactory());
    }

 ③在tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);中,使用transactionFactory工厂类去获取Transaction,这里传了三个参数,一是environment的数据源信息,一个是隔离级别,一个是是否自动提交的标识。我们看下这个newTransaction---构造Transaction的方法源码,这个方法的实现在JdbcTransactionFactory类中:

 

 

public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
        return new JdbcTransaction(ds, level, autoCommit);
    }

 这里又使用了JdbcTransaction类的构造函数:

 

 

public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        this.dataSource = ds;
        this.level = desiredLevel;
        this.autoCommmit = desiredAutoCommit;
    }

 

这样,获取到的Transaction就是JdbcTransaction。设置的信息如下,来个图看的更明白些:


 

④在 Executor executor = this.configuration.newExecutor(tx, execType);中,使用Transaction和execType来获取执行器,那这里的execType是啥玩意?这个就是在解析核心配置文件的<setting>标签时(方法在XMLConfigBuilder类中的settingsElement解析方法中),如<setting name="defaultExecutorType" value="SIMPLE"/>,会设置在configuration对象中,不同的execType标识不同的含义。它的取值有三个(SIMPLE, REUSE ,BATCH),含义分别如下:

SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。不设置时候默认使用SIMPLE,就是普通的执行器。我们这里使用的默认。

newExecutor方法源码如下:

 

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }

        if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

 那我们这里得到的Executor经过判断就是SimpleExecutor了。

 

⑤在 var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);中,我们要去获取SqlSession的实现类了DefaultSqlSession,终于到了最后。源码如下:

 

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
        this.configuration = configuration;
        this.executor = executor;
        this.dirty = false;
        this.autoCommit = autoCommit;
    }

这样,SqlSession的实现类DefaultSqlSession就拥有了配置对象信息,拥有了执行器信息,那么它就知道怎么去处理sql语句了。看看,这个configuration对象贯穿始终,核心的核心,源码是不会骗人的。

 

2、在private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection)方法中,它的源码如下:

private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
        DefaultSqlSession var8;
        try {
            boolean autoCommit;
            try {
                autoCommit = connection.getAutoCommit();
            } catch (SQLException var13) {
                autoCommit = true;
            }

            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            Transaction tx = transactionFactory.newTransaction(connection);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var14, var14);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

 与上一个方法唯一的不同点在于,它传递了Connection 类的对象,这个对象用来获取autoCommit属性的值,其他跟上一个方法一模一样,我们不再赘述。

 

二、综上所述

上面就是获取SqlSession的所有步骤,是不是很简单?这就是源码,理解了原理,以后谁问也不怕。

下一帖,我们就要通过SqlSession去执行getMapper方法了,很期待。

 

 

 

 

 

 

 

 

 

  • 大小: 35.9 KB
  • 大小: 23.7 KB
  • 大小: 27.1 KB
  • 大小: 11.8 KB
分享到:
评论

相关推荐

    mybatis-plus-boot-starter-3.4.3.3.jar

    mybatis-plus-boot-starter.jar 各个版本下载, ...Mybatis-Plus(简称MP)是一个基于MyBatis的增强工具库,它简化了与数据库的交互操作并提供了一系列增强功能,使开发者能够更加方便快捷地进行数据库访问。

    mybatis-3-mybatis-3.2.6

    1. **配置解析**:MyBatis的配置文件(mybatis-config.xml)被解析成Configration对象,这个对象包含了所有的全局配置信息,如数据源、事务管理器、Mappers等。解析过程主要由XMLConfigBuilder类完成。 2. **...

    mybatis-3.5.9 源码(mybatis-3-mybatis-3.5.9.zip)

    在 MyBatis-3.5.9 版本中,我们可以深入源码,探究其内部机制和优化点。 1. **SqlSessionFactory 和 SqlSession** - SqlSessionFactory 是 MyBatis 的核心组件,它用于创建 SqlSession 对象,每次数据库操作都需要...

    mybatis-plus-extension-3.5.3.1.jar

    mybatis-plus-extension.jar 各个版本,免费下载。 mybatis-plus 的扩展插件。,各个版本,免费下载。 mybatis 增强工具包的扩展插件,各个版本,免费下载。 下载不了,可关注我,评论区联系我。

    mybatis-3.2.2-src.rar 源码

    这个源码包"mybatis-3.2.2-src.rar"包含了完整的Mybatis 3.2.2版本的源代码,对开发者来说是一份宝贵的学习资源。 源码分析可以从以下几个主要方面展开: 1. **架构设计**:Mybatis 的核心组件包括...

    mybatis-plus3.5.2 jar包

    plus3.5.2常用jar包,mybatis-plus-3.5.2.jar、mybatis-plus-annotation-3.5.2.jar、mybatis-plus-core-3.5.2.jar、mybatis-plus-extension-3.5.2.jar、mybatis-plus-generator-3.5.2.jar和源码包mybatis-plus-...

    mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip

    mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip mybatis-plus最新代码生成器项目源码 :mybatis-plus-generator.zip ...

    mybatis-generator-core-1.4.0-SNAPSHOT.jar

    mybatis-generator-core-1.4.0-SNAPSHOT. 源码生成mybatis-generator-core-1.4.0-SNAPSHOT.jar方法.详细可见 https://blog.csdn.net/dono118/article/details/82980841

    mybatis-3-mybatis-3.3.0-SNAPSHOT.zip

    源码中的"mybatis-3-mybatis-3.3.0-SNAPSHOT"包含了MyBatis的主要组件和模块,如SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Executor、MappedStatement、ParameterHandler、ResultSetHandler、...

    mybatis-3-mybatis-3.3.0.zip

    通过解压"Mybatis-3-mybatis-3.3.0.zip",你可以获得完整的MyBatis框架源码,包括核心库、示例项目、文档和测试用例,这对于学习和深入理解MyBatis的工作原理非常有帮助。同时,你可以根据项目需求,将其集成到你的...

    mybatis-generator-core-1.3.2

    《MyBatis Generator Core 1.3.2:自动化代码生成的艺术》 在Java开发领域,MyBatis Generator(MBG)是一个强大的工具,它极大地简化了数据访问层的编码工作。MyBatis Generator Core 1.3.2是这个框架的一个版本,...

    mybatis-generator-core-1.3.2-sources

    mybatis-generator-core-1.3.2-sources

    mybatis-generator-core-1.3.5.jar

    jar包

    MyBatis-3-User-Guide-Simplified-Chinese.rar

    MyBatis 提供了拦截器插件机制,可以通过实现Interceptor接口并配置在mybatis-config.xml中,对SqlSession或Executor等对象的行为进行增强。 9. **MyBatis-Spring 集成** MyBatis 可以与Spring框架无缝集成,使用...

    mybatis-3.3.0,mybatis-spring-1.2.3.jar

    至于压缩包中的"mybatis-3.3.0"文件,这很可能包含了MyBatis框架的核心库,其中包括了MyBatis的主要类和接口,如SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession等。源码分析可以帮助我们深入理解MyBatis...

    mybatis-3-mybatis-3.5.7.zip源码

    1. **配置文件解析**:MyBatis的核心配置文件`mybatis-config.xml`定义了数据源、事务管理器、Mappers等关键元素。通过`XMLConfigBuilder`解析这些配置,构建出`Configuration`对象,它是整个MyBatis框架的中心。 2...

    mybatis-generator-core-1.3.6-sources

    mybatis-generator-core-1.3.6-sources对应的源码文件

    mybatis-3.0.3-SNAPSHOT-bundle.zip

    1. **mybatis-3.0.3-SNAPSHOT.jar**:这是MyBatis的核心库,包含了所有必要的类和接口,如SqlSession, SqlSessionFactory, Executor等,它们是执行数据库操作的基础。 2. **mybatis-3.0.3-SNAPSHOT-sources.jar**:...

    mybatis-generator-core-1.3.2(含有源码--生成注释、自定义sql)

    mybatis-generator-core-1.3.2(含有源码--生成注释、自定义sql) 只需修改2个文件即可,生成了mysql字段的注释,以及去除多余无用的sql,只留下增删改查,文件内含源码和已经打好的jar包,直接使用即可

Global site tag (gtag.js) - Google Analytics