MyBatis源码简读——2.3 1 SqlSession

本文深入剖析MyBatis的SQL执行流程,从SqlSession的创建到SQL的执行,包括参数处理、结果集处理等关键步骤。介绍了SqlSessionFactory、SqlSession、Executor、StatementHandler等核心组件的作用及其实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#执行流程

SQL执行的流程如下图

graph TD
A[SqlSession] --> B[Executor]
B --> C[StatementHandler]
C --> D[ParameterHandler]
D --> E[Statement]
E --> F[数据库]
F --> G[ResultSet]
G --> H[ResultSetHandler]
H --> C
C --> B
B --> A

比较难受优快云的md竟然不能画流程图

在这里插入图片描述

根据上图可以看出来,整个流程涉及的模块大概有

  • SqlSession:sql会话
  • Executor:执行器
  • StatementHandler:Statement 处理器
  • ParameterHandler:参数处理器
  • ResultSet:结果集
  • ResultSetHandler:结果处理器

不过ParameterHandler参数处理器在进行SQL初始化的时候我们已经知道了,其主要逻辑是获取请求参数,对SQL中的?占位符进行替换处理。所以关于SQL执行我们主要学习的是:

  • SqlSession
  • Executor
  • StatementHandler
  • ResultSet和ResultSetHandler

SqlSessionFactory

我们先看SqlSession的工厂方法

/**
 * Creates an {@link SqlSession} out of a connection or a DataSource
 * 数据会话工厂接口
 * @author Clinton Begin
 */
public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);

  SqlSession openSession(Connection connection);

  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);

  SqlSession openSession(ExecutorType execType, boolean autoCommit);

  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

DefaultSqlSessionFactory是其主要的实现类,当然还有一个SqlSessionManager这个下面说
其核心的方法主要有两个

  // 从数据源中获得会话
  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);
      // 返回要给默认的SQL会话
      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();
    }
  }

  // 从连接中获得会话
  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;
      }
      // 和openSessionFromDataSource 类似
      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();
    }
  }

代码不算太难,主要逻辑差异不大,无非是一个从数据源中获得事务,一个是从连接中获得事务,然后创建一个默认的SqlSession

SqlSession

我们再看SqlSession

接口代码

/**
 * The primary Java interface for working with MyBatis.
 * Through this interface you can execute commands, get mappers and manage transactions.
 * 数据会话
 * @author Clinton Begin
 */
public interface SqlSession extends Closeable {

  <T> T selectOne(String statement);

  <T> 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);

  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();

  void close();

  void clearCache();

  Configuration getConfiguration();

  <T> T getMapper(Class<T> type);

  Connection getConnection();
}

从上面方法的名称和继承关系我们可以大致了解几点:

  • 接口继承了Closeable,提供了某些资源关闭的功能
  • 主要方法涉及各种数据库操作的请求
  • 提供的获得各种资源(系统配置,SQL的Mapper)
  • 提供的获得连接和关闭连接功能
  • 提供了事务的部分功能
  • 提供了缓存操作功能

其主要实现类

  • DefaultSqlSession
  • SqlSessionManager

DefaultSqlSession

简单的介绍下里面的方法

@Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
        // 获得mapped的selectList对象,然后执行查询
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

几乎所有的查询逻辑最后都会调用到这个方法。
整个逻辑就是从配置中获得statement对应的MappedStatement对象,然后通过执行器执行操作,然后将结果封装成符合要求的对象集合。
可以看下update、delete其实内部逻辑大同小异,不算太复杂。

SqlSessionManager

SqlSessionManager实现了SqlSessionFactory和SqlSession接口,但是这两个接口的内部逻辑实现,其实都是其内部的两个代理类来实现的

public class SqlSessionManager implements SqlSessionFactory, SqlSession {

  private final SqlSessionFactory sqlSessionFactory;
  private final SqlSession sqlSessionProxy;
    // 线程变量,显示当前线程的sql会话
  private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
  
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
    // 创建代理对象
    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[]{SqlSession.class},
        new SqlSessionInterceptor());
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值