当前位置: 首页 > news >正文

gbase8s之MyBatis批量update问题

源代码

<update id="updateDynamicTableData"><foreach collection="mapList" item="map" separator=";">UPDATE ${tableName} SET<foreach collection="map" item="value" index="key" separator=",">${key}=#{value}  <!-- 注意:${key}需防注入 --></foreach>WHERE ARCHIVAL_CODE = #{map.ARCHIVAL_CODE}</foreach>
</update>

报错:

从错误信息和代码来看,问题出在 处理 NULL 值时 MyBatis 无法确定 JDBC 类型。具体分析如下:

问题原因

  1. NULL 值处理问题

    • 当 map 中的值为 null 时,MyBatis 无法自动推断 JDBC 类型(错误信息:Error setting null for parameter

    • 批量更新时(2条数据),只要有一条记录包含 NULL 值就会触发此错误

  2. 批量更新差异

    • 单条数据能成功是因为:可能该条数据的所有字段值都非 NULL

    • 两条数据失败是因为:第二条数据包含 NULL 值字段

解决方案

方法 1:指定 NULL 值的 JDBC 类型(推荐)

修改动态 SQL,为每个参数添加 jdbcType 配置:

<update id="updateDynamicTableData"><foreach collection="mapList" item="map" separator=";">UPDATE ${tableName} SET<foreach collection="map" item="value" index="key" separator=",">${key}=#{value, jdbcType=VARCHAR}  <!-- 添加jdbcType --></foreach>WHERE ARCHIVAL_CODE = #{map.ARCHIVAL_CODE}</foreach>
</update>

说明

  • jdbcType=VARCHAR 是示例,实际需根据字段类型选择:

    • 数字字段:jdbcType=NUMERIC

    • 日期字段:jdbcType=TIMESTAMP

    • 通用类型:jdbcType=OTHER

方法 2:全局配置 NULL 值处理

在 MyBatis 配置文件中添加:

<settings><!-- 指定 NULL 值的默认 JDBC 类型 --><setting name="jdbcTypeForNull" value="NULL"/>
</settings>

这会为所有 NULL 值统一设置 jdbcType=NULL

方法 3:接口参数指定类型

修改 DAO 接口,明确字段类型:

void updateDynamicTableData(@Param("mapList") List<Map<String, Object>> mapList,@Param("tableName") String tableName
);
#虽然不能直接解决,但可配合其他方案使用。

为什么单条成功、多条失败?

  • 单条数据:可能所有字段值恰好都非 NULL,无需处理类型推断

  • 多条数据:只要有一条记录包含 NULL 值字段,MyBatis 就需要处理类型映射,此时:

// 示例数据
List<Map> mapList = Arrays.asList({ "NAME": "张三", "AGE": 25 },             // 无NULL{ "NAME": null, "ADDRESS": "北京" }       // 包含NULL
);

第二条的 NAME=null 触发了类型推断错误。

完整修正方案(推荐)

关键点

  1. 确保 separator=","(内层循环用逗号分隔)

  2. 所有 #{value} 必须指定 jdbcType

  3. 动态字段 ${key} 需防范 SQL 注入(确保来源可信)

实际开发中,建议创建字段类型映射表,根据 ${key} 动态设置对应的 jdbcType

相关文章:

  • WPF--Application.Current.Dispatcher.BeginInvoke
  • 人工智能之数学基础:如何将二次型转换为标准型?
  • QMainWindow、QDialog 和 QWidget区别
  • 一文读懂:晶振不同等级的差异及对应最佳应用场景
  • leetcode 2616. 最小化数对的最大差值 中等
  • 软考 系统架构设计师系列知识点之杂项集萃(88)
  • springboot+vue大文件断点续传
  • 前端JavaScript面试题(2)
  • Promise(async、await)
  • 非本地地址调用摄像头需要https
  • Coze扣子 - AI生成数字人口播视频
  • 多环境开发配置,Spring boot
  • 【leetcode】101. 对称二叉树
  • Mysql 忘记密码后如何修改
  • 长春光博会 | 麒麟信安:构建工业数字化安全基座,赋能智能制造转型升级
  • 零基础学前端-传统前端开发(第四期-JS基础-运算)
  • sqlserver存储过程中入参使用JSON
  • redis穿透、击穿、雪崩
  • linux alignment fault对齐造成设备挂死问题定位梳理
  • 代码训练LeetCode(34)文本左右对齐
  • 棠下网站建设/南京百度seo公司
  • 做地图的网站/网上营销培训课程
  • 网易短链接生成/优化seo招聘
  • 杭州做卖房子的工作哪个网站好/优化什么建立生育支持政策体系
  • 网站建设如何财务处理/seo包括哪些方面
  • 教育网站建设供应商/爱站网长尾关键词挖掘查询工具