zoukankan      html  css  js  c++  java
  • Mybatis中selectKey源码分析

      刚回答了一个问题这样一个问题,mybatis不能正常返回主键增加值  下面通过源码分析一下selectKey都具体实现;关于Mybatis 基于注解Mapper源码分析 可以看一下具体解析过程。

      如果向数据库中插入一条数据,同时有希望返回该条记录的主键,该怎么处理了?有两种情况:

    1. 数据库主键不是自增列,需要预先生成
    2. 是自增列,插入后才能知道

       这两种情况都可以通过SelectKey解决,第一个种就是before,第二张是after

    @Insert("insert into table2 (name) values(#{name})")
        @SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
        int insertTable2(Name name);
    

      在简单介绍了如何使用后,首先看一下KeyGenerator接口中都有那些方法

    KeyGenerator接口

      

    /**
     * key生成器接口
     */
    public interface KeyGenerator {
      //在执行主SQL前执行selectKey
      void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
    
      //在主SQL执行后执行selectkey
      void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
    
    }
    

      通过接口都源码可以发现在KeyGenerator接口中定义了 processBefore 和processAfter 两个方法,顾名思义就是在在执行SQL前执行和执行SQL后执行,那么下面通过时序图将其整体调用顺序进行一个概览

      如何解析@SelectKey

     

    before具体执行时机  

    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
    //  //执行before
          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);
      }
    

      

      protected void generateKeys(Object parameter) {
        KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
        ErrorContext.instance().store();
        keyGenerator.processBefore(executor, mappedStatement, null, parameter);
        ErrorContext.instance().recall();
      }
    

      

      @Override
      public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        //是否执行前执行,如果不是就不执行
        if (executeBefore) {
          processGeneratedKeys(executor, ms, parameter);
        }
      }
    

      after执行时机

    @Override
      public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
        //如果executeBefore配置为false则执行
        if (!executeBefore) {
          processGeneratedKeys(executor, ms, parameter);
        }
      }
    

      

     具体执行源码

     private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
        try {
          //如果parameter不为null同时keyStatement不为null且keyStatement 指定了keyProperties
          if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
            //获取keyProperties
            String[] keyProperties = keyStatement.getKeyProperties();
            //获取配置信息
            final Configuration configuration = ms.getConfiguration();
            //获取参数对象元数据
            final MetaObject metaParam = configuration.newMetaObject(parameter);
            //其实已经判断过了
            if (keyProperties != null) {
              //新建keyExecutor
              Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
              //执行查询
              List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
              //如果查询结果为0个则抛出异常
              if (values.size() == 0) {
                throw new ExecutorException("SelectKey returned no data.");            
              } else if (values.size() > 1) {//查询的结果个数多余1个则抛出异常
                throw new ExecutorException("SelectKey returned more than one value.");
              } else {//只返了一个结果值
                MetaObject metaResult = configuration.newMetaObject(values.get(0));
                //如果keyProperty个数只有1个
                if (keyProperties.length == 1) {
                  //如果查询结果对象存在这个属性的getter方法
                  if (metaResult.hasGetter(keyProperties[0])) {
                    //将属性值设置到param中
                    setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
                  } else {
                    //如果没有getter方法就将当前值设置到属性中
                    setValue(metaParam, keyProperties[0], values.get(0));
                  }
                } else {//处理指定多个key属性场景
                  handleMultipleProperties(keyProperties, metaParam, metaResult);
                }
              }
            }
          }
        } catch (ExecutorException e) {
          throw e;
        } catch (Exception e) {
          throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
        }
      }
    
      private void handleMultipleProperties(String[] keyProperties,
          MetaObject metaParam, MetaObject metaResult) {
        //获取所有key  column
        String[] keyColumns = keyStatement.getKeyColumns();
          //如果key column不存在
        if (keyColumns == null || keyColumns.length == 0) {
          //没有指定key column则直接使用配置到 key property
          for (String keyProperty : keyProperties) {
            setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
          }
        } else {
          //存在key column 但是数量不一致
          if (keyColumns.length != keyProperties.length) {
            throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
          }
          //数量一致,要求keyColumn 和keyProperty一一对应
          for (int i = 0; i < keyProperties.length; i++) {
            setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
          }
        }
      }
    

      

  • 相关阅读:
    长篇专访科比:成功没秘诀 只有不断努力
    生活哲理
    8个让程序员追悔莫及的职业建议
    优秀程序员必备十大习惯
    回顾马云屌丝岁月的惨状:多次被拒失声痛哭
    程序员,究竟该怎么赚钱?
    洛杉矶凌晨4点-------启航
    iOS越狱开发
    iOS越狱开发中遇到的坑
    macOS上搭建RabbitMQ+MQTT服务器
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8921507.html
Copyright © 2011-2022 走看看