Mybatis如何使用动态SQL-foreach遍历集合、批量插入

发布时间:2021-12-15 11:45:09 作者:小新
来源:亿速云 阅读:348
# 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>

二、foreach遍历集合实战

2.1 遍历List集合

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>

2.2 遍历数组参数

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>

2.3 遍历Map集合

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>

三、批量插入操作详解

3.1 传统单条插入的问题

常规的单条INSERT语句在批量操作时存在明显缺陷: - 需要频繁建立/关闭数据库连接 - 执行效率低下(N次网络IO + N次SQL解析) - 事务管理复杂

3.2 foreach实现批量插入

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>

3.3 批量插入性能优化

  1. 批次控制:建议每批次500-1000条记录
// 分批次处理
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);
}
  1. 启用批处理模式
// 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();
}

四、高级应用场景

4.1 动态表名选择

<select id="selectByTable" resultType="map">
    SELECT * FROM ${tableName}
    WHERE id IN
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</select>

4.2 多条件动态查询

<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>

4.3 批量更新操作

<update id="batchUpdate">
    <foreach collection="userList" item="user" separator=";">
        UPDATE user
        SET name = #{user.name},
            age = #{user.age}
        WHERE id = #{user.id}
    </foreach>
</update>

五、常见问题与解决方案

5.1 参数处理异常

问题现象

There is no getter for property named '__frch_item_0' in 'class java.lang.Integer'

解决方案: - 确保使用@Param注解指定集合名称 - 检查collection属性是否与参数名一致

5.2 SQL语法错误

问题现象:生成的SQL语句缺少括号或分隔符

解决方案

<!-- 显式指定open/close -->
<foreach collection="list" item="item" open="(" close=")" separator=",">

5.3 大数据量性能问题

优化方案: 1. 使用ExecutorType.BATCH 2. 合理设置批次大小 3. 考虑使用存储过程处理超大数据量

5.4 不同数据库兼容性

解决方案

<!-- 数据库方言判断 -->
<if test="_databaseId == 'mysql'">
    <!-- MySQL特有语法 -->
</if>
<if test="_databaseId == 'oracle'">
    <!-- Oracle语法 -->
</if>

六、最佳实践建议

  1. 集合参数校验:始终在Java代码中进行空集合检查
if (CollectionUtils.isEmpty(idList)) {
    return Collections.emptyList();
}
  1. 安全注意事项
  1. 性能监控
// 添加SQL执行监控
long start = System.currentTimeMillis();
int count = mapper.batchInsert(list);
long duration = System.currentTimeMillis() - start;
log.info("批量插入{}条数据,耗时{}ms", list.size(), duration);
  1. 文档注释
<!-- 
  批量插入用户数据
  @param userList 用户列表,不能为空且元素必须包含所有必填字段
  @return 影响的行数 
-->

七、总结

MyBatis的foreach标签为集合处理和批量操作提供了优雅的解决方案。通过本文的详细介绍,我们了解到: 1. foreach标签可以灵活处理各种集合类型 2. 批量插入能显著提升数据操作效率 3. 合理使用动态SQL可以大幅减少重复代码 4. 需要注意不同数据库的语法差异

在实际开发中,建议结合具体业务场景选择合适的批处理方案,并始终关注性能表现和数据安全。通过良好的SQL编写习惯和适当的优化措施,可以充分发挥MyBatis动态SQL的强大功能。 “`

推荐阅读:
  1. mybatis批量插入(Oracle)
  2. mybatis oracle批量插入

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mybatis

上一篇:Kafka为什么会这么快呢

下一篇:Kafka可视化Web界面管理工具CMAK怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》