关于mybatis查询返回List<String>结果为[null],size是1的原因分析

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

前言

在项目中偶然遇到一个问题,报空指针异常,经排查,是mybatis查询结果映射到List时映射为了[null]数组。这就导致CollectionUtils.isEmpty判断为false。

问题复现

首先,我们准备三张表,t_user、t_user_role 和t_role,结构如下:

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT '' COMMENT '姓名',
  `account` varchar(50) DEFAULT '' COMMENT '账号',
  `password` varchar(100) DEFAULT '' COMMENT '密码',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='用户表';
复制代码
CREATE TABLE `t_user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11),
  `role_id` int(11),
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;
复制代码
CREATE TABLE `t_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT '',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='角色表';
复制代码

数据:

t_user表:

image.png

t_role表:

image.png

t_user_role表:

image.png

使用关联查询

select ur.role_id from t_user u inner join t_user_role ur on u.id=ur.user_id
复制代码

查询的结果为:

image.png

然后使用mybatis映射结果,发现接口返回的list为null元素的list,并不为空。

image.png

image.png

我们可以看到,打印出来的为[null],说明mapper接口返回的list不为空,元素为null。

出现上述问题的原因猜想

sql中select语句筛选的其实是一个对象,当一个对象的所有元素为空时,这条查询sql才会认为是没有查询到数据,映射到mybatis中,就为空对象。也就是没有查询到结果。但是当查询的sql只取一列数据并且这一列数据为null,但实际上这条sql查询的对象并不是所有的列全部为null,这时,映射到mybatis结果集后,就会认为查询到数据了,结果集映射这一列的值为null,所以返回了list的size为1,元素为null。

我们可以证实一下我们的猜想,将sql查询出所有的字段:

image.png 这样我们就容易理解了,这条sql查询的其实是有数据的,只不过在mybatis映射role_id字段时,role_id为null,导致映射为了list。

原因分析

出现上述问题的原因,其实是业务逻辑新增中间关系表的时候逻辑不严谨,在role_id为空时,不应该插入t_user_role数据。我们将t_user_role中的数据删除掉。在验证一下。

image.png 这样,结果返回与我们预期返回的结果一致。问题解决!

猜你喜欢

转载自juejin.im/post/7102308838681870343