在我的代码库中,我们有一个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
答案 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());
}
....
}