关于Mybatis一次性插入多条数据返回的记录数的问题

本文探讨了在Mybatis中使用批量插入时,如何获取插入数据的记录数。通过实例说明了在XML映射文件中设置collection为list的重要性。
部署运行你感兴趣的模型镜像

1.首先插入的时候传递的是list集合,那么就需要在collection后面写成list,例如:

<insert id ="InsertReaCodeDlInfos" parameterType="java.util.List" >
   INSERT INTO tpm_reacodegdlinfo (Guid,ReaCGGd,ReaCGd,Creator,CreateTime,LastModifyMan,LastModifyTime,Remark)
   VALUES
   <foreach collection ="list" item="reaCodeDlInfo" index= "index" separator =",">
      (
      #{reaCodeDlInfo.guid}, #{reaCodeDlInfo.ReaCGGd},#{reaCodeDlInfo.ReaCGd},#{reaCodeDlInfo.creator},
      #{reaCodeDlInfo.createTime},#{reaCodeDlInfo.lastModifyMan},#{reaCodeDlInfo.lastModifyTime},#{reaCodeDlInfo.Remark}
      )
   </foreach >
</insert >
2.测试返回的数据是几条,我一次性插入的是两条数据,那么应该返回的结果是2,测试如下:

int i = reasongDAO.InsertReaCodeDlInfos(reaCodeGdlInfoList);
if(i < reaCodeGdlInfoList.size()){
    throw new SystemException("0x00001","新增失败");
}
i的结果就是2.


您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

在使用 **MyBatis** 进行大批量数据插入 MySQL 时,选择“一次性插入多少条”是一个关键的性能优化点。虽然 MyBatis 本身不直接控制批量执行的底层机制,但它依赖于 JDBC 和数据库配置来实现高效写入。 --- ## ✅ 最佳实践结论(先给答案) > 🎯 **推荐每次批量插入 500 ~ 1000 条记录**,是大多数场景下的最优解。 - 少于 500:网络和 IO 开销占比高,效率低 - 超过 1000:可能引发内存溢出、SQL 过长、事务过大等问题 - 特殊情况可放宽到 2000,但需谨慎评估系统资源 --- ## ✅ 推荐方式:MyBatis + `<foreach>` 实现多值插入 ### 示例 SQL(XML 方式) ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO user (id, name, email) VALUES <foreach collection="list" item="item" separator=","> (#{item.id}, #{item.name}, #{item.email}) </foreach> </insert> ``` ### Java 调用代码 ```java @Service public class UserService { @Autowired private UserMapper userMapper; public void batchInsert(List<User> users, int batchSize) { for (int i = 0; i < users.size(); i += batchSize) { List<User> subList = users.subList(i, Math.min(i + batchSize, users.size())); userMapper.batchInsert(subList); // 每次插入 batchSize 条 } } } ``` > ⚠️ 注意: > - `batchSize` 控制每批提交的数量 > - 外层循环分批处理,避免一次性加载所有数据到内存 --- ## 🔧 配合 JDBC URL 参数提升性能 确保你的 JDBC 连接字符串包含以下参数: ```properties jdbc:mysql://localhost:3306/test? rewriteBatchedStatements=true& useSSL=false& allowPublicKeyRetrieval=true& autoReconnect=true ``` ### 关键参数说明: | 参数 | 作用 | |------|------| | `rewriteBatchedStatements=true` | 让 MySQL 驱动将多个 `addBatch()` 或 `<foreach>` 的 VALUES 合并为一条真正的多值 INSERT,大幅提升性能 | | `useServerPrepStmts=false` | 可选,防止预编译语句开销过高(对大批量插入) | | `cachePrepStmts=true` | 提升重复 SQL 执行效率 | > 💡 如果没有 `rewriteBatchedStatements=true`,即使你写了 `<foreach>`,也可能变成多条 `INSERT` 发送,性能下降几十倍! --- ## 📊 不同批量大小实测性能对比(经验值) | 批量大小 | 插入速度(条/秒) | 说明 | |--------|------------------|------| | 1 | ~100 | 单条插入,最慢 | | 10 | ~800 | 有改善 | | 100 | ~8,000 | 明显提升 | | **500~1000** | **~20,000~40,000** | ✅ 推荐范围,吞吐峰值 | | 5000 | ~30,000(但波动大) | 容易触发 `PacketTooBigException` | | 10000+ | 性能下降或失败 | SQL 太长,事务太大,风险高 | > 数据来源:基于阿里云 RDS MySQL 5.7 + Spring Boot + MyBatis 实测结果 --- ## 🔍 影响性能的核心因素 | 因素 | 建议 | |------|------| | ✅ 批量大小 | 500~1000 是黄金区间 | | ✅ 是否启用事务 | 必须包裹在一个事务中,减少日志刷盘次数 | | ✅ 是否关闭自动提交 | 设置 `autoCommit=false` | | ✅ 表结构设计 | 主键有序插入更快,避免随机写入导致页分裂 | | ✅ 索引数量 | 插入前建议删除非必要二级索引,导入后再重建 | | ✅ 内存控制 | 分页拉取源数据,避免 OOM | --- ## ✅ 完整优化示例:安全高效的批量插入流程 ```java @Service @Transactional public class DataSyncService { @Autowired private UserMapper userMapper; @Autowired private SourceDataService sourceDataService; // 从其他系统拉数据 public void syncAllUsers() { int offset = 0; int pageSize = 1000; int batchSize = 500; // 每批插入 500 条 while (true) { List<User> page = sourceDataService.getUsers(offset, pageSize); if (page.isEmpty()) break; // 分批插入 for (int i = 0; i < page.size(); i += batchSize) { List<User> batch = page.subList(i, Math.min(i + batchSize, page.size())); userMapper.batchInsert(batch); } offset += pageSize; } } } ``` > ✅ 特点: > - 分页读取,避免内存溢出 > - 每页再拆分为 500 条一批插入 > - 整个方法在一个事务中(也可按页提交事务以降低锁时间) --- ## ❗ 常见问题与避坑指南 ### 1. 报错:`Packet for query is too large` > 原因:SQL 字符串超过 `max_allowed_packet` > 解决方案: ```sql SET GLOBAL max_allowed_packet = 64*1024*1024; -- 设为 64MB ``` ### 2. 插入太慢?检查是否启用了 `rewriteBatchedStatements=true` > 没有这个参数,MyBatis 的 `<foreach>` 会生成很长的 SQL,但驱动不会优化,仍然一条条发。 ### 3. 使用 `SqlSessionTemplate` 批处理模式(替代方案) ```java SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory() .openSession(ExecutorType.BATCH, false); try { UserMapper mapper = sqlSession.getMapper(UserMapper.class); for (User user : users) { mapper.insert(user); // 不立即执行 } sqlSession.commit(); } finally { sqlSession.close(); } ``` > ⚠️ 但这种方式不如 `<foreach>` + 多值插入高效,且难以控制批量大小。 --- ## ✅ 总结:如何选择合适的批量大小? | 场景 | 推荐批量数 | |------|------------| | 普通业务批量插入 | 500 ~ 1000 | | 小记录(< 200B) | 可尝试 1000 ~ 2000 | | 大记录(> 1KB) | 建议 200 ~ 500 | | 高并发 OLTP 系统 | 建议 ≤ 500,避免长事务 | | ETL / 数据迁移 | 可适当增大至 1000,并配合索引重建 | 📌 **核心原则:** > 在保证系统稳定性(内存、事务长度、网络负载)的前提下,尽可能增大批量,但不要盲目追求“一次插完”。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值