mybatis批量插入list切割list算法

int totalNum = 9;
        int batchCommitNumber=10;
         int subListNum= totalNum/batchCommitNumber;
         List<Integer> collect = IntStream.range(0, 9).boxed().collect(Collectors.toList());
         for (int j = 0; j < subListNum+1; j++) {
             int start=j*batchCommitNumber;
             int end=(j+1)*batchCommitNumber;
             if (j==subListNum) {
                 end=totalNum-1;
            }
             if (start>end) {
                continue;
            }
          List<Integer> subList = collect.subList(j*batchCommitNumber, end);
          if (j==subListNum) {
              subList.add(collect.get(end));
          }

<think> 我们正在讨论MyBatis-Plus中使用@Insert注解实现批量插入的方法。根据引用内容,我们可以总结出以下几点关键信息: 1. 引用[1]展示了一个使用@Insert注解配合<script>标签和<foreach>标签实现批量插入的例子。这种方法通过XML风格的动态SQL在注解中直接编写SQL语句,其中<foreach>用于遍历集合。 2. 引用[2]提醒我们注意主键生成策略。如果使用MyBatis-Plus的雪花算法自动生成主键,需要确保在实体类的主键字段上正确配置@TableId注解,并批量插入时不要手动设置主键值(除非使用其他生成策略)。 3. 引用[3]提到一个常见错误:参数绑定异常。在批量插入时,需要确保在@Param注解中正确指定参数名,并在SQL语句中引用正确的参数。 因此,实现批量插入的步骤如下: 1. 在Mapper接口中定义一个方法,使用@Insert注解,并在注解值中编写插入SQL。 2. SQL语句使用<script>包裹,以便使用动态SQL标签(如<foreach>)。 3. 在SQL语句中,使用<foreach>标签遍历传入的集合,生成多个插入值。 4. 方法参数前使用@Param注解指定参数名,并在SQL中引用该参数名。 下面给出一个具体的例子: 假设我们有一个实体类`User`,对应的数据库表为`user`,包含字段`id`(主键,使用MyBatis-Plus的雪花算法自动生成)、`name`和`age`。 首先,确保实体类的主键配置正确: ```java public class User { @TableId(type = IdType.ASSIGN_ID) // 使用雪花算法自动生成主键(默认策略,可省略) private Long id; private String name; private Integer age; // 省略getter和setter } ``` 然后,在Mapper接口中编写批量插入方法: ```java public interface UserMapper extends BaseMapper<User> { @Insert("<script>" + "INSERT INTO user (id, name, age) VALUES " + "<foreach collection='userList' item='item' separator=','> " + "(#{item.id}, #{item.name}, #{item.age}) " + "</foreach>" + "</script>") void insertBatch(@Param("userList") List<User> userList); } ``` 注意点: - 在<foreach>标签中,`collection`属性指定了参数名(即`@Param`注解指定的名称),`item`属性指定了集合中每个元素的别名,`separator`指定了每个值之间的隔符(这里是逗号)。 - 在插入语句中,我们显式写入了`id`字段,但是这里我们使用`#{item.id}`,而MyBatis-Plus在插入时如果发现`id`为null,主键策略是`IdType.ASSIGN_ID`(默认),则会自动生成一个雪花算法ID。因此,在传入的User对象列表中,我们不需要设置`id`,MyBatis-Plus会在插入时自动填充。 但是,这里有一个重要问题:在批量插入的SQL中,我们每个插入值都包含了`id`字段,并期望MyBatis-Plus自动生成。然而,在MyBatis的层面,当我们使用`#{item.id}`时,如果`item.id`为null,那么插入的id就是null,这会导致主键为null而违反数据库约束(除非数据库设置了主键自增,但这里我们用的是雪花算法,数据库不应设置自增,而是由程序生成)。 因此,我们需要确保在插入之前,每个User对象的id已经被设置。但是,如果我们依赖MyBatis-Plus的自动填充,通常是在插入单个对象时由MyBatis-Plus在调用`insert`方法时自动填充。而在自定义的批量插入中,MyBatis-Plus不会自动填充。 解决方案: 1. 在调用批量插入方法之前,手动为每个User对象设置ID(使用MyBatis-Plus提供的IdWorker生成,或者使用实体类中配置的填充策略,但需要手动触发)。 2. 修改Mapper中的SQL,不在SQL中写id字段,让数据库自动生成(但数据库需要设置自增主键,实体类主键策略为`IdType.AUTO`),但这与雪花算法冲突。 如果我们想保持使用雪花算法,则应该在业务代码中为每个User对象生成ID。例如: ```java List<User> userList = new ArrayList<>(); for (int i = 0; i < 10; i++) { User user = new User(); user.setName("user" + i); user.setAge(20 + i); // 手动设置ID,使用MyBatis-Plus提供的IdWorker(3.3.0之前)或者IdentifierGenerator(3.3.0之后) // 注意:在3.3.0之后,IdWorker被移除了,建议使用IdentifierGenerator,但通常我们直接设置一个布式ID // 可以使用如下方法: // user.setId(IdWorker.getId()); // 3.3.0之前 // 3.3.0及之后,可以使用: // user.setId(new Snowflake().nextId()); 或者使用工具类 // 或者如果你配置了MyBatis-Plus的KeyGenerator,也可以自动生成,但这里我们自定义批量插入,需要手动设置。 // 由于我们使用的是自定义SQL,所以需要手动设置ID。 user.setId(IdUtil.getSnowflakeNextId()); // 使用hutool的IdUtil,或者自己实现 } userMapper.insertBatch(userList); ``` 但是,如果我们希望像MyBatis-Plus内置的`insert`方法一样自动填充ID,我们可以使用MyBatis-Plus的`SqlHelper`中的`executeBatch`方法来执行批量插入,这样就会触发自动填充。但这样就不是使用@Insert注解的方式了。 因此,使用@Insert注解进行批量插入时,如果需要生成主键,我们需要手动设置主键值。 另外,引用[3]中提到的错误,我们需要注意在SQL中引用的参数名必须和@Param注解中指定的参数名一致。例如,在<foreach>中`collection='userList'`,而方法参数为`@Param("userList")`,这样就不会出现参数绑定异常。 总结:使用@Insert注解实现批量插入,需要编写动态SQL,并注意主键生成和参数绑定问题。 §§相关问题§§ 1. MyBatis-Plus中使用@Insert注解批量插入时,如何避免主键重复? 2. 除了@Insert注解,MyBatis-Plus还有哪些批量插入的方法? 3. 如何解决MyBatis-Plus批量插入时的性能问题? </think>### MyBatis-Plus 使用 `@Insert` 注解实现批量插入的方法 在 MyBatis-Plus 中,使用 `@Insert` 注解实现批量插入需结合 **动态 SQL 语法**(`<script>` 和 `<foreach>` 标签)。以下是具体步骤和完整示例: #### 1. **Mapper 接口定义** ```java @Mapper public interface MaterialMapper extends BaseMapper<MaterialData> { // 批量插入方法 @Insert("<script>" + "INSERT INTO your_table (id, field1, field2, create_time) VALUES " + "<foreach collection='list' item='item' separator=','> " + "(#{item.id}, #{item.field1}, #{item.field2}, #{item.createTime}) " + "</foreach>" + "</script>") void insertBatch(@Param("list") List<MaterialData> dataList); } ``` #### 2. **关键配置说明** | 组件 | 说明 | |--------------|----------------------------------------------------------------------| | **`<script>`** | 包裹动态 SQL,允许在注解中使用 XML 标签 | | **`<foreach>`** | 遍历集合参数:<br> • `collection`:参数名(需与 `@Param` 一致)<br> • `item`:集合元素的别名<br> • `separator`:生成的 SQL 片段隔符 | | **`@Param`** | 显式声明参数名,避免 `Parameter 'xxx' not found` 错误 [^3] | #### 3. **实体类配置(主键生成策略)** ```java public class MaterialData { @TableId(type = IdType.ASSIGN_ID) // 使用雪花算法自动生成 ID private Long id; private String field1; private String field2; private Date createTime; // 省略 getter/setter } ``` **注意**: - 若需自动生成主键,确保 `@TableId(type = IdType.ASSIGN_ID)` 已配置 [^1] - **禁止手动设置 ID**,否则会导致雪花算法失效 [^2] #### 4. **常见问题解决** 1. **主键未自动生成** - 检查 `@TableId` 类型是否为 `IdType.ASSIGN_ID`(默认值) - 确保数据库表 **未设置主键自增**(AUTO_INCREMENT),应与雪花算法策略一致 [^2] 2. **参数绑定异常** 错误信息:`Parameter 'item' not found. Available parameters [list, param1]` **解决方案**: - 使用 `@Param("list")` 明确声明集合参数名 - SQL 中 `collection` 属性值必须与 `@Param` 定义的名称一致 [^3] 3. **性能优化** 大批量插入时,建议批次处理(如每 1000 条执行一次插入),避免单次 SQL 过长。 --- ### 完整调用示例 ```java // 业务层调用 @Service public class MaterialService { @Autowired private MaterialMapper materialMapper; public void batchInsert(List<MaterialData> dataList) { // 无需手动设置 ID!MyBatis-Plus 会自动填充 materialMapper.insertBatch(dataList); } } ``` ### 注意事项 1. **主键冲突**:确保未手动设置 `id` 字段,否则会覆盖自动生成的布式 ID。 2. **SQL 长度**:单次插入数据量过大可能导致数据库拒绝,需批处理。 3. **事务管理**:在 Service 层添加 `@Transactional` 保证原子性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值