zoukankan      html  css  js  c++  java
  • Mybatis源码分析-StatementHandler

    承接前文Mybatis源码分析-BaseExecutor,本文则对通过StatementHandler接口完成数据库的CRUD操作作简单的分析

    StatementHandler#接口列表

      //获取Statement对象,供操作数据库
      Statement prepare(Connection connection)
          throws SQLException;
    
      //参数配置
      void parameterize(Statement statement)
          throws SQLException;
    
      //批处理
      void batch(Statement statement)
          throws SQLException;
    
      //更新操作
      int update(Statement statement)
          throws SQLException;
    
      //查询操作
      <E> List<E> query(Statement statement, ResultHandler resultHandler)
          throws SQLException;
    
      //获取绑定的sql信息,包含sql语句
      BoundSql getBoundSql();
      
      //获取参数处理类,处理参数的映射等
      ParameterHandler getParameterHandler();
    

    RoutingStatementHandler-代理委托类

    其基本是间接类,只是根据statementType类型创建不同的StatementHandler类,达到适配的效果。此处我们只需要观察它的构造函数

      public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    	//根据mappedStatement中的statementType类型来进行委托类的创建
    	//默认都是PrepareStatementHandler
        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());
        }
    
      }
    

    mybatis在某语句不指定statementType属性的情况下,默认创建PrepareStatementHandler

    BaseStatementHandler-基本抽象实现类

    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;
    	//java类型处理类
        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        this.objectFactory = configuration.getObjectFactory();
    	//此处兼容doUpdate()方法的调用,因为传过来的boundSql为null
        if (boundSql == null) { // issue #435, get the key before calculating the statement
          generateKeys(parameterObject);
          boundSql = mappedStatement.getBoundSql(parameterObject);
        }
    
        this.boundSql = boundSql;
    	//paramterMap/resultType属性对应的入参集合处理
        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
        //resultMap/resultType属性对应的出参集合处理
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
      }
    

    BaseStatementHandler#prepare()-创建sql表达式对象statement

    具体源码如下

      public Statement prepare(Connection connection) throws SQLException {
        ErrorContext.instance().sql(boundSql.getSql());
        Statement statement = null;
        try {
    	  //创建表达式对象,供子类复写
          statement = instantiateStatement(connection);
          //设置执行sql的超时时间
          setStatementTimeout(statement);
          //通过mappedStatement对象设置statement的fetchSize大小
          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);
        }
      }
    

    此处我们只需要关注子类对instantiateStatement()方法的复写,其余的是设置执行sql超时时间、设置statement的fetchSize大小

    我们以mybatis默认的PrepareStatementHandler为例

    PrepareStatementHandler-预表达式帮助类

    PrepareStatementHandler#instantiateStatement()-创建Statement对象

    创建的对象为PrepareStatement,具体源码如下

      protected Statement instantiateStatement(Connection connection) throws SQLException {
        //获取待执行的sql语句
        String sql = boundSql.getSql();
        //主键列设置,一般此处针对insert语句
        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);
          }
        }//ResultSet返回类型,默认为空 
        else if (mappedStatement.getResultSetType() != null) {
          return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
        } else {
          return connection.prepareStatement(sql);
        }
      }
    

    PrepareStatementHandler#update()-CUD操作入口

    源码奉上

      public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute();
        //对增删改都会返回执行成功的记录数目
        int rows = ps.getUpdateCount();
        //针对key进行处理
        Object parameterObject = boundSql.getParameterObject();
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
        return rows;
      }
    

    PrepareStatementHandler#query()-R操作入口

    源码奉上

      public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute();
        //对select语句返回的resultMap/resultType进行相应的映射
        return resultSetHandler.<E> handleResultSets(ps);
      }
    

    小结

    • mybatis对jdbc调用数据库的方式进行了封装,实质都是调用Statement对象来执行sql语句,掌握纯jdbc访问数据库是最基本的

    • MappedStatement对象包含的内容很多,用于数据库访问的有statementType、keyGenerator、resultSetType等属性,具体的读者可自行查阅XMLStatementBuilder#parseStatementNode()源码

  • 相关阅读:
    java内部类
    unityUI拖拽
    Java泛型
    java集合
    python爬取糗百段子
    python读取文件并保存到mysql数据库
    BeanShell Sampler 身份证号-jmeter
    python操作数据库
    创建身份证号
    随机生成四要素
  • 原文地址:https://www.cnblogs.com/question-sky/p/7366345.html
Copyright © 2011-2022 走看看