源代码
<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 类型。具体分析如下:
问题原因
-
NULL 值处理问题:
-
当
map中的值为null时,MyBatis 无法自动推断 JDBC 类型(错误信息:Error setting null for parameter) -
批量更新时(2条数据),只要有一条记录包含 NULL 值就会触发此错误
-
-
批量更新差异:
-
单条数据能成功是因为:可能该条数据的所有字段值都非 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 触发了类型推断错误。
完整修正方案(推荐)

关键点:
-
确保
separator=","(内层循环用逗号分隔) -
所有
#{value}必须指定jdbcType -
动态字段
${key}需防范 SQL 注入(确保来源可信)
实际开发中,建议创建字段类型映射表,根据
${key}动态设置对应的jdbcType。