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

mybatis foreach里用bind、foreach中使用bind的坑、foreach中动态生成表名

文章目录

  • 一、前言
  • 二、解决方法/foreach中使用bind
    • 2.1、方法一:#传参
    • 2.2、方法二:$传参 bind生成变量
  • 三、bind变量覆盖问题/错误示例
  • 四、总结

一、前言

在mybatis实际开发中遇到这样一个场景,foreach标签中需要动态生成一个表名,如t0,t1,t2…等等, 可以在dao层传入,也可以在foreach中用bind标签生成,这里我们介绍使用bind生成该变量。

示例如下:

dao层传入[张三、李四]。 mapper.xml中根据传入的列表个数使用foreach进行union all拼接,并且需要动态生成表名 t0、t1等等。最终拼接sql如下:

select * from(select * from user where name='张三' order by id
) t0
union all
select * from(select * from user where name='李四' order by id
) t1

二、解决方法/foreach中使用bind

下面为公共的UserService.java、UserMapper.java中的代码

UserService.java代码:

@Autowired
private UserMapper userMapper;public List<User> selectByNameList(){userMapper.selectByNameList(Arrays.asList("张三","李四"));return null;
}

UserMapper.java代码:

public interface UserMapper  {List<User> selectByNameList(List<String> nameList);
}

2.1、方法一:#传参

UserMapper.xml代码

<select id="selectByNameList" resultType="com.demo.entity.User"parameterType="java.util.List"><foreach collection="list" item="item" separator="union all"  index="index">select * from (select * from user where name = #{item} order by id) t#{index}</foreach>
</select>

日志如下:

==>  Preparing: select * from ( select * from user where name = ? order by id ) t? union all select * from ( select * from user where name = ? order by id ) t?
==> Parameters: 张三(String), 0(Integer), 李四(String), 1(Integer)

2.2、方法二:$传参 bind生成变量

UserMapper.xml代码

<select id="selectByNameList" resultType="com.demo.entity.User"parameterType="java.util.List"><foreach collection="list" item="item" separator="union all"  index="index"><bind name="tableName" value="'t' + index"></bind>select * from (select * from user where name = #{item} order by id) ${tableName}</foreach>
</select>

日志如下:

==>  Preparing: select * from ( select * from user where name = ? order by id ) t0 union all select * from ( select * from user where name = ? order by id ) t1
==> Parameters: 张三(String), 李四(String)

注意:

  • ${}方式传参有sql注入问题,所以确保${}中的变量没有注入风险。

三、bind变量覆盖问题/错误示例

上面的示例中,我们在foreach标签内使用了bind绑定变量给tableName并且用${tableName}的方式获取值。如果我们是使用#{tableName}的方式获取值,会发现每次tableName的值都会是最后一个元素。

错误示例一:

<select id="selectByNameList" resultType="com.demo.entity.User"parameterType="java.util.List"><foreach collection="list" item="item" separator="union all"  index="index"><bind name="tableName" value="'t' + index"></bind>select * from (select * from user where name = #{item} order by id) #{tableName}</foreach>
</select>

日志文件:

==>  Preparing: select * from ( select * from user where name = ? order by id ) ? union all select * from ( select * from user where name = ? order by id ) ?
==> Parameters: 张三(String), t1(String), 李四(String), t1(String)

错误示例二:循环内重复绑定同名变量

<foreach item="item" collection="list" separator=","><!-- 错误:每次循环覆盖 previousItem,最终所有值相同 --><bind name="previousItem" value="item" />#{previousItem}
</foreach>

四、总结

总结:在 MyBatis 的 foreach 循环中,应避免使用 bind 来创建每个迭代的临时变量,因为 bind 的作用域是当前上下文,在循环中会被覆盖。替代方案是在 Java 代码中预处理数据,或者直接在表达式中使用循环项和索引。

在 MyBatis 的 foreach 循环中使用 bind 元素时,需特别注意 bind 的作用域是当前整个 SQL 语句,而非单次循环迭代。这意味着在循环内多次使用 bind 绑定同名变量时,后一次会覆盖前一次的值,可能导致逻辑错误。

http://www.xdnf.cn/news/13727.html

相关文章:

  • 预压技术对滚珠螺杆寿命的影响是什么?
  • 预测性去匿名化攻击(PDAA):重塑数据安全攻防边界
  • 说一说Redis中如何使用一致性哈希算法
  • 强化学习:DQN学习总结
  • 野火板子上重装ubuntu20.04系统
  • gbcom线上共享瓦片
  • Kubernetes 从入门到精通-deployment控制器
  • 山东大学 2025 web数据管理期末复习总结
  • Python _Day52|神经网络调参指南
  • WLAN 技术指南:从入门到原理
  • git约定示提交
  • 005__C++类的基本语法
  • Ntfs!NtfsVolumeCheckpointDpc函数分析到调用Ntfs!NtfsCheckpointAllVolumes函数
  • 【AI论文】利用自注意力机制实现大型语言模型(LLMs)中依赖于输入的软提示
  • 数据结构学习20250612
  • 无人叉车 AGV 的智能物流枢纽逻辑:对接方式分类、技术原理与场景适配
  • 【android bluetooth 框架分析 04】【bt-framework 层详解 6】【Properties介绍】
  • FEC(Forward Error Correction)前向纠错快速了解
  • 【AS32系列MCU调试教程】硬件调试:JLink 驱动配置与调试技巧
  • 5 Android系统常用debug方法
  • [安卓按键精灵辅助工具]一些安卓端可以用的雷电模拟器adb命令
  • 行为模式-命令模式
  • Dagster 实现数据质量自动化:6大维度检查与最佳实践
  • 工厂模式demo
  • Peiiieee的Linux笔记(1)
  • 基于大模型预测的上睑下垂综合诊疗技术方案
  • 浅析4D-bev标注技术在自动驾驶领域的重要性
  • 数据库更新!万方
  • centos转移mysql的数据存储目录
  • 猎犬:快速 友好的桌面文本搜索软件 支持30+格式与高精度OCR