mybatis plus update(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在 Java 后端开发领域,数据库操作是应用的核心功能之一。MyBatis Plus(以下简称 MP)作为 MyBatis 的增强工具包,凭借其简洁的 API 和高效的功能,成为许多开发者的首选。其中,mybatis plus update 操作是开发者日常工作中高频使用的场景。无论是修改用户信息、更新订单状态,还是调整库存数量,理解并掌握 MP 的更新机制都至关重要。

本文将从基础到进阶,分层次讲解 mybatis plus update 的实现方式,并通过实际案例和代码示例,帮助读者快速掌握这一核心技能。无论是编程新手还是有一定经验的开发者,都能从中获得实用的指导。


一、MyBatis Plus 更新操作的基础用法

1.1 基础更新:updateById 方法

MP 提供了最直接的更新方法 updateById,其核心逻辑是根据主键值更新指定对象的非空字段。

代码示例:

// 假设 User 表的主键为 id  
User user = new User();  
user.setId(1L);  
user.setAge(25);  // 仅修改年龄字段  

// 调用 updateById 方法  
userMapper.updateById(user);  

核心逻辑解释:

  • 主键校验:必须显式设置主键值(setId(1L)),否则会因主键缺失导致更新失败。
  • 字段覆盖:默认仅更新对象中非空的字段,空字段会被忽略。

比喻说明:
这就像快递员送包裹时,必须明确知道收件人的地址(主键),才能将包裹(数据)送达正确的地点。


1.2 批量更新:saveOrUpdate 方法

当需要根据主键是否存在自动执行插入或更新操作时,可以使用 saveOrUpdate 方法。

代码示例:

User user = new User();  
user.setId(1L);  // 存在则更新,不存在则插入  
user.setName("张三");  

userMapper.saveOrUpdate(user);  

注意事项:

  • 此方法会先查询主键是否存在,存在则调用 updateById,不存在则调用 insert
  • 频繁调用可能引发性能问题,需结合业务场景谨慎使用。

二、进阶用法:灵活的条件更新

2.1 条件更新:update 方法与 Wrapper

当需要根据条件批量更新数据时,update 方法配合 Wrapper(如 QueryWrapperLambdaUpdateWrapper)能精准控制更新范围。

代码示例(LambdaUpdateWrapper):

LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();  
wrapper.eq(User::getAge, 18)       // 条件:年龄等于18岁  
       .set(User::getIsAdult, true);  // 设置 isAdult 字段为 true  

userMapper.update(null, wrapper);  

核心逻辑说明:

  • update 方法参数:第一个参数为实体对象(可传 null,但需通过 set 方法指定更新字段),第二个参数为 Wrapper
  • LambdaUpdateWrapper:使用 Lambda 表达式避免字段名硬编码,提升代码可读性。

比喻说明:
这就像在超市打折时,商家根据商品种类(条件)对特定商品(符合条件的数据)统一降价(更新操作)。


2.2 动态字段更新:set 方法的灵活用法

通过 set 方法,开发者可以动态指定需要更新的字段,避免不必要的字段覆盖。

代码示例:

// 仅更新 name 和 email 字段  
userMapper.update(new UpdateWrapper<User>()  
    .set("name", "李四")  
    .set("email", "li@si.com")  
    .eq("id", 1L));  

优势:

  • 可避免因实体对象中其他字段(如 createTime)为空而被错误覆盖。
  • 支持 SQL 片段拼接(如 set("age = age + 1"))。

2.3 批量更新多条记录

当需要更新多条记录时,可通过 updateBatchById 方法实现。

代码示例:

List<User> users = new ArrayList<>();  
User user1 = new User(1L, "王五", 30);  
User user2 = new User(2L, "赵六", 28);  
users.add(user1);  
users.add(user2);  

userMapper.updateBatchById(users);  // 根据 id 批量更新  

性能提示:
此方法底层通过循环调用 updateById 实现,若数据量过大,建议结合分页或原生 SQL 优化。


三、高级技巧与最佳实践

3.1 乐观锁更新:version 字段的使用

通过版本号机制(version 字段)实现乐观锁,防止并发更新导致的数据覆盖。

实现步骤:

  1. 在实体类中添加 version 字段,并在数据库表中对应列设置为 INT
  2. 在 Mapper 接口或 XML 中声明 @Version 注解。

代码示例:

@Data  
public class User {  
    private Long id;  
    private String name;  
    @Version  // 标记为版本号字段  
    private Integer version;  
}  

// 更新逻辑  
User user = userMapper.selectById(1L);  
user.setName("王小二");  
userMapper.updateById(user);  // 自动增加 version 值  

工作原理:

  • 更新时会自动附加 version = version + 1 的条件,若版本不匹配则更新失败。

比喻说明:
这类似于图书馆的座位预约系统:用户只能在座位未被他人占用(版本号匹配)时成功续借。


3.2 原生 SQL 与自定义更新语句

当 MP 的内置方法无法满足复杂需求时,可通过 BaseMapperupdate 方法执行原生 SQL。

代码示例:

String sql = "UPDATE user SET age = age + 1 WHERE create_time BETWEEN #{startDate} AND #{endDate}";  
Map<String, Object> params = new HashMap<>();  
params.put("startDate", "2023-01-01");  
params.put("endDate", "2023-12-31");  

userMapper.update(new User(), new UpdateWrapper<User>().sql(sql, params));  

注意事项:

  • 需自行处理 SQL 注入风险,建议使用参数化查询。
  • 复杂逻辑建议通过 XML 文件管理 SQL 语句,提升可维护性。

3.3 事务管理与回滚策略

更新操作通常需要事务支持,确保数据一致性。

代码示例:

@Transactional  
public void updateUsers() {  
    // 更新用户信息  
    User user = new User(1L, "陈七", 35);  
    userMapper.updateById(user);  

    // 更新订单状态  
    Order order = new Order();  
    order.setId(1001L);  
    order.setStatus("COMPLETED");  
    orderMapper.updateById(order);  

    // 若任意步骤失败,回滚所有操作  
}  

关键点:

  • 使用 @Transactional 注解或编程式事务管理。
  • 确保资源释放(如数据库连接)和异常处理。

四、常见问题与解决方案

4.1 更新操作后返回影响行数为 0

可能原因:

  • 主键未正确设置。
  • 条件查询未命中任何记录。
  • 乐观锁版本号不匹配。

解决方法:

  • 检查主键值是否正确。
  • 使用 selectById 确认数据是否存在。
  • 在日志中查看生成的 SQL 语句,验证条件逻辑。

4.2 多字段同时更新时性能下降

当更新涉及大量字段或大数据量时,可能出现性能瓶颈。

优化建议:

  • 分批处理:使用 updateBatchById 时分批次提交。
  • 字段选择性更新:仅更新必要字段,避免全字段覆盖。
  • 索引优化:为条件字段添加索引(如 age 字段)。

结论

mybatis plus update 操作是后端开发中不可或缺的技能。通过本文的讲解,读者可以掌握从基础到高级的更新方法,包括条件更新、批量操作、乐观锁机制以及性能优化策略。无论是处理简单的单条数据更新,还是应对复杂的并发场景,MP 的灵活 API 都能提供高效解决方案。

建议读者在实践中多尝试不同场景的代码示例,并结合项目需求选择最优实现方式。同时,持续关注 MyBatis Plus 的版本更新,以充分利用其不断优化的新特性。通过理论与实践的结合,开发者能够更自信地应对数据库更新操作的挑战。

最新发布