概述

MyBatis 会将查询结果保存在 HashMap 中,所以,如果查询出来的结果集中包含相同的记录,最后一个记录将会覆盖前面所以的记录,到最后只剩下一条记录。

背景

最近做到一个项目,其中需要统计程序评判的所有结果。其中测试数据有多个,如果所有的测试数据都失败了,那么结果将会一样。

查询数据库

未使用 id 之前的 mapper.xml 代码,

<resultMap type="**.pojo.JudgeResult2" id="JudgeResultMap">
    <result column="runtime" property="runtime" jdbcType="INTEGER" />
    <result column="memory" property="memory" jdbcType="INTEGER" />
    <result column="message" property="message" jdbcType="VARCHAR" />
</resultMap>

首先贴出数据库中的记录

psid rtid runtime memory
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0
140  7    0       0

上述十条记录完全重复若使用上述的 resultMap,查询到的结果将是

{
  "type": {
    "id": 7,
    "name": "结果错误"
  },
  "runtime": 0,
  "memory": 0,
  "message": null
}

查看查询日志信息发现,确实查询到了 10 条记录,但是最后的记过仍旧只有一条记录。百思不得其解。

最后发现一个规律,就是重复的记录都会变成一条记录,于是就想到了跟踪 MyBatis 的源码,发现其采用 HashMap 保存结果集,导致记录被覆盖。

解决方案

resultMap 中必须保证有一个 id,只要能表示记录的唯一性即可。即使冗余也是值得的

<resultMap type="**.pojo.JudgeResult2" id="JudgeResultMap">
    <id column="sdid" property="sdid" jdbcType="INTEGER" />
    <result column="runtime" property="runtime" jdbcType="INTEGER" />
    <result column="memory" property="memory" jdbcType="INTEGER" />
    <result column="message" property="message" jdbcType="VARCHAR" />
</resultMap>