MyBatis内部查询

时间:2016-01-11 20:08:18

标签: mybatis spring-mybatis

在我的代码库中,我们有一个MyBatis查询,如下所示,

INSERT INTO TABLE_A(
        ID,
        NAME,
        VERSION
    )
    VALUES  (
        #id#,
        #name#,
        (select NVL(max(version), 0 ) + 1 from SAE_PROC_SETTING where name = #name#)
    )

唯一约束是列名称和版本。如果多个用户同时插入值,有时我们会遇到唯一约束错误。当我们检查时,名称和版本是相同的,并按预期抛出错误。

我的问题是,MyBatis如何处理内部查询

(select NVL(max(version), 0 ) + 1 from TABLE_Awhere name = #name#)

此查询是否由MyBatis提交给Oracle,然后oracle首先执行SELECT然后执行INSERT查询或者MyBatis首先执行SELECT,然后替换INSERT中的值并在Oracle中提交INSERT查询(MyBatis的2个步骤) ?

如果它像第二个选项那样处理,当2个人在同一时间插入同名时,两者都有可能获得相同的版本。然后在尝试插入时,我们将得到UniqueConstraint错误。

请让我知道MyBatis如何在内部处理这个问题。任何指针都没问题。

谢谢, SD

1 个答案:

答案 0 :(得分:0)

MyBatis将完整语句(带内部选择的插入)发送到JDBC驱动程序,并且是执行此操作的数据库(在您的情况下为Oracle)(首先执行SELECT然后执行INSERT)。 MyBatis只是替换你的查询参数,然后通过prepareStatement传递查询。

日志将插入显示为一个语句。

2016-07-26 17:34:23.776 DEBUG 91036 --- [           main] sample.mybatis.mapper.CityMapper.insert  : ==>  Preparing: insert into city (name, state, country) values ((select DISTINCT 'a' from city), 'CA', 'US'); 
2016-07-26 17:34:23.777 DEBUG 91036 --- [           main] sample.mybatis.mapper.CityMapper.insert  : ==> Parameters: 
2016-07-26 17:34:23.779 DEBUG 91036 --- [           main] sample.mybatis.mapper.CityMapper.insert  : <==    Updates: 1

然后我调试它,当它被调用时,这个方法(source github)只是传递INSERT案例:

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {

      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
       .....
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
       ....
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    ....
  }