MyBatis 核心配置综述之StatementHandler(上)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: StatementHandler 是四大组件中最重要的一个对象,负责操作 Statement 对象与数据库进行交流,在工作时还会使用 ParameterHandler 和 ResultSetHandler 对参数进行映射,对结果进行实体类的绑定

MyBatis 四大组件之StatementHandler


我们在搭建原生JDBC的时候,会有这样一行代码

Statement stmt = conn.createStatement(); //也可以使用Prepared

这行代码创建的 Statement 对象或者是 PreparedStatement 对象就是由StatementHandler进行管理的。


StatementHandler 的基本构成


来看一下StatementHandler中的主要方法:

79.jpg

  • prepare: 用于创建一个具体的 Statement 对象的实现类或者是 Statement 对象
  • parametersize: 用于初始化 Statement 对象以及对sql的占位符进行赋值
  • update: 用于通知 Statement 对象将 insert、update、delete 操作推送到数据库
  • query: 用于通知 Statement 对象将 select 操作推送数据库并返回对应的查询结果


StatementHandler的继承结构

80.jpg


有没有感觉和  
Executor 的继承体系很相似呢?最顶级接口是四大组件对象,分别有两个实现类 BaseStatementHandler  和  RoutingStatementHandler ,BaseStatementHandler 有三个实现类, 他们分别是 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler。


RoutingStatementHandler: RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是对应Handler的三种实现类。在MyBatis工作时,使用的StatementHandler 接口对象实际上就是 RoutingStatementHandler 对象。我们可以理解为

StatementHandler statmentHandler = new RountingStatementHandler();
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  // 根据 statementType 创建对应的 Statement 对象
  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());
  }
}

BaseStatementHandler: 是 StatementHandler 接口的另一个实现类.本身是一个抽象类.用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类


  • SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句
  • PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句,
  • CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程


StatementHandler 对象创建以及源码分析


StatementHandler 对象是在 SqlSession 对象接收到命令操作时,由 Configuration 对象中的newStatementHandler 负责调用的,也就是说 Configuration 中的 newStatementHandler 是由执行器中的查询、更新(插入、更新、删除)方法来提供的,StatementHandler 其实就是由 Executor 负责管理和创建的。


SimpleExecutor.java

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      // 获取环境配置
      Configuration configuration = ms.getConfiguration();
      // 创建StatementHandler,解析SQL语句
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      // 由handler来对SQL语句执行解析工作
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

81.jpg

由图中可以看出,StatementHandler 默认创建一个 RoutingStatementHandler ,这也就是 StatementHandler 的默认实现,由 RoutingStatementHandler 负责根据 StatementType 创建对应的StatementHandler 来处理调用。


prepare方法调用流程分析


prepare 方法的调用过程是这样的,在上面的源码分析过程中,我们分析到了执行器 Executor 在执行SQL语句的时候会创建 StatementHandler 对象,进而经过一系列的 StatementHandler 类型的判断并初始化。再拿到StatementHandler 返回的 statementhandler 对象的时候,会调用其prepareStatement() 方法,下面就来一起看一下 preparedStatement() 方法(我们以简单执行器为例,因为创建其 StatementHandler 对象的流程和执行 preparedStatement() 方法的流程是差不多的):


SimpleExecutor.java

public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
  Statement stmt = null;
  try {
    // 获取环境配置
    Configuration configuration = ms.getConfiguration();
    // 创建StatementHandler,解析SQL语句
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    stmt = prepareStatement(handler, ms.getStatementLog());
    // 由handler来对SQL语句执行解析工作
    return handler.<E>query(stmt, resultHandler);
  } finally {
    closeStatement(stmt);
  }
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
  Statement stmt;
  Connection connection = getConnection(statementLog);
  stmt = handler.prepare(connection, transaction.getTimeout());
  handler.parameterize(stmt);
  return stmt;
}
// prepare方法调用到 StatementHandler 的实现类RoutingStatementHandler,再由RoutingStatementHandler调用BaseStatementHandler中的prepare 方法
// RoutingStatementHandler.java
@Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    return delegate.prepare(connection, transactionTimeout);
  }
//  BaseStatementHandler.java
 @Override
  public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
    ErrorContext.instance().sql(boundSql.getSql());
    Statement statement = null;
    try {
      statement = instantiateStatement(connection);
      setStatementTimeout(statement, transactionTimeout);
      setFetchSize(statement);
      return statement;
    } ...

其中最重要的方法就是  instantiateStatement() 方法了,在得到数据库连接 connection 的对象的时候,会去调用 instantiateStatement() 方法,instantiateStatement 方法位于 StatementHandler 中,是一个抽象方法由子类去实现,实际执行的是三种 StatementHandler 中的一种,我们还以 SimpleStatementHandler 为例

protected Statement instantiateStatement(Connection connection) throws SQLException {
    if (mappedStatement.getResultSetType() != null) {
      return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    } else {
      return connection.createStatement();
    }
  }

从上面代码我们可以看到,instantiateStatement() 最终返回的也是Statement对象,经过一系列的调用会把statement 对象返回到 SimpleExecutor 简单执行器中,为 parametersize 方法所用。也就是说,prepare 方法负责生成 Statement 实例对象,而 parameterize 方法用于处理 Statement 实例多对应的参数。

相关文章
|
4月前
|
SQL XML Java
mybatis复习01,简单配置让mybatis跑起来
文章介绍了MyBatis的基本概念、历史和特点,并详细指导了如何配置MyBatis环境,包括创建Maven项目、添加依赖、编写核心配置文件、创建数据表和实体类、编写Mapper接口和XML配置文件,以及如何编写工具类和测试用例。
mybatis复习01,简单配置让mybatis跑起来
|
5月前
|
安全 Java 数据库连接
后端框架的学习----mybatis框架(3、配置解析)
这篇文章详细介绍了MyBatis框架的核心配置文件解析,包括环境配置、属性配置、类型别名设置、映射器注册以及SqlSessionFactory和SqlSession的生命周期和作用域管理。
后端框架的学习----mybatis框架(3、配置解析)
|
4月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
75 1
|
5月前
|
缓存 Java 数据库连接
mybatis1.常见配置
本文介绍了MyBatis框架中的常见配置及其加载顺序。配置可通过`properties`元素、资源文件或方法参数传递,其中方法参数传递的属性具有最高优先级。文章列举了几个重要的配置项,如`cacheEnabled`用于全局开启或关闭缓存功能;`lazyLoadingEnabled`控制对象的延迟加载行为;`useGeneratedKeys`允许JDBC支持自动生成主键;`defaultExecutorType`设定默认执行器类型等。此外,还介绍了多环境配置方法,通过`environments`元素可定义不同环境下的数据库连接信息,并可根据需求动态选择加载特定环境
|
6月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
125 3
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
接口模板,文本常用的接口Controller层,常用的controller层模板,Mybatisplus的相关配置
|
Java 数据库连接 mybatis
MyBatis-Spring配置简单了解
在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在 MyBatis-spring 中,则使用 SqlSessionFactoryBean 来替代。
889 0
|
3月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
164 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
3月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
92 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块