详解MyBatis的SqlSession获取流程

 更新时间:2023年07月10日 10:15:58   作者:半夏之沫  
SqlSession的获取是通过SqlSessionFactory的openSession() 方法,那么具体的获取流程是什么,所以本文就给大家详细讲解一下MyBatis的SqlSession获取流程,需要的朋友可以参考下

前言

已知在MyBatis的使用中,使用MyBatis时会先读取配置文件mybatis-config.xml为字符流或者字节流,然后通过SqlSessionFactoryBuilder基于配置文件的字符流或字节流来构建SqlSessionFactory,然后再通过SqlSessionFactoryopenSession() 方法获取SqlSession,示例代码如下所示。

public static void main(String[] args) throws Exception {
    String resource = "mybatis-config.xml";
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(Resources.getResourceAsStream(resource));
    SqlSession sqlSession = sqlSessionFactory.openSession();
}

上述示例代码中的SqlSessionFactory实际为DefaultSqlSessionFactory,本篇文章将对DefaultSqlSessionFactory获取SqlSession的流程进行学习。

正文

DefaultSqlSessionFactoryopenSession() 方法如下所示。

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

继续看openSessionFromDataSource() 方法的实现,如下所示。

private SqlSession openSessionFromDataSource(ExecutorType execType, 
                                             TransactionIsolationLevel level, 
                                             boolean autoCommit) {
    Transaction tx = null;
    try {
        // Environment中包含有事务工厂和数据源
        final Environment environment = configuration.getEnvironment();
        // 获取事务工厂
        // 如果配置了JDBC事务,则获取JDBC事务工厂,否则获取MANAGED事务工厂
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        // 创建事务
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        // 创建执行器
        final Executor executor = configuration.newExecutor(tx, execType);
        // 构建DefaultSqlSession并返回
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        closeTransaction(tx);
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

openSessionFromDataSource() 方法会先从Configuration中将Environment获取出来,Environment中包含有事务工厂和数据源,Environment是在MyBatis配置文件中进行配置并会在加载MyBatis配置文件时被添加到Configuration中。

MyBatis的配置文件中可以配置两种事务工厂,为JDBC事务工厂和MANAGED事务工厂,它们分别可以创建JDBC事务和MANAGED事务,类图如下所示。

获取事务工厂的getTransactionFactoryFromEnvironment() 方法如下所示。

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
        // 配置了事务工厂则使用配置的事务工厂
        // MyBatis可以配置JDBC和MANAGED这两种事务工厂
        return new ManagedTransactionFactory();
    }
    // 没做配置的情况下使用MANAGED事务工厂
    return environment.getTransactionFactory();
}

MyBatis中如果使用JDBC事务,则事务的管理由java.sql.Connection完成,如果使用MANAGED事务,则MyBatis会将事务的管理交由WEB容器(TomcatJBoss等)来完成。以commit()rollback() 方法为例,看下JdbcTransactionManagedTransaction对这两个方法的实现,如下所示。

public class JdbcTransaction implements Transaction {
    // ......
    @Override
    public void commit() throws SQLException {
        if (connection != null && !connection.getAutoCommit()) {
            if (log.isDebugEnabled()) {
                log.debug("Committing JDBC Connection [" + connection + "]");
            }
            connection.commit();
        }
    }
    @Override
    public void rollback() throws SQLException {
        if (connection != null && !connection.getAutoCommit()) {
            if (log.isDebugEnabled()) {
                log.debug("Rolling back JDBC Connection [" + connection + "]");
            }
            connection.rollback();
        }
    }
    // ......
}
public class ManagedTransaction implements Transaction {
    // ......
    @Override
    public void commit() throws SQLException {
        // 不做任何事情
    }
    @Override
    public void rollback() throws SQLException {
        // 不做任何事情
    }
    // ......
}

回到openSessionFromDataSource() 方法,创建好事务后,会构建执行器Executor,看一下newExecutor(Transaction transaction, ExecutorType executorType) 方法的实现,如下所示。

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    // 根据ExecutorType的枚举值创建对应类型的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);
    }
    // 如果MyBatis配置文件中开启了二级缓存
    if (cacheEnabled) {
        // 创建CachingExecutor作为Executor的装饰器,为Executor增加二级缓存功能
        executor = new CachingExecutor(executor);
    }
    // 将插件逻辑添加到Executor中
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

在上面构建执行器Executor的方法中,主要是做了三件事情,解释如下。

第一件事情,根据ExecutorType的枚举值创建对应类型的ExecutorExecutorType枚举值如下所示。

public enum ExecutorType {
    SIMPLE, REUSE, BATCH
}

MyBatis提供了三种类型的Executor,分别为BatchExecutorReuseExecutorSimpleExecutor,类图如下所示。

BaseExecutor中定义了四个抽象方法,如下所示。

protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;
protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;
protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
    throws SQLException;
protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
    throws SQLException;

BaseExecutor提供的方法中会调用这四个抽象方法,同时这四个抽象方法需要由BatchExecutorReuseExecutorSimpleExecutor根据各自的功能进行实现,所以Executor的设计使用了模板设计模式。

第二件事情,如果在MyBatis配置文件中开启了二级缓存,则为Executor创建装饰器CachingExecutor,以增加对二级缓存功能的支持。CachingExecutorExecutor的关系如下所示。

CachingExecutor实现了Executor接口,同时CachingExecutor持有Executor的引用,这是装饰器模式的应用。关于MyBatis中的缓存,会在后续的文章中进行介绍。

第三件事情,如果配置了插件,则将插件的逻辑添加到Executor中。关于MyBatis中的插件,会在后续的文章中进行介绍。

回到openSessionFromDataSource() 方法,创建好Executor后,就会调用DefaultSqlSession的构造方法创建一个DefaultSqlSession并返回,在DefaultSqlSession的构造方法中只是进行了简单的赋值,如下所示。

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

至此,SqlSession就创建出来了。

总结

SqlSession的获取是通过SqlSessionFactoryopenSession() 方法,SqlSession的创建过程主要先是创建事务管理器,然后基于事务管理器创建执行器Executor,最后基于Executor创建SqlSession

通常,SqlSessionFactoryDefaultSqlSessionFactory,创建出来的SqlSessionDefaultSqlSession

整体的一个流程图如下所示。

以上就是详解MyBatis的SqlSession获取流程的详细内容,更多关于MyBatis SqlSession获取流程的资料请关注脚本之家其它相关文章!

相关文章

  • Mybatis中#{}和${}传参的区别及#和$的区别小结

    Mybatis中#{}和${}传参的区别及#和$的区别小结

    这篇文章主要介绍了Mybatis中#{}和${}传参的区别及#和$的区别小结 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-07-07
  • Spring MVC异步上传、跨服务器上传和文件下载功能实现

    Spring MVC异步上传、跨服务器上传和文件下载功能实现

    这篇文章主要介绍了Spring MVC异步上传、跨服务器上传和文件下载功能实现,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • java把字符串写入文件里的简单方法分享

    java把字符串写入文件里的简单方法分享

    这篇文章主要介绍了java把字符串写入到文件里的简单方法,这是跟一个外国朋友学的代码,需要的朋友可以参考下
    2014-03-03
  • SpringBoot整合PostgreSQL的示例代码

    SpringBoot整合PostgreSQL的示例代码

    本文主要介绍了SpringBoot整合PostgreSQL的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Java中的密码加密方式

    Java中的密码加密方式

    文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固定,且不容易发生碰撞,此外,通过加盐和多重加密,可以进一步增加密码的复杂性和安全性
    2025-01-01
  • java.net.MalformedURLException异常的解决方法

    java.net.MalformedURLException异常的解决方法

    下面小编就为大家带来一篇java.net.MalformedURLException异常的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Java如何使用poi导入导出excel工具类

    Java如何使用poi导入导出excel工具类

    这篇文章主要介绍了Java如何使用poi导入导出excel工具类问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 本真的REST架构风格理解

    本真的REST架构风格理解

    这篇文章主要为大家介绍了本真的REST架构风格的深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • Java基础之Web服务器与Http详解

    Java基础之Web服务器与Http详解

    无论你是前端开发者还是后端开发者,以及测试工程师,这篇文章的知识都是你需要弄懂的。读完这一篇文章,将全面弄懂 HTTP 协议、TCP 协议,面试官再也难不倒你相关知识
    2021-09-09
  • 关于Java中Object类的几个方法示例

    关于Java中Object类的几个方法示例

    这篇文章主要给大家介绍了关于Java中Object类的几个方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-05-05

最新评论