解决mybatis查询Map接收值为null不存key的问题

探讨MyBatis查询结果中Map接收值为null时的处理方式,介绍callSettersOnNulls配置项的作用及Gson序列化空值的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天跟大家讨论下mybatis查询Map接收值为null不存key的问题

问题出现的前提条件:将数据从DB中查询出来时将查出来的字段映射为Map,而不是封装成Bean.

我们看下mybatis查询使用map接收时遇到的问题:

xml文件:

SELECT 
			a.apply_id AS "applyId",
			a.ali_pid AS "aliPid",
			a.ali_account AS "aliAccount",
			a.agreement_resource_ids AS "agreementResourceIds",
			a.status AS "status",
			a.error_field AS "errorField",
			ac.company_name AS "companyName",
			u.name AS "userName",
			DATE_FORMAT(a.create_date,'%Y-%m-%d') AS "createDate",
			sa1.name AS "provinceName",
			sa2.name AS "cityName",
			sa3.name AS "regionName",
			ac.address AS "address",
			acbac.status AS "aliStatus",
			acbl.reason_desc AS "reasonDesc",
			aac.memo AS "memo"

返回结果:

applyId=174, address=测试, cityName=北京市, aliPid=2088123123123213, aliAccount=123123123123, companyName=企业20181212, regionName=东城区, provinceName=北京, userName=张三, aliStatus=3, status=2, createDate=2018-12-28

根据返回结果看到,并没有memo字段,原因是该字段在DB中的值为null,所以说map接收数据库中为null的值不会存在对应的键值。

出现这种情况的原因:

maibatis在默认情况下,对Map的解析生成如果value为null的话,那么key不会被加入到map中,所以map接收结果时就没有value为null的键值。

解决方法:在mybatis配置文件中设置callSettersOnNulls设置为true,该属性默认为false。

callSetterOnNulls:指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。

<!-- 全局参数 -->
	<settings>
        <!-- 设置当结果集中为null,调用setter(map 为put)方法 -->
        <setting name="callSettersOnNulls" value="true"/>
	</settings>

加上该配置的返回结果:

memo=null, address=测试, aliPid=2088123123123213, companyName=测试企业20181212, regionName=东城区, userName=张三, applyId=174, errorField=null, cityName=北京市, aliAccount=123123123123, provinceName=北京, agreementResourceIds=null, aliStatus=3, reasonDesc=null, status=2, createDate=2018-12-28

在应用层查询的map已经有这个键值了,解决了结果集为null但是没用存键值的问题。

在解决该问题过程中,看到网上有说如果只查询一个字段,并且结果为null用map接收时,结果为空map。

就此我进行了测试:

xml文件:

SELECT  a.memo AS "memo" from a

结果:

{memo=null}

经此实验这种说法是不正确的,接收到一个所有key值都为null 的map 而不是一个为null的map;

但是我带到页面上的结果还是没有memo这个字段,(一直以为是这个配置没有起作用,只顾着看前端接收到的返回值,没有关注后端的结果。自己要蠢死了)

 

最后找到了问题,因为我应用层使用了Gson序列化

return GsonUtil.getGson().toJson(map);

Gson默认当属性的值设为空时不会被序列化,如果强制序列化null值,我们可以使用GsonBuilder来序列化提供null值;

new GsonBuilder().serializeNulls().create().toJson(result);可以将null值也序列化。

 前端页面接收返回结果:

 

 

如果跟大家理解有出入,欢迎提出一起讨论。。。。。 

### MyBatis 返回 Map 类型结果集时跳过 Null 字段MyBatis 中,默认情况下,当查询返回 `Map` 类型的结果集时,即使某些字段为 `null`,这些字段仍然会作为键存在于 `Map` 中。然而,可以通过自定义方式实现忽略 `null` 的功能。 #### 方法一:通过拦截器实现过滤功能 可以编写一个 MyBatis 插件来拦截查询结果并移除为 `null` 的字段。以下是具体实现: ```java @Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class SkipNullFieldInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object result = invocation.proceed(); if (result instanceof List<?>) { ((List<Map<String, Object>>) result).forEach(map -> map.entrySet().removeIf(entry -> entry.getValue() == null)); } return result; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) {} } ``` 上述代码中,插件会在每次执行查询操作后检查返回是否为列表形式,并逐一处理其中的每个 `Map` 对象,删除所有为 `null` 的条目[^1]。 #### 方法二:手动设置 Mapper 查询方法 另一种更简单的方式是在业务层对返回的数据进行二次加工。例如,在 DAO 或 Service 层调用完成后立即清理掉不需要的字段: ```java private static Map<String, Object> removeNullFields(Map<String, Object> originalMap) { return originalMap.entrySet() .stream() .filter(entry -> entry.getValue() != null) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } // 调用示例 Map<String, Object> resultMap = mapper.queryForMap(param); resultMap = removeNullFields(resultMap); ``` 这种方法虽然有效,但在性能上可能不如全局性的拦截器方案高效[^2]。 #### 方法三:调整 SQL 输出结构 还可以考虑修改 SQL 语句本身,使其仅选择那些非空列。这通常适用于固定模式下的查询场景,但对于动态表单或者复杂联结查询来说不够灵活。 --- ### 总结 以上三种策略各有优劣: - **拦截器法**适合统一管理需求; - **手写工具函数**便于快速部署到现有项目中而无需额外依赖; - **SQL优化路径**则侧重于减少不必要的数据传输量。 最终的选择取决于实际应用场景以及团队的技术偏好。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yangerkong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值