MyBatis-Plus UpdateWrapper 使用常见陷阱和解决方案

 更新时间:2024年08月22日 11:26:36   作者:Api官方认证调用工程师  
MyBatis-Plus是Mybatis的一个增强,简化了Mybatis的开发过程,不仅保持了Mybatis原有的功能,而且在无代码侵略下增加了许多的增强的功能,提供了丰富的CRUD操作,单表的CRUD操作无需编写SQL语句,本文介绍的是UpdateWrapper的常见陷阱和对应的解决方案,感兴趣的朋友一起看看吧

概要

MyBatis-Plus是Mybatis的一个增强,简化了Mybatis的开发过程,不仅保持了Mybatis原有的功能,而且在无代码侵略下增加了许多的增强的功能,提供了丰富的CRUD操作,单表的CRUD操作几乎无需编写SQL语句。虽然Mybatis-Plus方便了开发者的开发,但是也会遇到一些常见的陷阱和问题,了解这些潜在的陷阱并知道如何避免它们,可以帮助你更高效的和正确的使用Mybatis-Plus。本文中介绍的是UpdateWrapper的常见陷阱和对应的解决方案。

常见陷阱与解决方案

在我们的业务场景中,常常需要更新多条数据。在使用 MyBatis-Plus 进行更新操作时,由于错误地使用 UpdateWrapper,可能会导致数据更新出现不可预知的错误。这些错误包括条件重复使用、忽略逻辑删除字段、拼写错误、以及嵌套条件使用不当等问题。

用户表

1.条件重复使用导致更新错误

在使用Mybatis-Plus的 "UpdateWapeer" 时,如果在循环中重复使用一个 "UpdateWapeer" 对象,前一个循环中设置的条件和更新值会在后续的循环中继续生效,可能会导致更新操作受前一次条件的影响,导致最终只更新了部分的数据。

假设我们有一个用户表 'User' 需要根据不同用户Id批量删除用户,采用逻辑删除,如果我们在循环中使用同一个 ‘UpdateWarpper' 对象进行操作,就可能会导致部分更新错误。

public void updateByIds(UserIdsPO po) {
        List<Integer> userIds = po.getUserIds();
        userIds.forEach(userId ->{
            UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("is_delete",1)
                    .eq("id", userId);
            update(updateWrapper);
        });
}

在这个错误示例中,"UpdateWapeer" 在每次循环都会添加新的更新条件和设置值,导致前一次的条件和值影响后续的更新操作。这可能导致只有第一条数据被正确更新,后续的数据更新出现错误。

解决方案

 为了避免重复使用导致更新错误,我们应该在循环中创建一个新的 "UpdateWapeer" 对象,确保每次更新操作的条件和设置值是独立的。

 public void updateByIds(UserIdsPO po) {
        List<Integer> userIds = po.getUserIds();
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        userIds.forEach(userId ->{
            updateWrapper.set("is_delete",1)
                    .eq("id", userId);
            update(updateWrapper);
        });
}

当然建议不要再循环中去操作数据库,因为这样每次都要创建新的连接,向Mysql发送网络请求,增加额外的开销。建议批量操作,这样就连接一次数据库就好了,性能大大的提升。

public void updateByIds(UserIdsPO po) {
        List<Integer> userIds = po.getUserIds();
        //根据用户id查询用户
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", userIds);
        List<User> userList = list(queryWrapper);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        List<User> updateList = new ArrayList<>();
        userList.forEach(user ->{
            updateWrapper.set("is_delete",1)
                    .eq("id", user.getId());
            //将要修改的用户添加到集合中
            updateList.add(user);
        });
        //批量更新
        updateBatchById(updateList);
}

只要确保每一次循环都是新的 "UpdateWapeer" 对象,就能更新成功。

2.Sql注入风险

直接拼接 SQL 语句时,可能会存在 SQL 注入风险。攻击者可以通过传入恶意构造的输入,执行未预期的 SQL 语句,导致数据泄露或破坏。

public void updateUserStatus(Long userId, String status) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.setSql("status = '" + status + "'")
         .eq("id", userId);
    update(updateWrapper);
}

 解决方案

使用 MyBatis-Plus 提供的条件构造器方法,避免手动拼接 SQL 语句,同时使用参数化查询来防止 SQL 注入。

public void updateUserStatus(Long userId, String status) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("status", status)
         .eq("id", userId);
    update(updateWrapper);
}

3.嵌套条件使用不当

在使用 and 和 or 嵌套条件时,如果嵌套条件使用不当,可能会导致条件逻辑错误,更新操作未达到预期效果。例如,条件 A and (B or C) 和 (A and B) or C 的逻辑是不同的,不正确的嵌套条件可能导致错误的更新结果。

public void updateUsersState(int state, int age) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("state", state);
         .lt("age", age).or().isNull("name");
    update(updateWrapper);
}

 在这个错误示例中,条件 lt("age", age)isNull("name") 是通过 or 连接的,但没有使用 and 进行正确的嵌套,可能导致逻辑错误。

解决方案

通过使用 and 方法将条件正确嵌套,确保条件 lt("age", age)isNull("name") 组合在一起,并与其他条件正确连接,从而实现预期的更新效果。 

public void updateUsersState(int state, int age) {
     UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
     updateWrapper.set("state", state)
          .and(wrapper -> wrapper.lt("age", age).or().isNull("name"));
     update(updateWrapper);
}

4.条件未正确设置导致全表更新

有时候我们需要批量更新用户的状态。如果没有设置任何条件,可能会导致全表更新,造成严重的后果。

public void updateAllUsersState(int state) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("state", state);
    update(updateWrapper);
}

在这个错误示例中,如果未设置任何条件,可能会导致全表更新。

解决方案

始终确保设置了适当的条件,或者在更新前进行条件检查。

public void updateUserStateById(Long userId, int state) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("state", state)
         .eq("id", userId);
    update(updateWrapper);
}

5.列名拼写错误

在使用 UpdateWrapper 时,如果列名拼写错误,可能会导致 SQL 语法错误或更新操作没有预期效果。拼写错误会导致生成的 SQL 语句不正确,从而无法执行预期的更新操作。

public void updateUserName(Long userId, String newName) {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.set("nmae", newName)  // 拼写错误
         .eq("id", userId);
    update(updateWrapper);
}

解决方案

通过使用 LambdaUpdateWrapper,可以避免列名拼写错误,因为它使用实体类的字段而不是字符串来指定列名。

public void updateUserName(Long userId, String newName) {
    LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
    lambdaUpdateWrapper.set(User::getName, newName);
               .eq(User::getId, userId);
    update(lambdaUpdateWrapper);
}

小结

通过避免这些潜在的问题提高我们的数据库操作的安全性和效率,有效地防止这些问题。

到此这篇关于MyBatis-Plus UpdateWrapper 使用攻略的文章就介绍到这了,更多相关MyBatis-Plus UpdateWrapper 使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MapStruct @Mapping注解之处理映射中的Null值方式

    MapStruct @Mapping注解之处理映射中的Null值方式

    这篇文章主要介绍了MapStruct @Mapping注解之处理映射中的Null值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-03-03
  • 举例讲解Java设计模式编程中Decorator装饰者模式的运用

    举例讲解Java设计模式编程中Decorator装饰者模式的运用

    这篇文章主要介绍了Java设计模式编程中Decorator装饰者模式的运用,装饰者模式就是给一个对象动态的添加新的功能,装饰者和被装饰者实现同一个接口,装饰者持有被装饰者的实例,需要的朋友可以参考下
    2016-05-05
  • SpringBoot中使用Swagger的最全方法详解

    SpringBoot中使用Swagger的最全方法详解

    Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格的Web服务,这篇文章主要给大家介绍了关于SpringBoot中使用Swagger的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • Logback配置文件这么写(TPS提高10倍)

    Logback配置文件这么写(TPS提高10倍)

    这篇文章主要介绍了Logback配置文件这么写(TPS提高10倍),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 利用Springboot+Caffeine实现本地缓存实例代码

    利用Springboot+Caffeine实现本地缓存实例代码

    Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库,下面这篇文章主要给大家介绍了关于利用Springboot+Caffeine实现本地缓存的相关资料,需要的朋友可以参考下
    2023-01-01
  • Java使用Condition实现精准唤醒线程详解

    Java使用Condition实现精准唤醒线程详解

    这篇文章主要为大家详细介绍了Java如何使用Condition实现精准唤醒线程效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-02-02
  • 如何查找YUM安装的JAVA_HOME环境变量详解

    如何查找YUM安装的JAVA_HOME环境变量详解

    这篇文章主要给大家介绍了关于如何查找YUM安装的JAVA_HOME环境变量的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-10-10
  • java封装全局异常处理深入详解

    java封装全局异常处理深入详解

    这篇文章主要为大家介绍了java封装全局异常处理的深入详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • Spring Boot 与 Apache Pulsar 集成构建高性能消息系统实践应用案例

    Spring Boot 与 Apache Pulsar 集成构建高性能

    本文介绍了ApachePulsar作为新一代消息中间件的特点,并详细说明了如何在SpringBoot应用Pulsar,还介绍了Pulsar的高级特性和实践应用案例,如订单处理系统和实时数据分析,感兴趣的朋友跟随小编一起看看吧
    2026-04-04
  • maven项目切换JDK踩坑指南分享

    maven项目切换JDK踩坑指南分享

    文章介绍了如何在Windows系统中配置多版本JDK环境,并解决环境变量配置失效的问题,同时,还提供了在IntelliJ IDEA中配置不同项目JDK版本的方法
    2024-11-11

最新评论