gbase8s之MyBatis批量update问题

发布于:2025-06-15 ⋅ 阅读:(21) ⋅ 点赞:(0)

源代码

<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