原生Mybatis执行过程

 

本来不想写这个的,但是太容易忘记了,好不容易看了很久的源码才了解了一点,忘记可惜了。

Configuration:
    a、 MyBatis所有的配置信息都保存在Configuration对象之中,配置文件中的大部分配置都会存储到该类中
    b、可以理解为所有mybatis文件的集合

DefaultSqlSessionFactory
        在SqlSessionFactoryBuilder对象主要是为了获取SqlSessionFactory对象,在创建对象的过程来配置Configuration对象配置的实例的类就是DefaultSqlSessionFactory
        DefaultSqlSessionFactory可以理解为工厂配置类
        
SqlSession:
    作为MyBatis工作的主要顶层API,表示和数据库交互时的会话,完成必要数据库增删改查功能
    从中获取会话的连接

Executor:
               MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
    sql的执行器

StatementHandler:
    封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数等

ParameterHandler:
    负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
    主要负责类型的转换
    这个用户可以自己定制

ResultSetHandler:
    负责将JDBC返回的ResultSet结果集对象转换成List类型的集合

TypeHandler
    负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换

MappedStatement
    MappedStatement维护一条<select|update|delete|insert>节点的封装
    mapper文件中的一个id对应一个该对象

SqlSource
    负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回

BoundSql
    表示动态生成的SQL语句以及相应的参数信息

MappedStatement  
        XML文件中的某个方法
        
StatementHandler
        负责处理Mybatis与JDBC之间Statement的交互
        
        
RoutingStatementHandler
        类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用
        SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。
        
Statement 对象用于将 SQL 语句发送到数据库中

 SqlSessionFactory sessionFactory = null;
        String resource = "mybatis.xml";
        sessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource));
        SqlSession sqlSession = sessionFactory.openSession();
        InitClass initClass =  (InitClass) sqlSession.selectOne("com.example.demo.UserMapper.selectId");
        System.out.println(initClass.getId());

我们已上面这段代码作为示例来进行说明

SqlSessionFactoryBuilder对象的作用就是用来生成SqlSessionFactory的。

Resources对象用来读取文件在项目中的路径,将之传入build方法中的会进入下面的步骤

 public SqlSessionFactory build(Reader reader) {
     // 主要引用下面的方法
    return build(reader, null, null);
  }


public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
        // XMLConfigBuilder 对象就是用来解析之前传入的xml文件的属性举例几个属性
        //typeAliases设置别名 mappers 映射执行sql的xml文件
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
        //parse()解析mybtis方法中configuration标签的下面的所有属性封装到Configuration对象
        //build方法将解析完成的Configuration对象传入得到DefaultSqlSessionFactory类
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }


public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }


  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

在通过build方法得到SqlSessionFactory对象后,后面肯定就是得到SqlSession类了继续执行openSession()

通过opSession方法真正执行的方法是openSessionFromDataSource()方法

// ExecutorType类 默认是simple类型 
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        // configuration为xml的配置类,getEnvironment方法可以得到数据库连接属性
      final Environment environment = configuration.getEnvironment();
       //得到事务工厂
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
       //得到事务类型 其中getConnection方法是得到数据库连接
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        //然后就是进入Executor 数据库的访问主要就是它来实现的(执行sql,返回对象,都是在这里完成)
      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();
    }
  }

Exector:

Executor分成两大类,一类是CacheExecutor,另一类是普通BaseExecutor

CacheExecutor:加入的缓存功能这里就不多介绍了这里主要介绍BaseExecutor

newExecutor方法会是根据传入ExectorType类型选择一个Exector的实现类来完成SQL的执行方式

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;
  }

BaseExecutor中又分为一下类型

ExecutorType.SIMPLE: 这个执行器类型不做特殊的事情。它为每个语句的执行创建一个新的预处理语句。

ExecutorType.REUSE: 这个执行器类型会复用预处理语句。
ExecutorType.BATCH: 这个执行器会批量执行所有更新语句,如果 SELECT 在它们中间执行还会标定它们是 必须的,来保证一个简单并易于理解的行为。

这个类型是根据mybatis.xml中配置的没有配置的话默认SIMPLE

根据默认类型我们进入SimpleExecutor方法中

@Override
  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:封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数,预编译语句,和基础的增删改查等
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }


 

通过newStatementHandler方法来获得一个StatenenHandler对象

   //RoutingStatementHandler类似路由器,在其构造函数中会根据Mapper文件中设置的StatementType来选择使用SimpleStatementHandler、PreparedStatementHandler和CallableStatementHandler,
其实现的接口StatementHandler的方法也是由这三个具体实现类来实现。

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
       // RoutingStatementHandler会根据类型选择具体的实现类来执行sql 
       
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

通过MappedStatement储存的Statementype参数来确定具体执行SQL的处理者

 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    //默认是PreparedStatementHandler
    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());
    }

  }

在得到StatementHandler对象后 执行prepareStatement方法获取一个Statemen对象

private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection, transaction.getTimeout());
    //设置SQL的参数
    handler.parameterize(stmt);
    return stmt;
  }
protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }

这里就用到了Transaction中的获取数据库连接

 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;
    } catch (SQLException e) {
      closeStatement(statement);
      throw e;
    } catch (Exception e) {
      closeStatement(statement);
      throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
    }
  }

这里执行的就是具体在StatemenHandler中预编译方法的实现

 protected Statement instantiateStatement(Connection connection) throws SQLException {
    String sql = boundSql.getSql();
    if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
      String[] keyColumnNames = mappedStatement.getKeyColumns();
      if (keyColumnNames == null) {
        return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
      } else {
        return connection.prepareStatement(sql, keyColumnNames);
      }
    } else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
      return connection.prepareStatement(sql);
    } else {
      return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
    }
  }

最终指向的是默认PreparedStatementHandler对象中的方法来执行预编译语句返回一个Statemen对象

最后执行的handler.update(stmt)

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

指向就是PreparedStatementHandler类中的实现方法

 

接下来就是真正执行SQL的方法前面只是预编译语句

InitClass initClass =  (InitClass) sqlSession.selectOne("com.example.demo.UserMapper.selectId");

@Override
  public <T> T selectOne(String statement, Object parameter) {
    // Popular vote was to return null on 0 results and throw exception on too many.
    List<T> list = this.selectList(statement, parameter);
    if (list.size() == 1) {
      return list.get(0);
    } else if (list.size() > 1) {
      throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
    } else {
      return null;
    }
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

 @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      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();
    }
  }

找到executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);

接下来具体执行交给executor来执行,具体流程上面已经讲过了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值