目录

  • 一 SqlSession的创建
    • 1.1 获取environments配置元素
    • 1.2 获取事务工厂
    • 1.3 获取执行器Executor
    • 1.4 构建DefaultSqlSession

系列文章:

文章 状态 时间 描述
(一)Mybatis 基本使用 已复习 2022-12-14 对Mybtais的基本使用,能够开发
(二)Mybatis-config.xml的初始化 已复习 2023-02-10 对我们编写的mybatis配置文件的解析
(三)SqlSessionFactory的初始化 已复习 2023-02-11 SqlSession会话工厂的初始化
(四)Mapper文件的解析 已复习 2023-02-12 主要对我们编写的Mapper.xml进行解析
(五)SqlSession的创建 已复习 2023-02-13 主要介绍构建DefaultSqlSessionFactory
(六)Mapper的接口代理 已复习 2023-02-14 如何通过动态代理来执行我们编写的方法
(七)MapperMethod的INSERT分析 已复习 2023-02-15 通过代理对象来执行Insert语句,返回结果
(八)MapperMethod的Select分析 已复习 2023-02-16 通过代理对象来执行Select语句,返回结果
(九)Mybatis的PreparedStatement 已复习 2023-02-17 预处理语句的常见,以及与数据库打交道
(十)Mybatis的结果隐射 已复习 2023-02-18 数据库结果与实体类对象的转换
(十一)Mybatis中的缓存 计划中 Mybatis中一级缓存与二级缓存
(十二)Mybatis中的插件开发 计划中 Mybatis中的插件运行机制与开发
(十三)Mybatis中的四大组件梳理 计划中 Mybatis中的四大组件的梳理
(十四)Mybatis中的设计模式梳理 计划中 Mybatis中设计模式的整理
(十五)Spring-Mybatis整理 计划中 Spring与Mybatis整合
(十六)Mybatis疑惑总结 计划中 我遇到的疑惑与问题
  • 官网:mybatis – MyBatis 3 | 简介

使用 MyBatis 的主要 Java 接口就是 SqlSession。你可以通过这个接口来执行命令,获取映射器实例和管理事务。在介绍 SqlSession 接口之前,我们先来了解如何获取一个 SqlSession 实例。SqlSessions 是由 SqlSessionFactory 实例创建的。SqlSessionFactory 对象包含创建 SqlSession 实例的各种方法。而 SqlSessionFactory 本身是由 SqlSessionFactoryBuilder 创建的,它可以从 XML、注解或 Java 配置代码来创建 SqlSessionFactory。

一 SqlSession的创建

@Testvoid contextLoads() {// 第一阶段:MyBatis的初始化阶段String resource = "mybatis-config.xml";// 得到配置文件的输入流InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(resource);} catch (IOException e) {e.printStackTrace();}// 得到SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 第二阶段:数据读写阶段try (SqlSession session = sqlSessionFactory.openSession()) {// 找到接口对应的实现UserMapper userMapper = session.getMapper(UserMapper.class);// 组建查询参数User userParam = new User();userParam.setSchoolname("Sunny School");// 调用接口展开数据库操作List<User> userList =  userMapper.queryAllByLimit(userParam);// 打印查询结果for (User user : userList) {System.out.println("name : " + user.getName() + " ;  email : " + user.getEmail());}}}
  • 我们来看看SqlSession的创建是如何创建的,在上两篇文件中完成配置文件的解析返回SqlSessionFactory
          // 第二阶段:数据读写阶段try (SqlSession session = sqlSessionFactory.openSession()) {
  • 可以通过调式看出,我们的SqlSessionFactory的实现是DefaultSqlSessionFactory

DefaultSqlSessionFactory


@Overridepublic SqlSession openSession() {return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);}public enum ExecutorType {SIMPLE, // 为每个语句创建新的预处理语句REUSE,  // 复用BATCH   // 执行批量操作
}/*** 从数据源中获取SqlSession对象* @param execType 执行器类型* @param level 事务隔离级别* @param autoCommit 是否自动提交事务* @return SqlSession对象*/private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {// 找出要使用的指定环境final Environment environment = configuration.getEnvironment();// 从环境中获取事务工厂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); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}

主要包含以下几个步骤:

  1. 首先从configuration获取Environment对象,里面主要包含了DataSource和TransactionFactory对象
  2. 创建TransactionFactory对象
  3. 创建Transaction对象
  4. 从configuration获取Executor
  5. 构造DefaultSqlSession对象

1.1 获取environments配置元素

//配置environment环境
<environments default="development"><environment id="development">/** 事务配置 type= JDBC、MANAGED *  1.JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。*  2.MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。*/<transactionManager type="JDBC" />/** 数据源类型:type = UNPOOLED、POOLED、JNDI *  1.UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。*  2.POOLED:这是JDBC连接对象的数据源连接池的实现。 *  3.JNDI:这个数据源的实现是为了使用如Spring或应用服务器这类的容器*/<dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/xhm" /><property name="username" value="root" /><property name="password" value="root" />//默认连接事务隔离级别<property name="defaultTransactionIsolationLevel" value=""/> </dataSource></environment>
</environments>
  • 解析我们配置文件中的environment配置元素,具体解析过程请参考前面的文章。


XMLConfigBuilder

// 解析我们配置文件中的environment配置元素
private void environmentsElement(XNode context) throws Exception {if (context != null) {if (environment == null) {// 获取 default 属性environment = context.getStringAttribute("default");}for (XNode child : context.getChildren()) {// 获取 id 属性String id = child.getStringAttribute("id");/** 检测当前 environment 节点的 id 与其父节点 environments 的属性 default * 内容是否一致,一致则返回 true,否则返回 false* 将其default属性值与子元素environment的id属性值相等的子元素设置为当前使用的Environment对象*/if (isSpecifiedEnvironment(id)) {// 将environment中的transactionManager标签转换为TransactionFactory对象TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));// 将environment中的dataSource标签转换为DataSourceFactory对象DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));// 创建 DataSource 对象DataSource dataSource = dsFactory.getDataSource();Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory).dataSource(dataSource);// 构建 Environment 对象,并设置到 configuration 中configuration.setEnvironment(environmentBuilder.build());}}}
}

1.2 获取事务工厂

DefaultSqlSessionFactory

 private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {if (environment == null || environment.getTransactionFactory() == null) {// 委托事务工厂return new ManagedTransactionFactory();}// 我们配置的事务工厂JdbcTransactionFactoryreturn environment.getTransactionFactory();}

  • JdbcTransaction由JDBC进行事务管理

JdbcTransaction

// 由JDBC进行事务管理
public class JdbcTransaction implements Transaction {private static final Log log = LogFactory.getLog(JdbcTransaction.class);// 数据库连接protected Connection connection;// 数据源protected DataSource dataSource;// 事务隔离级别protected TransactionIsolationLevel level;// 是否自动提交事务protected boolean autoCommit;public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {dataSource = ds;level = desiredLevel;autoCommit = desiredAutoCommit;}public JdbcTransaction(Connection connection) {this.connection = connection;}@Overridepublic Connection getConnection() throws SQLException {if (connection == null) {openConnection();}return connection;}/*** 提交事务* @throws SQLException*/@Overridepublic void commit() throws SQLException {// 连接存在且不会自动提交事务if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Committing JDBC Connection [" + connection + "]");}// 调用connection对象的方法提交事务connection.commit();}}/*** 回滚事务* @throws SQLException*/@Overridepublic void rollback() throws SQLException {if (connection != null && !connection.getAutoCommit()) {if (log.isDebugEnabled()) {log.debug("Rolling back JDBC Connection [" + connection + "]");}connection.rollback();}}@Overridepublic void close() throws SQLException {if (connection != null) {resetAutoCommit();if (log.isDebugEnabled()) {log.debug("Closing JDBC Connection [" + connection + "]");}connection.close();}}protected void setDesiredAutoCommit(boolean desiredAutoCommit) {try {if (connection.getAutoCommit() != desiredAutoCommit) {if (log.isDebugEnabled()) {log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");}connection.setAutoCommit(desiredAutoCommit);}} catch (SQLException e) {// Only a very poorly implemented driver would fail here,// and there's not much we can do about that.throw new TransactionException("Error configuring AutoCommit.  "+ "Your driver may not support getAutoCommit() or setAutoCommit(). "+ "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);}}protected void resetAutoCommit() {try {if (!connection.getAutoCommit()) {// MyBatis does not call commit/rollback on a connection if just selects were performed.// Some databases start transactions with select statements// and they mandate a commit/rollback before closing the connection.// A workaround is setting the autocommit to true before closing the connection.// Sybase throws an exception here.if (log.isDebugEnabled()) {log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");}connection.setAutoCommit(true);}} catch (SQLException e) {if (log.isDebugEnabled()) {log.debug("Error resetting autocommit to true "+ "before closing the connection.  Cause: " + e);}}}protected void openConnection() throws SQLException {if (log.isDebugEnabled()) {log.debug("Opening JDBC Connection");}connection = dataSource.getConnection();if (level != null) {connection.setTransactionIsolation(level.getLevel());}setDesiredAutoCommit(autoCommit);}@Overridepublic Integer getTimeout() throws SQLException {return null;}}

JdbcTransaction主要维护了一个默认autoCommit为false的Connection对象,对事物的提交,回滚,关闭等都是接见通过Connection完成的。

1.3 获取执行器Executor

/*** 创建一个执行器* @param transaction 事务* @param executorType 数据库操作类型* @return 执行器*/public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor 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);}// 根据配置文件中settings节点cacheEnabled配置项确定是否启用缓存if (cacheEnabled) { // 如果配置启用缓存// 使用CachingExecutor装饰实际执行器executor = new CachingExecutor(executor);}// 为执行器增加拦截器(插件),以启用各个拦截器的功能executor = (Executor) interceptorChain.pluginAll(executor);return executor;}
  • 执行器的类型,我们来看看执行器的接口信息


Executor

public interface Executor {ResultHandler NO_RESULT_HANDLER = null;// 数据更新操作,其中数据的增加、删除、更新均可由该方法实现int update(MappedStatement ms, Object parameter) throws SQLException;// 数据查询操作,返回结果为列表形式<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;// 数据查询操作,返回结果为列表形式/*** 执行查询操作* @param ms 映射语句对象* @param parameter 参数对象* @param rowBounds 翻页限制* @param resultHandler 结果处理器* @param <E> 输出结果类型* @return 查询结果* @throws SQLException*/<E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;// 数据查询操作,返回结果为游标形式<E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;// 清理缓存List<BatchResult> flushStatements() throws SQLException;// 提交事务void commit(boolean required) throws SQLException;// 回滚事务void rollback(boolean required) throws SQLException;// 创建当前查询的缓存键值CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);// 本地缓存是否有指定值boolean isCached(MappedStatement ms, CacheKey key);// 清理本地缓存void clearLocalCache();// 懒加载void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);// 获取事务Transaction getTransaction();// 关闭执行器void close(boolean forceRollback);// 判断执行器是否关闭boolean isClosed();// 设置执行器包装void setExecutorWrapper(Executor executor);}

executor包含了Configuration和刚刚创建的Transaction,默认的执行器为SimpleExecutor,如果开启了二级缓存(默认开启),则CachingExecutor会包装SimpleExecutor,然后依次调用拦截器的plugin方法返回一个被代理过的Executor对象,记住这个地方,后面Sql语句具体的执行是交给执行器来进行处理的。

1.4 构建DefaultSqlSession

 return new DefaultSqlSession(configuration, executor, autoCommit);
public class DefaultSqlSession implements SqlSession {// 配置信息private final Configuration configuration;// 执行器private final Executor executor;// 是否自动提交private final boolean autoCommit;// 缓存是否已经被污染private boolean dirty;// 游标列表private List<Cursor<?>> cursorList;public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {this.configuration = configuration;this.executor = executor;this.dirty = false;this.autoCommit = autoCommit;}}


SqlSession的所有查询接口最后都归结位Exector的方法调用。后面文章我们来分析其调用流程。

Mybatis源码分析(五)SqlSession的创建相关推荐

  1. mybatis源码分析3 - sqlSession的创建

    1 引言和主要类 初始化mybatis,也就是创建完单例SqlSessionFactory后,就进入到了mybatis的运行阶段.mybatis每次的运行都是通过SqlSession对象来进行,它是运 ...

  2. mybatis源码分析4 - sqlSession读写数据库完全解析

    1 引言和主要类 创建完sqlSession实例后,我们就可以进行数据库操作了.比如通过selectOne()方法查询数据库,如代码 // 读取XML配置文件 String resource = &q ...

  3. MyBatis 源码分析之 SqlSession 创建

    三哥 内容来自[自学星球] 欢迎大家来了解我的星球,和星主(也就是我)一起学习 Java ,深入 Java 体系中的所有技术.我给自己定的时间是一年,无论结果如何,必定能给星球中的各位带来点东西. 想 ...

  4. mybatis源码分析2 - SqlSessionFactory的创建

    1 主要类 初始化mybatis的过程,其实就是创建SqlSessionFactory单例的过程.下面是一个简单的初始化例子. String resource = "main/resourc ...

  5. Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法

    Mybatis 源码探究 (3)创建 SqlSessionFactory对象 时隔许久,终于又能接着来搞他啦.Mybatis 一起来探究吧. 先笑会再进入主题吧 开始啦 一.new SqlSessio ...

  6. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  7. 源码通透-mybatis源码分析以及整合spring过程

    源码通透-mybatis源码分析以及整合spring过程 mybatis源码分析版本:mybaits3 (3.5.0-SNAPSHOT) mybatis源码下载地址:https://github.co ...

  8. MyBatis源码分析(一)MyBatis整体架构分析

    文章目录 系列文章索引 一.为什么要用MyBatis 1.原始JDBC的痛点 2.Hibernate 和 JPA 3.MyBatis的特点 4.MyBatis整体架构 5.MyBatis主要组件及其相 ...

  9. 十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了

    十年老架构师神级推荐,MyBatis源码分析,再也不用为源码担忧了 前言 MyBatis是一个优秀的持久层ORM框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注SQL 本身,而不需要花 ...

  10. mybatis源码分析之事务管理器

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇:mybatis源码分析之Configuration 主要分析了构建SqlSessionFactory的过程中配置文件的 ...

最新文章

  1. PostgreSQL 优化器代码概览
  2. latex sr 中一些对齐和表格问题及总结
  3. SQL 语句使用关键字错误
  4. ospaf-开源项目成熟度分析工具
  5. 计算机主板时钟,主板时钟电路工作原理
  6. P3760-[TJOI2017]异或和【树状数组】
  7. CF617E XOR and Favorite Number
  8. Spring Data JPA 从入门到精通~@NamedQueries预定义查询
  9. Ubuntu16 python2.7升级python3.5
  10. Android调用系统照相机
  11. 应用安全的重要性!再怎么强调都不过分的5大理由
  12. linux 0.01内核分析与操作系统设计 百度网盘,《Linux 0.01内核分析与操作系统设计——创造你自己的操作系统》...
  13. pli测试50题题库_面试人员情商测试50题1
  14. 树链剖分 - 月下“毛景树”(BZOJ 4151)
  15. 棋盘dp 牛牛的DRB迷宫I
  16. webpack 打包时排除某些依赖模块
  17. 自定义view,仿微信、支付宝密码输入控件的源码实现
  18. websocket+cdn架构部署
  19. 电脑主要硬件解读与选购建议
  20. opencv android 透视,OpenCV图像几何变换之透视变换

热门文章

  1. 免费天气API,天气JSON API,不限次数获取十五天的天气预报
  2. 如何重装计算机操作系统,老电脑怎么重装操作系统
  3. 阿里云ECS遭挖矿程序攻击解决方法(彻底清除挖矿程序,顺便下载了挖矿程序的脚本)
  4. 2022全新米酷影视V7.0.3网站源码+带插口分析
  5. XuperChain立体网络创世徽章·合成款全新亮相,超多惊喜等你来!
  6. elementui 表格中单元格自定义功能
  7. 英语中常见100个句型
  8. 【python数据分析实战】电商打折套路解析(1)—— 各个品牌都有多少商品参加了双十一活动?
  9. 小学计算机实验考查总结,芷江县大树坳乡小学:小学科学实验操作考查圆满完成...
  10. 如何利用计算机上好小学科学课,轻点电脑就能完成科学实验?这所小学将虚拟实验课搬进课堂...