您好,登录后才能下订单哦!
# Mybatis如何使用动态SQL-foreach遍历集合、批量插入
## 一、动态SQL与foreach标签概述
### 1.1 什么是动态SQL
动态SQL是MyBatis提供的强大特性之一,它允许我们在XML映射文件中构建灵活的SQL语句,根据不同条件动态生成不同的SQL片段。这种机制完美解决了传统JDBC中需要拼接复杂SQL字符串的痛点。
### 1.2 foreach标签的作用
`<foreach>`是MyBatis动态SQL的核心标签之一,主要用于:
- 遍历集合或数组参数
- 在IN条件中构建多值列表
- 实现批量插入操作
- 动态生成SQL片段
### 1.3 基本语法结构
```xml
<foreach collection="集合参数名"
item="当前元素别名"
index="索引别名"
open="开始符号"
close="结束符号"
separator="分隔符">
#{item}
</foreach>
Mapper接口定义:
List<User> selectUsersByIdList(@Param("idList") List<Integer> idList);
XML映射实现:
<select id="selectUsersByIdList" resultType="User">
SELECT * FROM user
WHERE id IN
<foreach collection="idList" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
Mapper接口:
List<User> selectUsersByIdArray(Integer[] ids);
XML实现:
<select id="selectUsersByIdArray" resultType="User">
SELECT * FROM user
WHERE id IN
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
Mapper接口:
List<User> selectUsersByCondition(@Param("params") Map<String, Object> params);
XML实现:
<select id="selectUsersByCondition" resultType="User">
SELECT * FROM user
WHERE 1=1
<foreach collection="params.entrySet()" item="value" index="key">
AND ${key} = #{value}
</foreach>
</select>
常规的单条INSERT语句在批量操作时存在明显缺陷: - 需要频繁建立/关闭数据库连接 - 执行效率低下(N次网络IO + N次SQL解析) - 事务管理复杂
Mapper接口定义:
int batchInsertUsers(@Param("userList") List<User> userList);
XML实现方案一(标准SQL):
<insert id="batchInsertUsers">
INSERT INTO user(name, age, email) VALUES
<foreach collection="userList" item="user" separator=",">
(#{user.name}, #{user.age}, #{user.email})
</foreach>
</insert>
XML实现方案二(MySQL特有语法):
<insert id="batchInsertUsers">
INSERT INTO user(name, age, email)
VALUES
<foreach collection="userList" item="user" separator=",">
(#{user.name}, #{user.age}, #{user.email})
</foreach>
ON DUPLICATE KEY UPDATE
name = VALUES(name),
age = VALUES(age)
</insert>
// 分批次处理
int batchSize = 500;
for (int i = 0; i < userList.size(); i += batchSize) {
List<User> subList = userList.subList(i, Math.min(i + batchSize, userList.size()));
userMapper.batchInsertUsers(subList);
}
// SqlSession配置
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (User user : userList) {
mapper.insertUser(user);
}
sqlSession.commit();
} finally {
sqlSession.close();
}
<select id="selectByTable" resultType="map">
SELECT * FROM ${tableName}
WHERE id IN
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
<select id="dynamicQuery" resultType="User">
SELECT * FROM user
WHERE 1=1
<if test="names != null">
AND name IN
<foreach collection="names" item="name" open="(" close=")" separator=",">
#{name}
</foreach>
</if>
<if test="ageList != null">
AND age IN
<foreach collection="ageList" item="age" open="(" close=")" separator=",">
#{age}
</foreach>
</if>
</select>
<update id="batchUpdate">
<foreach collection="userList" item="user" separator=";">
UPDATE user
SET name = #{user.name},
age = #{user.age}
WHERE id = #{user.id}
</foreach>
</update>
问题现象:
There is no getter for property named '__frch_item_0' in 'class java.lang.Integer'
解决方案:
- 确保使用@Param
注解指定集合名称
- 检查collection
属性是否与参数名一致
问题现象:生成的SQL语句缺少括号或分隔符
解决方案:
<!-- 显式指定open/close -->
<foreach collection="list" item="item" open="(" close=")" separator=",">
优化方案:
1. 使用ExecutorType.BATCH
2. 合理设置批次大小
3. 考虑使用存储过程处理超大数据量
解决方案:
<!-- 数据库方言判断 -->
<if test="_databaseId == 'mysql'">
<!-- MySQL特有语法 -->
</if>
<if test="_databaseId == 'oracle'">
<!-- Oracle语法 -->
</if>
if (CollectionUtils.isEmpty(idList)) {
return Collections.emptyList();
}
${}
中使用用户输入// 添加SQL执行监控
long start = System.currentTimeMillis();
int count = mapper.batchInsert(list);
long duration = System.currentTimeMillis() - start;
log.info("批量插入{}条数据,耗时{}ms", list.size(), duration);
<!--
批量插入用户数据
@param userList 用户列表,不能为空且元素必须包含所有必填字段
@return 影响的行数
-->
MyBatis的foreach标签为集合处理和批量操作提供了优雅的解决方案。通过本文的详细介绍,我们了解到: 1. foreach标签可以灵活处理各种集合类型 2. 批量插入能显著提升数据操作效率 3. 合理使用动态SQL可以大幅减少重复代码 4. 需要注意不同数据库的语法差异
在实际开发中,建议结合具体业务场景选择合适的批处理方案,并始终关注性能表现和数据安全。通过良好的SQL编写习惯和适当的优化措施,可以充分发挥MyBatis动态SQL的强大功能。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。