带你学习Mybatis之SqlSession

SqlSession是mybatis的核心接口,SqlSessionFactory负责创建SqlSession对象,包含多个openSession()方法的重载。 在SqlSession中定义了常用的数据库操作以及事务操作,接口定义如下

SqlSession

public interface SqlSession extends Closeable {
 // 参数为sql语句,返回查询的结果对象
  <T> selectOne(String statement);
 // 第二个参数为实参对象
  <T> selectOne(String statement, Object parameter);

  <E> List<E> selectList(String statement);

  <E> List<E> selectList(String statement, Object parameter);
 // 第三个参数为查询结果集的范围
  <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

  <K, V> Map<K, V> selectMap(String statement, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

  <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
 
 //返回值是游标对象
  <T> Cursor<T> selectCursor(String statement);

  <T> Cursor<T> selectCursor(String statement, Object parameter);

  <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);

 // 查询结果对象将由此指定的ResultHandler对象处理
  void select(String statement, Object parameter, ResultHandler handler);

  void select(String statement, ResultHandler handler);

  void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

  int insert(String statement);

  int insert(String statement, Object parameter);

  int update(String statement);

  int update(String statement, Object parameter);

  int delete(String statement);

  int delete(String statement, Object parameter);
 // 提交事务
  void commit();

  void commit(boolean force);
 // 回滚事务
  void rollback();

  void rollback(boolean force);

 // 将请求刷新到数据库
  List<BatchResult> flushStatements();

 // 关闭当前session
  @Override
  void close();

 // 清空缓存
  void clearCache();

 // 获取Configuration对象
  Configuration getConfiguration();

 // 获取type对应的Mapper对象
  <T> getMapper(Class<T> type);

 // 获取该SqlSession对应的数据库连接
  Connection getConnection();
}

MyBatis为SqlSession提供了默认实现,DefaultSqlSession类

 // Configuration配置对象
  private final Configuration configuration;
   // 底层依赖的Executor对象
  private final Executor executor;
 // 是否自动提交事务
  private final boolean autoCommit;
   // 当前缓存中是否存在脏数据
  private boolean dirty;
   // 防止用户忘记关闭已打开的游标,cursorList收集由该SqlSession对象生成的游标对象,在DefaultSqlSession.close()方法统一关闭
  private List<Cursor<?>> cursorList;

所有的数据库相关操作全部封装到了Executor接口实现中,DefaultSqlSession类中查询方法的调用关系如下图

方法调用关系 查询最终都是调用Executor.query(MappedStatement, Object, RowBounds, ResultHandler)方法实现数据库查询操作的。

对返回对象进行调整

  • selectOne()方法从结果集中获取第一个元素返回
  • selectMap()方法将List集合转为Map集合返回
  • select()方法将结果对象集合交由用户指定的ResultHandler对象处理,且没有返回值
  • selectList()方法直接将集合返回

DefaultSqlSession中的insert()、update()、delete()方法最后通过调用DefaultSqlSession.update(String,Object)方法,从而调用Executor.update(MappedStatement, Object)方法完成数据库的修改操作。

DefaultSqlSessionFactory

DefaultSqlSessionFactory实现了SqlSessionFactory接口,提供了两种创建DefaultSqlSession的方式

方式一

通过数据源获取数据库连接,并创建Executor对象以及DefaultSqlSession对象

// ExecutorType是一个枚举
// SIMPLE, 为每个语句的执行创建一个新的预处理语句
// REUSE, 复用预处理语句
// BATCH 批量执行所有更新语句
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      // 获取mybatis-config.xml的配置中的Environment对象
      final Environment environment = configuration.getEnvironment();
      // 获取TransactionFactory
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      // 创建Transaction
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      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();
    }
  }
方式二

用户提供数据库连接,根据数据库连接创建Executor对象以及DefaultSqlSession对象

private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
    try {
      boolean autoCommit;
      try {
        autoCommit = connection.getAutoCommit();
      } catch (SQLException e) {
        // Failover to true, as most poor drivers
        // or databases won't support transactions
        autoCommit = true;
      }
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      final Transaction tx = transactionFactory.newTransaction(connection);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }
SqlSessionManager

SqlSessionManager同时实现了SqlSessionFactory和SqlSession接口,也提供了SqlSessionFactory创建SqlSession对象以及SqlSession操作数据库的功能。

private final SqlSessionFactory sqlSessionFactory;
// localSqlSession中记录的sqlSession对象的代理对象,SqlSessionManager初始化时会使用JDK动态代理的方式创建
private final SqlSession sqlSessionProxy;
// 记录当前一个与当前线程绑定的SqlSession对象
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal();

SqlSessionManager与DefaultSqlSessionFactory主要不同点是SqlSessionManager提供了两种模式:第一种模式和DefaultSqlSessionFactory的行为相同,同一个线程每次通过SqlSessionManager对象访问数据库时,都会创建新的DefaultSession对象完成数据库操作

第二种模式是SqlSessionManager通过localSqlSession这个ThreadLocal变量,记录当前线程绑定的SqlSession对象,供当前线程循环使用,从而避免在同一个线程多次创建SqlSession对象带来的性能损失

// 通过构造函数可以看出,sqlSessionProxy是代理类,会执行SqlSessionManager.SqlSessionInterceptor中的方法
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionManager.SqlSessionInterceptor());
}
private class SqlSessionInterceptor implements InvocationHandler {
    public SqlSessionInterceptor() {
        // Prevent Synthetic Access
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      // 会使用第二种模式
      if (sqlSession != null) {
        try {
          return method.invoke(sqlSession, args);
        } catch (Throwable t) {
          throw ExceptionUtil.unwrapThrowable(t);
        }
      } else {// 第一种模式
        try (SqlSession autoSqlSession = openSession()) {
          try {
            final Object result = method.invoke(autoSqlSession, args);
            autoSqlSession.commit();
            return result;
          } catch (Throwable t) {
            autoSqlSession.rollback();
            throw ExceptionUtil.unwrapThrowable(t);
          }
        }
      }
    }
  }
四大对象

sqlSession真正的执行时通过Executor、StatementHandler、ParameterHandler、ResultSetHandler来完成数据库操作和结果返回

  • Executor 执行器 通过执行器来调度StatementHandler、ParameterHandler和ResultHandler等来执行对应的sql
  • StatementHandler 使用数据库的Statement/PreparedStatement执行操作
  • ParameterHandler 用于sql对参数的处理
  • ResultSetHandler 进行结果集ResultSet的封装和返回

https://zhhll.icu/2020/框架/mybatis/组件分析/2.mybatis之SqlSession/

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/698207.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Axios网络请求

网页&#xff1a;Axios中文文档 | Axios中文网Axios 是一个基于 promise 的网络请求库&#xff0c;可以用于浏览器和 node.jshttps://www.axios-http.cn/ 安装命令npm install axios 上一节创建的项目终端安装&#xff0c;安装完成 生命周期函数 App.vue在上述位置加入代码 …

【区块链】深入解析Proof of Work (PoW): 区块链技术的核心驱动力

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 深入解析 Proof of Work (PoW): 区块链技术的核心驱动力引言一、PoW基本概念1.1…

【linux网络(二)】网络基础之套接字编程

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux网络 1. 前言2. 端口号详…

微服务之熔断器

1、高并发带来的问题 在微服务架构中&#xff0c;我们将业务拆分成一个个的服务&#xff0c;服务与服务之间可以相互调用&#xff0c;但是由于网络原因 或者自身的原因&#xff0c;服务并不能保证服务的100%可用&#xff0c;如果单个服务出现问题&#xff0c;调用这个服务就会…

iPhone - 为什么姓名和付款都变成灰色?

问题描述 为什么姓名和付款都变成灰色&#xff1f;点开订阅也显示图 2 的无法连接&#xff1f; 原因分析 联网 WIFI 没有对『设置』开放权限。 解决方案 设置 - 无线局域网 - 使用无线局域网与蜂窝网络的App - 找到『设置』应用 - 勾选『无线局域网与蜂窝数据』

kafka集成spark

1.新建Scala项目 具体教程可见在idea中创建Scala项目教程-CSDN博客 1.1右键项目名-添加框架支持-勾选scala 1.2main目录下新建scala目录-右键Scala目录-将目录标记为-勾选源代码根目录 1.3创建包com.ljr.spark 1.4引入依赖&#xff08;pox.xml) <dependencies><…

3D Web轻量化引擎HOOPS Communicator核心功能特点及应用优势

随着3D技术的发展&#xff0c;越来越多的行业开始在其应用中集成三维模型和可视化技术。特别是在工程、建筑和制造业&#xff0c;3D模型不仅用于设计和展示&#xff0c;还用于分析和优化。然而&#xff0c;传统的3D渲染引擎往往需要高性能的硬件支持&#xff0c;难以在网络环境…

探索GPT-4V在学术领域的应用——无需编程即可阅读和理解科学论文

1. 概述 论文地址&#xff1a;https://arxiv.org/pdf/2312.05468.pdf 随着人工智能潜力的不断扩大&#xff0c;人工智能&#xff08;AI&#xff09;在化学领域的应用也在迅速发展。特别是大规模语言模型的出现&#xff0c;极大地扩展了人工智能在化学研究中的作用。由于这些模…

Vue 路由:一级路由,嵌套路由

1、安装路由插件,因为用的是vue2 所以路由版本要和vue2对应上&#xff0c;所有有3 yarn add vue-router3 2、在main.js里引入 import VueRouter from vue-router Vue.use(VueRouter) 3、新建文件夹 router,创建index.js 4、引入路由插件&#xff0c;并且暴露出来这个路由 5、在…

一文入门vim

先来波快问快答。 第一个问题&#xff0c;vim是什么&#xff1f; vim就是一文本编辑器。 第二个问题&#xff0c;我们为什么要使用vim&#xff1f; 好像在终端中可选择使用的文本编辑器也不多&#xff08;其他有&#xff0c;但是相对而言vim用的比较广泛&#xff09; 第三…

PNAS | 工作记忆中大脑节律的因果功能图

摘要 工作记忆是一个涉及大脑中多个功能解剖节点的关键认知过程。尽管有大量与工作记忆结构相关的神经影像学证据&#xff0c;但我们对控制整体表现的关键中枢的理解并不完整。因果解释需要在对特定功能解剖节点进行安全、暂时和可控的神经调节后进行认知测试。随着经颅交流电…

适用于 macOS 的最佳免费数据恢复软件

升级到 macOS 后&#xff0c;它可以帮助您从 HDD、SSD、存储卡、USB 闪存驱动器、数码相机或其他存储介质设备中完全恢复已删除、格式化或无法访问的数据。 当 macOS Monterey 用户寻找数据恢复解决方案时&#xff0c;免费数据恢复软件始终是一个不错的选择。实际上&#xff0…

通过引用得到变量的值

编写程序&#xff1a; 运行结果&#xff1a; 程序分析&#xff1a; a的值开始为10,b是a的引用&#xff0c;它的值当然也应该是10&#xff0c;当a的值变为100(a*a的值&#xff09;时&#xff0c;b的值也随之变为100。在输出a和b的值后&#xff0c;b的值变为20&#xff0c;显然a的…

30 张Java 的思维导图,全面梳理构建 Java 的知识体系分享

小编这几天在网上收集了 30 张大佬制作的 Java 知识点总结的思维导图&#xff0c;整理成了这篇文章分享给大家&#xff0c;帮助大家梳理构建 Java 的知识体系。 这份思维导图包含从Java的简介、主要特性、发展历史到语法、数据类型、修饰符、运算符、类、数组、框架、面向对象…

Faster-RCNN基本思想和网络结构

简单来说&#xff0c;Faster RCNN RPN Fast RCNN RPN 是指 Region Proposal Network&#xff0c;建议区域生成网络。 Faster RCNN 中用 RPN 来代替了 Fast RCNN 中的SS算法。 算法流程&#xff1a; &#xff08;1&#xff09;将图像输入CNN网络得到相应的特征图。 &#x…

如何评估pcdn调度算法的优化效果(壹)

评估PCDN&#xff08;Peer-assisted Content Delivery Network&#xff0c;对等网络内容分发网络&#xff09;调度算法的优化效果是一个综合且系统的过程&#xff0c;涉及多个维度的考量。以下是一些建议的步骤和考量因素&#xff0c;以便全面评估优化效果&#xff1a; 一&…

WT32-ETH01作为TCP Server进行通讯

目录 模块简介WT32-ETH01作为TCP Server设置W5500作为TCP Client设置连接并进行通讯总结 模块简介 WT32-ETH01网关主要功能特点: 采用双核Xtensa⑧32-bit LX6 MCU.集成SPI flash 32Mbit\ SRAM 520KB 支持TCP Server. TCP Client, UDP Server. UDP Client工作模式 支持串口、wi…

探索乡村振兴新模式:发挥科技创新在乡村振兴中的引领作用,构建智慧农业体系,助力美丽乡村建设

随着科技的不断进步&#xff0c;乡村振兴工作正迎来前所未有的发展机遇。科技创新作为推动社会发展的重要力量&#xff0c;在乡村振兴中发挥着越来越重要的引领作用。本文旨在探讨如何发挥科技创新在乡村振兴中的引领作用&#xff0c;通过构建智慧农业体系&#xff0c;助力美丽…

【MySQL】(基础篇六) —— 过滤数据

过滤数据 本文将讲授如何使用SELECT语句的WHERE子句指定搜索条件。 WHERE子句 数据库表一般包含大量的数据&#xff0c;很少需要检索表中所有行。通常只会根据特定操作或需要提取表数据的子集。只检索所需数据需要指定搜索条件&#xff08;search criteria&#xff09;&…

IIR和FIR两种滤波器有什么区别?

概念的区分 IIR&#xff08;Infinite Impulse Response&#xff0c;无限脉冲响应&#xff09;和FIR&#xff08;Finite Impulse Response&#xff0c;有限脉冲响应&#xff09;滤波器是两种常见的数字信号处理滤波器类型&#xff0c;它们在结构、性能和用途上有显著区别&#…