spring + mybatis + c3p0 整合(源码分析-mybati核心对象)

摘要

近期由于项目使用mybatis出现了数据源阻塞,导致应用程序假死,服务超时引发严重后果,故此下定决心重新梳理一下spring+mybatis+c3p0整合问题,主要分为:配置、源码(通过一次数据库操作分析)、myabatis缓存、问题总结

spring + mybatis + c3p0 整合(配置篇)
spring + mybatis + c3p0 整合(源码分析)

mybatis整体架构

mybatis整体架构分为三层:基础支持层、核心处理层、接口层

在这里插入图片描述

接口层

接口层是上层应用于mybatis交互的桥梁,核心是SqlSession接口,暴露了一系列正删改查API给应用程序;接口层接受到请求会调用核心处理层完成具体数据库操作

SqlSession接口实现使用了工厂方法模式,SqlSessionFactory负责创建SqlSession对象,包含了多个openSession方法的重载

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

}

核心处理层

核心处理层完成核心处理流程,包括mybatis初始化和数据库操作所涉及的全部流程;如参数映射、sql解析、sql执行、结果处理和映射;接下来主要分析这一层的相关对象。

基础支持层

如事务管理、数据源、缓存管理、反射模块、日志、解析器模块、类型转换、Binding模块、资源加载等;后面我们主要分析下缓存管理,其他的有兴趣的可自行学习

mybatis核心对象

  • Configuration 核心环境配置,配置文件映射关系等都会保存在这里,mybatis四大核心组件都是在configuration中创建。相关源码如下
  • Executor 一个 SqlSession 对应一个 Executor 对象,这个对象负责增删改查的具体操作。
  • ParameterHandler 参数处理器, 没有过多的类关联关系, 只有一个默认的实现类。
  • StatementHandler 是 mybatis 创建 Statement 的处理器, 会负责 Statement 的创建工作, 在 JDBC 中 Statement 执行 SQL 语句时主要分为两个主要对象Statement 和 PrepareStatement。
  • ResultSetHandler 结果处理器,与ParameterHandler 类似只有一个默认实现类。

附上一张核心对象的调用关系
在这里插入图片描述

configuration创建4大核心对象源码

上篇有提过Configuration对象是SqlSessionFactoryBean.buildSqlSessionFactory()方法创建的,若未配置mybatis-config.xml默认new一个Configuration对象;若指定了配置文件configLocation会通过XMLConfigBuilder解析配置文件设置相关熟悉创建Configuration对象

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler;
  }

  public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
      ResultHandler resultHandler, BoundSql boundSql) {
    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
    return resultSetHandler;
  }

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

  public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
  }

  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);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

Executor组件

在这里插入图片描述

这里用了模板设计模式和装饰器模式

  • BaseExecutor提供默认实现,并提供抽象方法由不同实现类负责实现不同功能
  • CachingExecutor实现缓存管理;优先从缓存查询,如果存在就返回;如果不存在就交由BaseExecutor的子实现类处理
  • SimpleExecuto默认使用的执行器, 每执行一次 update 或 select, 就开启一个 Statement 对象, 用完就直接关闭 Statement 对象
  • ReuseExecutor可重用的执行器, 可重用的对象为 Statement, 在执行器内部提供一个 Map 映射, 执行 SQL 作为 key, value 为 Statement
  • BatchExecutor 批量提交 SQL 的一个执行器, 用作批量提交;可解决foreach拼接sql过长问题

StatementHandler组件

在这里插入图片描述

看类图就明白,其设计与Executor类似;其作用是创建执行sql的Statement
JDBC中 Statement 执行 SQL 语句时主要分为两个主要对象:Statement 和 PrepareStatement

  • BaseStatementHandler提供模板代码,具体创建Statement类型通过抽象方法instantiateStatement(),不同子类做不同实现
  • SimpleStatementHandler,负责处理不带动态参数运行的 SQL,对应Statement
  • PreparedStatementHandler, 负责处理 SQL 中的占位符动态参数赋值操作,对应PrepareStatement ;能够避免sql注入问题
  • CallableStatementHandler,复制处理存储过程的SQL,对应CallableStatement
  • RoutingStatementHandler看名称就知道这是个路由对象,根据不同statementType 决定具体实现

BaseStatementHandler相关源码

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    this.rowBounds = rowBounds;

    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
    this.objectFactory = configuration.getObjectFactory();

    if (boundSql == null) { // issue #435, get the key before calculating the statement
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }

    this.boundSql = boundSql;

    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  }
  
public Statement prepare(Connection connection) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      statement = instantiateStatement(connection);
      setStatementTimeout(statement);
      setFetchSize(statement);
      return statement;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

RoutingStatementHandler部分源码

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    switch (ms.getStatementType()) {
      case STATEMENT:
        delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case PREPARED:
        delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      case CALLABLE:
        delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
        break;
      default:
        throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
    }

  }

ParameterHandler组件 参数处理器

主要作用于 PreparedStatemet 参数解析时使用;从上文BaseStatementHandler源码可知其在初始化StatementHandler组件时创建

public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps)
      throws SQLException;
}

ResultSetHandler 组件 结果处理器

同参数处理器类型,负责处理 Statement 返回的结果, 根据定义返回类型进行封装返回;从上文BaseStatementHandler源码可知其在初始化StatementHandler组件时创建

插件开发

上文Configuration源码可以看出,mybatis四大核心对象都支持插件化的,其使用的是责任链设计模式;有兴趣的可以自行研究探讨,这里不做详细分析了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值