0

在我的代码库中,我们有一个 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 个步骤)?

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

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

谢谢,标清

4

1 回答 1

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

然后我对其进行调试,当它被调用时(源 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());
    }
    ....
  }
于 2016-07-26T15:50:27.227 回答