Mybaits 使用过程中mapper.xml foreach List<String[]>的时候报错

nested exception is org.apache.ibatis.binding.BindingException: Parameter 'rangeItem' not found. Available parameters are [md, column, page, param3, param4, param1, param2, order]

错误代码如下:

XML 复制代码
 <if test="md.rangeList != null and md.rangeList.size() > 0">
      <foreach collection="md.rangeList" item="rangeItem" separator="OR"> 
          a.meter_number BETWEEN #{rangeItem[0]} AND #{rangeItem[1]}
     </foreach>
</if>

第一种改法容易被sql注入谨慎使用,将#{}改为${}

核心区别

一、${} 和 #{} 的核心区别

特性 ${} (字符串替换 / 直接拼接) #{} (预编译参数占位符)
底层实现 直接将参数拼接到 SQL 语句中(字符串替换) 基于 JDBC PreparedStatement 的 ? 占位符
参数处理 不做类型转换,原样拼接(需手动处理引号) 自动做类型转换,自动添加引号(如字符串)
SQL 注入风险 高(直接拼接,无过滤) 低(预编译,参数与 SQL 分离)
适用场景 动态表名、列名、排序字段、分表分库等动态语法 普通参数(where 条件、插入值、更新值等)
语法限制 可拼接任意 SQL 片段,无类型限制 仅能替换 "参数值",不能替换 SQL 关键字 / 标识符

二、为什么用 #{} 会报错?

#{} 的核心是替换 "参数值",而非 "SQL 语法 / 标识符",如果用在不支持占位符的场景,就会触发报错,常见原因如下:

1. 替换 SQL 标识符(表名 / 列名 / 排序字段)

JDBC 的 PreparedStatement 占位符(?仅支持替换 "值" ,不支持替换表名、列名、ORDER BY 后的字段等 "标识符"。如果强行用 #{} 替换这些内容,会导致 SQL 语法错误

2. 替换 SQL 关键字(如 ORDER BY 的 ASC/DESC)

同理,排序方向(ASC/DESC)是 SQL 关键字,不能用 #{} 替换

3. 参数类型不匹配(少见,但易忽略)

#{} 会自动做类型转换,如果参数类型与数据库字段类型不兼容,也可能报错:

  • 例如:Java 传 Boolean.TRUE,但数据库字段是 VARCHAR#{} 会转换为 1(MySQL),若字段不支持数字,会报类型错误;
  • 解决:确保参数类型与数据库字段匹配,或手动转换。
4. 特殊 SQL 语法(如 IN 子句)

如果直接用 #{} 传递数组 / 集合到 IN 子句,会报错(因为 #{} 会将数组解析为单个值)

三、总结:如何选择?

场景 推荐用法 注意事项
普通参数(where 条件、插入值) #{} 安全,避免 SQL 注入
动态表名 / 列名 / 排序字段 / 关键字 ${} 1. 仅用于可信参数;2. 手动过滤防注入
IN 子句(数组 / 集合) <foreach> + #{} 不要直接用 #{}${} 拼接数组

四. 修改方案

XML 复制代码
<if test="md.rangeList != null and md.rangeList.size() > 0">
     <foreach collection="md.rangeList" item="rangeItem" separator="OR" open="(" close=")">
        a.meter_number BETWEEN ${rangeItem[0]} AND ${rangeItem[1]}
    </foreach>
</if>

第二种方法就是将列表(List,Set,Map)里面的数组封装为对象去调用

java 复制代码
package org.jeecg.modules.meter.vo;

import lombok.Data;

@Data
public class MeterRangeVo {

    /**
     * 开始表身号
     */
    private String startMeterNumber;

    /**
     * 截止表身号
     */
    private String endMeterNumber;

    public MeterRangeVo(String startNum, String endNum) {
        this.startMeterNumber = startNum;
        this.endMeterNumber = endNum;
    }
}
XML 复制代码
<if test="md.rangeList != null and md.rangeList.size() > 0">
     <foreach collection="md.rangeList" item="rangeItem" separator="OR" open="(" close=")">
          a.meter_number BETWEEN #{rangeItem.startMeterNumber} AND #{rangeItem.endMeterNumber}
      </foreach>
 </if>
相关推荐
前网易架构师-高司机3 天前
带标注的驾驶员安全带识别数据集,识别率99.5%,可识别有无系安全带,支持yolo,coco json,pascal voc xml格式
xml·yolo·数据集·交通·安全带
逍遥德4 天前
Maven教程.01- settings.xml 文件<profile>使用详解
xml·java·maven
逍遥德4 天前
Maven教程.03-如何阅读pom.xml文件
xml·java·后端·maven
松叶似针4 天前
Flutter三方库适配OpenHarmony【doc_text】— .docx 解析全流程:从 ZIP 解压到 XML 提取
xml·flutter·harmonyos
松叶似针5 天前
Flutter三方库适配OpenHarmony【doc_text】— parseDocxXml:正则驱动的 XML 文本提取
xml·flutter
2301_780669865 天前
MyBatis(配置,增删改查,注解与XML两种开发方式)、SpringBoot配置文件(yml简化properties)
xml·spring boot·mybatis·javaweb
强子感冒了8 天前
JSON和XML学习笔记
xml·学习·json
сокол11 天前
【网安-Web渗透测试-漏洞系列】XXE漏洞
xml·web安全·php
树码小子12 天前
Mybatis(13)MyBatis Generator(xml生成器)& Mybatis-Plus初识
xml·mybatis
MX_935916 天前
Spring xml 方式整合第三方框架总结加案例
xml·java·spring