你知道MyBatis insert插入数据的返回值是多少吗?是受影响的行数?或是其他值。返回值为-2147482646
你知道是什么情况嘛?接下来来看一个测试用例
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(is);
sqlSession = factory.openSession(ExecutorType.BATCH, true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> params = new HashMap<>();
// Mapper中的SQL是insert into user (username,age) select username,age from user where id between ${start} and ${end}
params.put("start", 1);
params.put("end", 10);
Integer count = mapper.insertBatchUser(params);
System.out.println("受影响的行数:"+count);
日志打印结果
查询的SQL为
insert into user (username,age) select username,age from user where id between 1 and 10
一般地插入数据后返回值应该是受影响的行数。比如我插入5条数据,如果插入成功应该返回5。但是mybatis却给我返回了-2147482646
,真是离谱!
原因
原因竟是SqlSession的ExecutorType导致的!当我把sqlSession = factory.openSession(ExecutorType.BATCH, true); 中的ExecutorType换成BATCH
换成SIMPLE
或是REUSE
后插入数据的返回值就正常了,返回值就是受影响的行数而不是-2147482646
为什么会这样的?那就需要了解下MyBatis中的三种ExecutorType了
- SIMPLE 对应SimpleExecutor简单执行器,平时我们默认就是用的它
- BATCH 对应BatchExecutor批量执行器,底层是JDBC的Connection的executeBatch方法
- RESUE 对应ResueExecutor重用执行器,重用Statement对象
mybatis执行插入SQL的时候会调用Executor的update方法(增删改最终都属于更新数据,所以调用的是update方法)查询数据库,Executor是一个接口,默认使用的SimpleExecutor这个实现类。而前述代码在创建SqlSession时指定的Executor的类型为Batch,那么mybatis插入数据库的时候就会调用BatchExecutor的doUpdate方法。我们来追踪一下BatchExecutor的doUpdate方法的执行逻辑
看到没,只要是使用了BatchExecutor,无论怎么插入数据,最后的返回值是固定的,都是Integer.MIN_VALUE + 1002
即-2147482646
补充:SqlSession.insert的调用链路
下面是DefaultSqlSession的insert方法
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
它委托给DefaultSqlSession的update方法执行插入操作,下面是DefaultSqlSession的update方法
public int update(String statement, Object parameter) {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
}
可以看到SqlSession把update的任务委托给了Executor的update方法。而Executor的update方法默认是由抽象类BaseExecutor实现的。我们来看下BaseExecutor的update方法
public int update(MappedStatement ms, Object parameter) throws SQLException {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
可以看到它最终调用的doUpdate方法,这个doUpdate就是由不同类型的Executor的子类实现的。而BatchExecutor实现该方法的逻辑就是返回值固定为 -2147482646
public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
// 省略中间逻辑
return Integer.MIN_VALUE + 1002;
}