当前位置:   article > 正文

Mybatis中selectKey源码分析

selectkey标签源码

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

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

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

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

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

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

KeyGenerator接口

  1. /**
  2. * key生成器接口
  3. */
  4. public interface KeyGenerator {
  5. //在执行主SQL前执行selectKey
  6. void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
  7. //在主SQL执行后执行selectkey
  8. void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);
  9. }

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

  如何解析@SelectKey

before具体执行时机  

  1. protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  2. this.configuration = mappedStatement.getConfiguration();
  3. this.executor = executor;
  4. this.mappedStatement = mappedStatement;
  5. this.rowBounds = rowBounds;
  6. this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
  7. this.objectFactory = configuration.getObjectFactory();
  8. if (boundSql == null) { // issue #435, get the key before calculating the statement
  9. // //执行before
  10. generateKeys(parameterObject);
  11. boundSql = mappedStatement.getBoundSql(parameterObject);
  12. }
  13. this.boundSql = boundSql;
  14. this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
  15. this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
  16. }
  1. protected void generateKeys(Object parameter) {
  2. KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
  3. ErrorContext.instance().store();
  4. keyGenerator.processBefore(executor, mappedStatement, null, parameter);
  5. ErrorContext.instance().recall();
  6. }
  1. @Override
  2. public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
  3. //是否执行前执行,如果不是就不执行
  4. if (executeBefore) {
  5. processGeneratedKeys(executor, ms, parameter);
  6. }
  7. }

  after执行时机

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

 具体执行源码

  1. private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
  2. try {
  3. //如果parameter不为null同时keyStatement不为null且keyStatement 指定了keyProperties
  4. if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
  5. //获取keyProperties
  6. String[] keyProperties = keyStatement.getKeyProperties();
  7. //获取配置信息
  8. final Configuration configuration = ms.getConfiguration();
  9. //获取参数对象元数据
  10. final MetaObject metaParam = configuration.newMetaObject(parameter);
  11. //其实已经判断过了
  12. if (keyProperties != null) {
  13. //新建keyExecutor
  14. Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
  15. //执行查询
  16. List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
  17. //如果查询结果为0个则抛出异常
  18. if (values.size() == 0) {
  19. throw new ExecutorException("SelectKey returned no data.");
  20. } else if (values.size() > 1) {//查询的结果个数多余1个则抛出异常
  21. throw new ExecutorException("SelectKey returned more than one value.");
  22. } else {//只返了一个结果值
  23. MetaObject metaResult = configuration.newMetaObject(values.get(0));
  24. //如果keyProperty个数只有1
  25. if (keyProperties.length == 1) {
  26. //如果查询结果对象存在这个属性的getter方法
  27. if (metaResult.hasGetter(keyProperties[0])) {
  28. //将属性值设置到param中
  29. setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
  30. } else {
  31. //如果没有getter方法就将当前值设置到属性中
  32. setValue(metaParam, keyProperties[0], values.get(0));
  33. }
  34. } else {//处理指定多个key属性场景
  35. handleMultipleProperties(keyProperties, metaParam, metaResult);
  36. }
  37. }
  38. }
  39. }
  40. } catch (ExecutorException e) {
  41. throw e;
  42. } catch (Exception e) {
  43. throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
  44. }
  45. }
  46. private void handleMultipleProperties(String[] keyProperties,
  47. MetaObject metaParam, MetaObject metaResult) {
  48. //获取所有key column
  49. String[] keyColumns = keyStatement.getKeyColumns();
  50. //如果key column不存在
  51. if (keyColumns == null || keyColumns.length == 0) {
  52. //没有指定key column则直接使用配置到 key property
  53. for (String keyProperty : keyProperties) {
  54. setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
  55. }
  56. } else {
  57. //存在key column 但是数量不一致
  58. if (keyColumns.length != keyProperties.length) {
  59. throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
  60. }
  61. //数量一致,要求keyColumn 和keyProperty一一对应
  62. for (int i = 0; i < keyProperties.length; i++) {
  63. setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
  64. }
  65. }
  66. }
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号