Mybatis语法(四)mysql插入或更新

本文介绍了一种使用MyBatis实现数据批量插入及更新的方法。通过在SQL语句中利用ON DUPLICATE KEY UPDATE特性,可以有效地解决数据在并发场景下的插入与更新问题。此外,还展示了如何在插入多条记录时应用foreach标签。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现有user表,userId为用户id,做为数据表user的主键:

由于userId不可以重复,而这里userId直接作为主键。为防止并发操作,插入语句可以这样设计:不存在userId则插入,否则更新:

<!--修改或更新-->
 <insert id="insertOrUpdate" parameterType="com.iflytek.edu.zx.activitity.dto.ActivityUser">
 
    insert into user
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="userId != null">
        userId,
      </if>
      <if test="nickName != null">
        nickName,
      </if>
      <if test="role != null">
        role,
      </if>
      <if test="createTime != null">
        createTime,
      </if>
      <if test="updateTime != null">
        updateTime,
      </if>
      <if test="nickNameUpdateTime != null">
        nickNameUpdateTime,
      </if>
      <if test="nickNameCreateTime != null">
        nickNameCreateTime,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="userId != null">
        #{userId,jdbcType=VARCHAR},
      </if>
      <if test="nickName != null">
        #{nickName,jdbcType=VARCHAR},
      </if>
      <if test="role != null">
        #{role,jdbcType=VARCHAR},
      </if>
      <if test="createTime != null">
        #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null">
        #{updateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="nickNameUpdateTime != null">
        #{nickNameUpdateTime,jdbcType=TIMESTAMP},
      </if>
      <if test="nickNameCreateTime != null">
        #{nickNameCreateTime,jdbcType=TIMESTAMP},
      </if>
    </trim>
    ON DUPLICATE KEY UPDATE
    updateTime=#{updateTime,jdbcType=TIMESTAMP}
     <if test="nickName != null">
     	,nickName=#{nickName,jdbcType=VARCHAR}
     </if>
     <if test="role != null">
     	,role = #{role,jdbcType=VARCHAR}
     </if>
    
    <if test="nickNameUpdateTime != null">
     	,nickNameUpdateTime=#{nickNameUpdateTime,jdbcType=TIMESTAMP}
     </if>
    
     <if test="nickNameCreateTime != null">
        ,nickNameCreateTime = #{nickNameCreateTime,jdbcType=TIMESTAMP}
      </if>
 
 </insert>

on udplicate key update后的内容表示,主键存在时则执行更新操作,需要注意的是insert字段中需要含有唯一性字段(主键索引或唯一索引)。

再如:

 <insert id="insertOnDuplicate" parameterType="XXXX">
    insert into t_product (
        id,
        intention_code,
        add_type,
        product_id,
        sbom_code,
        sbom_name)
    values (#{id},#{intentionCode,jdbcType=VARCHAR}, #{addType,jdbcType=INTEGER},  #{productId,jdbcType=BIGINT}, #{sbomCode,jdbcType=VARCHAR}, #{sbomName,jdbcType=VARCHAR}})
      ON DUPLICATE KEY UPDATE
      product_id = VALUES(product_id),
        sbom_name = VALUES(sbom_name),
        price = VALUES(price))
  </insert>

多条记录仅仅是多了foreach 标签:

  
<insert id="insertByBatchOnDuplicate" parameterType="java.util.List">
        insert into t_xxx (
        id,
        intention_code,
        add_type,
        product_id,
        sbom_code,
        sbom_name
    )
        values
        <foreach collection="list" item="item" index="index" separator=",">
            ( #{item.id},#{item.intentionCode,jdbcType=VARCHAR},
            #{item.addType,jdbcType=INTEGER},
            #{item.productId,jdbcType=BIGINT},
            #{item.sbomCode,jdbcType=VARCHAR},
            #{item.sbomName,jdbcType=VARCHAR}
         )
        </foreach>
        ON DUPLICATE KEY UPDATE
        product_id = VALUES(product_id),
        sbom_name = VALUES(sbom_name)
    </insert>

<think>嗯,用户问的是MyBatis如何实现MySQL的批量插入和删除。首先,我得回忆一下MyBatis的批量操作方式。记得MyBatis有几种方法,比如foreach循环拼接SQL,者使用批量处理器。 批量插入的话,常见的是在Mapper XML里用foreach遍历集合,生成多个VALUES子句。比如INSERT INTO表(字段) VALUES (...), (...), ...。但需要注意MySQL的JDBC驱动默认不支持批量,可能需要rewriteBatchedStatements参数。还有,一次插入的数据量不能太大,否则可能会超时者超过max_allowed_packet。 然后,批量删除也是类似的,用foreach拼IN语句,比如DELETE FROM表 WHERE id IN (id1, id2,...)。这里要确保传入的列表不为空,否则SQL会出错。可能需要判断一下集合是否为空,者在Java代码里处理。 另外,用户可能不知道ExecutorType.BATCH这种方式。用SqlSession的批处理模式,可以一次性发送多个语句,减少网络开销。但需要手动控制提交,比如每1000条commit一次,避免内存溢出。 还要考虑性能对比。foreach方式生成的SQL可能会很长,而批处理模式是预编译多次执行,可能更高效。需要根据数据量选择合适的方法。比如数据量大的时候,批处理更好,小批量的话foreach方便。 可能用户没有提到的,事务的问题。批量操作应该放在一个事务里,要么全部成功,要么回滚。需要确保事务管理正确,比如Spring中@Transactional的使用。 还有,参数类型要对,比如传入的list要是List类型,者在注解里指定@Param。可能出现的错误包括括号不匹配、分隔符问题,者在XML里特殊字符的处理,比如大于号要转义。 总结一下,回答的时候要分插入和删除,分别给出XML和注解的示例,提到性能优化参数,以及不同方法的适用场景。可能用户的实际需求是处理大量数据,所以还要提醒注意事项,比如分批提交,避免内存问题。</think>MyBatis 实现 MySQL 的批量插入和删除主要有两种方式:使用 `<foreach>` 标签拼接 SQL 语句,通过 `ExecutorType.BATCH` 批处理模式。以下是具体实现步骤和代码示例: --- ### 一、批量插入实现 #### 方法 1:使用 `<foreach>` 标签 ```xml <!-- Mapper.xml --> <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO user(name, age) VALUES <foreach collection="list" item="item" separator=","> (#{item.name}, #{item.age}) </foreach> </insert> ``` ```java // Java 调用 List<User> userList = new ArrayList<>(); // ... 添加数据 userMapper.batchInsert(userList); ``` #### 方法 2:使用 `ExecutorType.BATCH` ```java try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); for (User user : userList) { mapper.insertSingle(user); // 单条插入语句 } sqlSession.commit(); // 统一提交 } ``` #### 📌 性能优化建议 1.MySQL JDBC URL 添加 `rewriteBatchedStatements=true` 参数 2. 单次批量插入建议控制在 500-1000 条以内 --- ### 二、批量删除实现 #### 方法 1:使用 `<foreach>` 标签 ```xml <!-- Mapper.xml --> <delete id="batchDelete" parameterType="java.util.List"> DELETE FROM user WHERE id IN <foreach collection="list" item="id" open="(" separator="," close=")"> #{id} </foreach> </delete> ``` ```java // Java 调用 List<Integer> ids = Arrays.asList(1, 2, 3); userMapper.batchDelete(ids); ``` #### 方法 2:使用注解方式 ```java @Delete({ "<script>", "DELETE FROM user WHERE id IN", "<foreach collection='ids' item='id' open='(' separator=',' close=')'>", "#{id}", "</foreach>", "</script>" }) int batchDelete(@Param("ids") List<Integer> ids); ``` --- ### 三、对比分析 | 方法 | 优点 | 缺点 | |-------------------|-----------------------------|-----------------------------| | `<foreach>` 拼接 | 简单直观,单次网络交互 | SQL 长度限制,不适合超大数据量 | | ExecutorType.BATCH | 预编译复用,适合大数据量 | 需要手动控制提交,代码复杂度稍高 | | 注解方式 | 不需要 XML 配置 | 复杂 SQL 可读性较差 | --- ### 、注意事项 1. **空集合处理**:传入空集合会导致 SQL 语法错误,建议先判空 2. **事务控制**:批量操作建议统一用 `@Transactional` 管理 3. **分批次提交**:大数据量时建议每 1000 条提交一次 4. **SQL 注入防护**:不要直接拼接字符串,必须使用 `#{}` 参数化 --- ### 五、扩展方案 对于超大数据量(10万+),建议: 1. 使用 `LOAD DATA INFILE` 文件导入(插入场景) 2. 分批次执行 + 多线程处理 3. 使用 MyBatis-Plus 的 `saveBatch()` 方法(基于框架封装) 根据实际场景选择最适合的方案,一般中小批量数据推荐 `<foreach>` 方式,大数据量推荐 `ExecutorType.BATCH` 模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w_t_y_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值