SQL --update批量更新

本文介绍了一种在数据库中批量更新两张关联表数据的方法。通过使用正确的SQL更新语句,确保了只有匹配的记录被更新,同时保留了非匹配项的原始数据。文章详细展示了SQL语句的编写过程及优化。

需求:将t_user_info表中user_img、nickname、user_bg_img三个字段的值设置成与t_hr表中的hr_name、hr_img、hr_bg_img三个字段的值一样。

t_user_info表如下

113309_RlXu_2312022.jpg

t_hr表如下

113348_wRM8_2312022.jpg

t_user_info表数据存放情况如下

113608_gtpQ_2312022.jpg

t_hr表数据存放情况

113629_IaP3_2312022.jpg

由两张数据表存放数据情况可以看出,t_user_info表里存放的是用户信息,id从1000000000开始,依次推增。t_hr表里存放的是hr信息,他们的关系是:用户= 普通用户+HR用户。

需求分析:

工程开始的时候,t_user_info表里的user_img数据与t_hr表里hr_img数据并没有保持一致。现如今要求设置成一致。

即需要批量更新t_user_info表里user_img、user_bg_img和nickname字段。

最开始,我写的sql如下,(这里为了方便起见,先更新一个字段试下)

UPDATE t_user_info tui
SET tui.USER_IMG = (
    SELECT
        th.HR_IMG
    FROM
        t_hr th
    WHERE
        th.USE_FLAG = 1
    AND 
        th.AUDIT_FLAG = 1
    AND tui.USER_ID = th.HR_ID
)

接着,我验证我写的sql是不是对的,查看数据库,结果发现:

1.t_hr表中hr_id 等于 t_user_info表中user_id的数据都是对的

2.两个id不相等的数据,都被赋值成 空数据了,图如下

更新之前,我将t_user_info表里面user_img的数据全部设置成1

133748_1frV_2312022.jpg

上述sql更新之后的图如下

133848_e6xn_2312022.jpg

很明显user_id在t_hr表中存在的数据都更新成功了,例如:1000000000、1000000001、1000000004、……等。

当user_id不在t_hr表中的数据,例如1000000002、1000000003、1000000005、……等,就出现了错误,原本的数据为1,更新后变成空了。

接着开始找原因

很明显,上述的跟新是将t_user_info表中所有的数据都更新了,我们的需求是仅仅只需要更新user_id=hr_id的数据,user_id原本的数据还需要保留。因此,想到了在更新语句后面加条件,SQL如下:

134622_a7wz_2312022.jpg

很明显看到上述sql报错了,找不到th.HR_ID这列。

我就在这个带条件的地方卡了很久

最终在网上查找资料时,才发现updatre语句后面,可以跟多张表,接着将SQL改成如下

135012_BLHT_2312022.jpg

执行语句成功了,这步很关键。但是发现执行后message里面的信息,发现受影响的行数为35。

接着来查找满足条件的总个数是不是35,执行如下SQL

172221_CbOI_2312022.jpg

发现是25

对比查询where后的条件发现,原来是更新语句的条件带少了,马上补上去,SQL如下

172509_bzsN_2312022.jpg

恩恩,这就对了,接着我补上了USER_BG_IMG、NICKNAME,SQL如下

UPDATE t_user_info tui,t_hr th
SET tui.USER_IMG = (
    SELECT
        th.HR_IMG
    FROM
        t_hr th
    WHERE
        th.USE_FLAG = 1
    AND 
        th.AUDIT_FLAG = 1
    AND tui.USER_ID = th.HR_ID
),
tui.USER_BG_IMG = (
    SELECT
        th.HR_BG_IMG
    FROM
        t_hr th
    WHERE
        th.USE_FLAG = 1
    AND 
        th.AUDIT_FLAG = 1
    AND tui.USER_ID = th.HR_ID
),
tui.NICKNAME = (
    SELECT
        th.HR_NAME
    FROM
        t_hr th
    WHERE
        th.USE_FLAG = 1
    AND 
        th.AUDIT_FLAG = 1
    AND tui.USER_ID = th.HR_ID
)
    WHERE
        th.USE_FLAG = 1
    AND 
        th.AUDIT_FLAG = 1
    AND tui.USER_ID = th.HR_ID

接着很开心的交了任务。不一会儿,项目经理看到这段代码了,立马改写了SQL,如下

UPDATE t_user_info tui,t_hr th
SET tui.user_img = th.hr_img,
 tui.user_bg_img = th.hr_bg_img,
 tui.NICKNAME = th.HR_NAME
WHERE
    tui.user_id = th.hr_id
AND th.USE_FLAG = 1
AND th.AUDIT_FLAG = 1

其实,仔细看了下SQL,优化后还是对的。


转载于:https://my.oschina.net/u/2312022/blog/617269

<think> 首先,用户的问题是关于MyBatis-Plus中使用@Update注解实现批量更新的方法。我需要基于提供的引用和系统指令来回答。 回顾系统指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,保证真实可靠。 用户的问题是关于MyBatis-Plus的@Update注解实现批量更新。引用部分提供了关于乐观锁@Version注解和逻辑删除@TableLogic的信息,但用户这次问的是@Update注解的批量更新。 我需要回想MyBatis-Plus的知识: - @Update注解是用于定义更新操作的SQL语句。 - 批量更新通常涉及一次更新多个记录。在MyBatis-Plus中,可以使用updateBatchById方法或自定义SQL。 用户指定使用@Update注解,所以我应该专注于如何在注解中编写SQL来实现批量更新。 步骤: 1. **确认需求**:用户想用@Update注解实现批量更新。这意味着在Mapper接口的方法上使用@Update注解定义SQL。 2. **基本方法**: - 在MyBatis-Plus中,批量更新可以通过编写自定义SQL来实现。 - 对于@Update注解,可以写一个SQL更新语句,使用IN子句或CASE语句来处理多个ID。 3. **示例**: - 假设有一个实体User,有id、name等字段。 - 批量更新示例SQL:使用WHERE id IN来更新多个记录。 - 例如:UPDATE user SET name = #{name} WHERE id IN (#{ids}) 4. **使用@Update注解**: - 在Mapper接口中,定义一个方法,如: @Update("UPDATE user SET name = #{name} WHERE id IN (#{ids})") int batchUpdate(@Param("name") String name, @Param("ids") List<Long> ids); - 但这里有个问题:直接IN (#{ids})可能不正确,因为ids是列表。Mybatis解析时需要处理集合。 5. **处理集合参数**: - 在Mybatis中,如果参数是集合,需要在SQL中使用<foreach>标签,但@Update注解是原生SQL,不支持动态SQL标签。 - 解决方案:使用XML映射文件,或者在注解中使用脚本标签。 - 从Mybatis 3.4.2开始,支持在注解中使用<script>标签来写动态SQL。 6. **使用<script>标签**: - 例如: @Update({ "<script>", "UPDATE user SET name = #{name} WHERE id IN", "<foreach item='item' collection='ids' open='(' separator=',' close=')'>", "#{item}", "</foreach>", "</script>" }) int batchUpdate(@Param("name") String name, @Param("ids") List<Long> ids); 7. **MyBatis-Plus的批量更新方法**: - MyBatis-Plus提供了IService接口中的updateBatchById方法,但这不是使用@Update注解。 - 用户指定了@Update注解,所以我应该提供基于注解的方法。 8. **引用部分**:引用[1]和[2]是关于乐观锁和逻辑删除的,不直接相关,但我可以在回答中提及它们作为上下文,但主要关注@Update。 9. **回答结构**: - 结构清晰:先解释概念,然后提供步骤和示例。 - 使用中文。 - 在末尾添加引用标识。 - 生成相关问题。 10. **生成相关问题**:在回答后,列出相关问题。 11. **LaTeX**:用户的问题不涉及数学表达式,所以可能不需要,但如果需要,确保格式正确。例如,如果有变量,用$...$。 完整回答: - 介绍@Update注解的用途。 - 解释如何实现批量更新- 提供代码示例。 - 提醒注意事项。 - 添加引用。 - 生成相关问题。 代码示例: ```java @Mapper public interface UserMapper extends BaseMapper<User> { @Update({ "<script>", "UPDATE user SET name = #{name} WHERE id IN", "<foreach item='id' collection='ids' open='(' separator=',' close=')'>", "#{id}", "</foreach>", "</script>" }) int batchUpdateName(@Param("name") String name, @Param("ids") List<Long> ids); } ``` 注意事项: - 确保Mybatis版本支持<script>标签。 - 批量更新可能影响性能;考虑事务管理。 - MyBatis-Plus的updateBatchById更简单,但用户指定了注解方式。 引用:引用[1]提到乐观锁,但用户没问这个。我可以提到,如果更新涉及版本控制,可以参考乐观锁。引用[2]是逻辑删除。在回答中,自然地添加引用标识。 例如:如果您需要乐观锁支持,可以参考@Version注解[^1]。 生成相关问题: 1. MyBatis-Plus中如何实现事务管理? 2. 批量更新的性能优化方法? 3. 如何使用MyBatis-Plus的updateBatchById方法? 最后,确保回答真实可靠。 </think>### MyBatis-Plus 使用 @Update 注解实现批量更新的方法 在 MyBatis-Plus 中,`@Update` 注解用于定义自定义更新 SQL 语句。实现批量更新时,需要结合动态 SQL(如 `<foreach>` 标签)来处理多个记录。以下是逐步指南和示例,帮助您高效完成此操作: #### 1. **理解批量更新的原理** - **批量更新**:指一次性更新数据库中的多条记录,通常通过 SQL 的 `IN` 子句或动态条件实现。 - **`@Update` 注解的作用**:允许在 Mapper 接口的方法上直接编写 SQL,支持动态 SQL 语法(需使用 `<script>` 标签)。 - **注意事项**: - MyBatis-Plus 默认提供 `updateBatchById` 方法,但用户指定了 `@Update` 注解方式,需手动实现。 - 确保 MyBatis 版本 ≥ 3.4.2(支持注解中的动态 SQL)。 - 批量更新性能受事务和数据库配置影响,建议在事务中操作。 #### 2. **实现步骤** 以下是一个完整示例,以更新 `User` 实体(假设有 `id`、`name` 字段)的批量名称为例: ##### (1) 定义 Mapper 接口 在 Mapper 接口中,使用 `@Update` 注解编写动态 SQL。核心是利用 `<foreach>` 标签遍历参数集合: ```java import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Update; import java.util.List; @Mapper public interface UserMapper extends BaseMapper<User> { @Update({ "<script>", "UPDATE user SET name = #{name} WHERE id IN", " <foreach item='id' collection='ids' open='(' separator=',' close=')'>", " #{id}", " </foreach>", "</script>" }) int batchUpdateName(@Param("name") String name, @Param("ids") List<Long> ids); } ``` - **代码说明**: - `<script>`:包裹动态 SQL,使 MyBatis 能解析标签。 - `<foreach>`:遍历 `ids` 参数集合: - `collection="ids"`:指定方法参数中的集合名。 - `item="id"`:定义遍历时的临时变量。 - `open="("` 和 `close=")"`:生成 `IN (id1, id2, ...)` 格式。 - `separator=","`:设置分隔符为逗号。 - `@Param` 注解:显式声明参数名,避免 SQL 注入问题。 ##### (2) 在 Service 层调用 在 Service 实现类中注入 Mapper 并调用方法: ```java import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import javax.annotation.Resource; @Service public class UserServiceImpl implements UserService { @Resource private UserMapper userMapper; @Transactional // 添加事务保证原子性 @Override public boolean batchUpdateUserName(String name, List<Long> ids) { int count = userMapper.batchUpdateName(name, ids); return count > 0; } } ``` - **事务管理**:使用 `@Transactional` 确保所有更新要么全部成功,要么回滚。 - **返回值**:`batchUpdateName` 返回更新的记录数,可用于验证结果。 #### 3. **关键注意事项** - **性能优化**: - **集合大小限制**:避免一次性更新过多记录(例如超过 1000 条),否则可能导致 SQL 过长或数据库超时。可以分批处理: ```java // 示例:每 100 条分批更新 List<List<Long>> partitions = Lists.partition(ids, 100); partitions.forEach(part -> userMapper.batchUpdateName(name, part)); ``` - **索引使用**:确保 `WHERE` 子句中的字段(如 `id`)有索引。 - **与其他注解结合**: - 如果更新涉及乐观锁(防并发冲突),可添加 `@Version` 字段[^1]: ```java @Version private Integer version; // 在实体类中添加 ``` 并在 SQL 中检查版本号: ```sql UPDATE user SET name=#{name}, version=version+1 WHERE id IN (...) AND version=#{version} ``` - 逻辑删除场景可参考 `@TableLogic` 注解[^2]。 - **错误处理**: - 参数校验:在 Service 层检查 `ids` 是否为空。 - 异常捕获:处理 `DataIntegrityViolationException` 等数据库异常。 #### 4. **替代方案比较** | 方法 | 优点 | 缺点 | |------|------|------| | **`@Update` + 动态 SQL** | 灵活控制 SQL,适合复杂条件 | 需手动处理集合参数 | | **`updateBatchById`** | 简洁(MyBatis-Plus 内置) | 无法使用注解,需实体列表 | | **XML 映射文件** | 支持更复杂 SQL | 配置繁琐,不适合简单场景 | 推荐场景:简单批量更新用 `@Update`;复杂业务用 XML 或内置方法。如果您需要乐观锁支持,可结合 `@Version` 优化并发控制[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值