问题
有一个分页查询用户的接口,本来已经通过测试并且上线运行了。突然在测试环境报BUG,每一页有不同程度的数据重复,例如,第一页有张三,第三页又出现张三了。
主要的代码如下:
PageMethod.startPage(query.getCurrPage(), query.getPageSize());
List<User> users = userMapper.pages(query);
return new PageInfo<>(users);
第一反应是,可能 MyBatis-Plus
出问题了,或者是使用错误了。
MyBatis-Plus 官方文档推荐的方式,和出问题的代码一致(版本不同)
//第二种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectIf(1);
那么问题只可能出现在SQL
上
分析SQL
表结构如下:
CREATE TABLE `gov_contract_customer_relation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`no` varchar(50) NOT NULL COMMENT '编号',
`name` varchar(50) NOT NULL COMMENT '姓名',
`age` int DEFAULT NULL COMMENT '年龄',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `no_UNI_IDX` (`no`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
出现问题的分页SQL
如下:
SELECT
*
FROM t_user
WHERE age > 20
ORDER BY create_time DESC
LIMIT 0, 10;
问题表现为 LIMIT 0, 10
和 LIMIT 0, 50
的结果中,前10条数据不一致。
有 ORDER BY
子句,测试期间没有写操作,不同的分页容量,按以往经验前10条数据应该一致。那么问题可能是 create_time
的值造成的。
查询所有的 create_time
发现,所有的值全部一样。因为是测试环境,测试同学批量导入数据,所以 create_time
值都一样。
原因
如果没有 ORDER BY
子句,MySQL 不保证以任何特定顺序返回。我们可能会观察到类似默认排序的可重复结果,但 MySQL 没有对此做出保证,所以这是不可靠的。
当 ORDER BY
子句用于排序的值全部相同时,会造成和没有 ORDER BY
子句一样的结果。
解决方案
SELECT
*
FROM t_user
WHERE age > 20
ORDER BY create_time DESC, no ASC
limit 0, 10;
增加排序字段,避免无法排序字段值全部相同。最好使用有唯一约束的字段作为排序依据。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。