Mybatis是如何生成自增主键的id给对象呢
- 前天遇到了一个问题,需求场景是这样的:系统中有两张表:一张车辆主表和车辆设备信息表,设备信息表中关联车辆主表的主键ID。系统做了一个EXCEL批量导入车辆及设备信息的功能,在测试服务器上测试没有问题,但是上正式环境后,发生了一个奇怪的现象:车辆信息和设备信息对应不上了,有窜行现象(比如第一台车辆对应第二个车辆设备)。于是开始艰难的查找问题之路。
- 首先想到可能的问题是不是他们上传时,excel的格式不对?于是乎找了一份正式的文件,看了一下,文件确实存在问题。告知他们修改文件的格式及表头。本以为这是小问题,已经解决。下午又给反馈,还是不行。。(what!?一定是你们操作方式不对!)。于是亲自上正式环境导入一次,艹!果然不对。。啪啪打脸。。
- 于是再次分析想,难道是导入excel之后,数据插入之前的处理有问题?漏掉了了某一条数据?于是打出日志,对比excel解析后的数据和入库之前的数据,发现还是匹配的上的,并没有什么问题!这tm心态就崩了呀。。这什么情况!??于是绞尽脑汁接着想。。那查查数据库吧。
- 由于登录正式环境,需要用跳板机,老不方便,查看数据库还需要使用命令行,所以一般不愿意查询数据库。没办法,只能查看一下数据了。通过sql一查询,完蛋,主键id是不连续的,每个id中间都隔了1。通过命令show variables like '%auto_increment_increment%'查看发现,主键自增步长为2,于是把这个变量设置成1,问题解决。问题原因似乎找到了:插入数据库,使用的是mybatis批量插入。第一步插入车辆信息,插入成功后,主键id返回到车辆实体类中,然后将车辆的id,赋值给设备信息实体类的车辆id字段,然后再批量插入设备信息。伪代码:
carDao.batchInsert(saveCars);//批量保存车辆
for (int i = 0; i <saveCars.size() ; i++) {
CarInfo car= saveCars.get(i);
DeviceInfo deviceInfo= saveDevices.get(i);
deviceInfo.setCarId(car.getId());
}
deviceDao.batchInsert(saveDevices);//批量保存设备
批量插入用的mybatis。例如插入10台车辆信息,返回的id是1,2,3…10,然后将车辆id赋值给设备,应该是没问题的。可是问题就出在这里:由于数据库设置的自增步长是2,导致数据库中的id是不连续的,实际数据库中车辆id是1,3,5,7。。。19。但是,mybatis拿到的却是连续的id,也就是1,2,3,4…10.然后赋值给设备。
数据库中设备信息记录的车辆id是一一对应的,正常查询第二行车辆id为2的设备(此时id连续),应该是查到设备b
实际情况数据库记录:
此时,列表列出的车辆信息是5台,现在要查询第二行车辆,也就是id为3的车辆的设备信息(此时id已经不连续)。结果查询到的设备,是设备表第三行的设备,也就是设备c,此时发生了窜行,数据对不上了。
5. 那么问题来了,为什么mybatis插入数据成功后,拿到的id为什么和数据库中实际的id不一致呢?于是想到了看一下,看一下id是如何赋值的。经过多轮debug,终于找到赋值的地方,大致的调用过程:
1.processBatch(MappedStatement ms, Statement stmt, Object parameter)
-->2. assignKeys(configuration, rs, rsmd, keyProperties, parameter);
-->3.assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
-->4.assignerList.forEach(x -> x.assign(rs, param));
--》 5.Object value = typeHandler.getResult(rs, columnPosition);
metaParam.setValue(propertyName, value);
在第5步时候,调用的是--》 int result = rs.getInt(columnIndex);
也就是从结果集中获取id.
去处理赋值
从结果集中获取id,然后通过反射赋值。
6. 看到最后,按照我的理解,插入成功后,是从结果集中获取主键id,然后反射赋值给对象。可是,我的疑问依然没解决:讲道理结果集中的id应该就是数据库中的id,对象中的主键,应该和数据库中的id一致,可是为什么数据库中如果自增长步长是2,数据库中记录的主键是1,3,5,7…,而mybatis中赋值给对象的,确实1,2,3,4呢。。
求哪位大佬指教。。抱拳!