mybatis查询mysql结果的null和N/A引起的异常问题排查

背景:

        今天线上环境突发意外情况,昨天还好好的页面,突然少了两个模块,经检查发现查询结果是正常结果,但是返回数据格式却与预想的不一致,返回结果

{
    "success": true,
    "code": 200,
    "msg": null,
    "data": [
        null
    ]
}

预想中的查询结果为空时,data字段应该是一个空的数据,但是返回结果中却出现了一个空对象,数据连接层使用mybatis框架,所以怀疑mybatis做了一些转换,就转换了一下sql查询方式发现同样的sql查询不同的字段值时返回的格式会有区别,在navicat中执行sql发现查询结果还是有区别的。

返回null对象的sql为:

 SELECT SUM(media.read_count) as `count`,media.*,temp.*,channel.*
        FROM tableName media
        ORDER BY `count` desc

在Navicat执行结果为:

SELECT * FROM tableName media temp.maxDay=media.`day` ;

查询结果为:

仔细看一下会发现,查询结果仍是有区别的

  • NULL是指某个字段没有值
  • N/A是指结果集为空,是没有数据输出的。

所以当查询结果为NULL时,经过mybatis转换后便是一个null对象,返回N/A时,表示没有结果,返回的结果就是一个空的数组。

仔细观察两个sql会发现,使用聚合函数sum时返回结果就是null,查询结果为单独列时,就会返回N/A。

延伸拓展:

N/A是指结果集为空,是没有数据输出的;

NULL是指某个字段没有值;

空值一般指空字符串。

null和空值的区别:

相同点:

        null和空值都代表有数据输出。

不同点:

1、内存区别
        空值(‘’)的长度是0,是不占用空间的;
        而的NULL长度是NULL,其实它是占用空间的。

2、查询的区别
        查询null:使用函数isnull,注意isnull有不同形式
        查询空值:则使用=’ ',两个引号中间是没有空格的

3、统计的区别
        count(字段),若该字段在某一行的值为NULL,则该行不会被统计;
        若该字段在某一行的值为空值,该行会被统计
        count( * ):NULL会被统计。

### MyBatis 更新操作返回 `null` 的原因及解决方案 #### 一、可能的原因分析 当执行 MyBatis 更新操作时,如果返回值为 `null` 或者不符合预期的结果数,通常有以下几个常见原因: - **SQL语句错误**:检查 SQL 语句是否有语法错误或逻辑问题。确保使用的表名、列名正确无误[^1]。 - **参数传递不当**:确认传入的参数是否匹配 Mapper 接口定义的方法签名以及 XML 中配置的内容。特别是对于批量更新的情况,注意集合类型的处理方式[^2]。 - **自动提交设置**:默认情况下,某些 JDBC 驱动程序可能会关闭事务的自动提交功能,在这种状态下即使成功修改了数据也不会立即反映到数据库中,从而导致看似失败的操作。可以通过调整连接池配置来开启此选项[^3]。 - **影响行数判断失误**:MyBatis 默认会通过受影响的记录数量作为方法调用后的返回结果。然而有时候开发者期望获取其他形式的信息反馈(比如自增 ID),这时就需要额外编写查询语句并将其封装成对象返回给业务层。 #### 二、具体的解决措施 针对上述提到的各种情况,可以采取如下策略解决问题: ##### 使用 `<update>` 标签内的 `useGeneratedKeys` 属性 为了能够捕获由数据库引擎生成的新键值(例如 MySQL 的 AUTO_INCREMENT 字段),可以在 `<update>` 节点上增加 `useGeneratedKeys=true` `keyProperty="id"` 参数指定哪个 Java Bean 成员变量用来接收新产生的主键值: ```xml <update id="updateUserById" parameterType="com.example.User" useGeneratedKeys="true" keyProperty="userId"> UPDATE users SET name=#{name} WHERE userId=#{userId} </update> ``` ##### 设置合理的 `flushCache` 行为 适当利用缓存机制有助于提高性能表现,但在涉及写入型操作时应谨慎对待。为了避免脏读现象的发生,建议将 `flushCache` 设定为 true 来强制刷新二级缓存中的相关内容: ```xml <select id="selectUsersByName" resultType="com.example.User" flushCache="true"> SELECT * FROM users WHERE name LIKE CONCAT('%',#{userName},'%') </select> <!-- 对应的 Update 操作 --> <update id="deleteUserByIds" parameterType="java.util.List" flushCache="true"> DELETE FROM users WHERE userId IN <foreach item="uid" collection="list" open="(" separator="," close=")"> #{uid} </foreach> </update> ``` ##### 处理 NULL 值的问题 在实际开发过程中经常会遇到需要向数据库插入或更新含有NULL值得字段的情形。此时应当特别留意不同版本间可能存在差异的行为特性,并作出相应适配。以 MyBatis Plus为例,可通过重载 `setSql()` 方法来自定义如何表达SET子句部分;而对于普通版,则可在Mapper文件里显式声明那些允许为空的数据项及其对应的JDBC类型[^1]: ```sql -- mapper.xml 文件片段 -- <if test="createdTime != null"> , created_time = #{createdTime,jdbcType=TIMESTAMP} </if> ``` 另外值得注意的是,部分场景下还需考虑时间戳格式化等问题,确保前后端传输的一致性. #### 结论 综上所述,面对 MyBatis 更新操作返回 `null` 这样的异常状况时,应该从多个角度出发进行全面排查,包括但不限于 SQL 文本准确性验证、输入参数校验、环境配置审查等方面的工作。同时也要善于借助日志工具辅助定位潜在缺陷所在位置,最终实现高效稳定的持久层交互体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值