Bootstrap

MyBatis-Plus UpdateWrapper 使用攻略:避免常见陷阱

文章目录

目录

文章目录

概要

常见陷阱与解决方案

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

解决方案

2.Sql注入风险

 解决方案

3.嵌套条件使用不当

解决方案

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

解决方案

5.列名拼写错误

解决方案

小结

概要

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

小结

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

;