MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

背景

我的某个项目中有这样一段代码, 使用了 LambdaUpdateChainWrapper  和 继承ServiceImpl而来的update,并且把 LambdaUpdateChainWrapper 作为参数传给了 update,代码如下(业务部分已删除):

@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapperStudentPOimplements StudentService {

 public void updateStudent(StudentUpdateRequest request) {
        StudentPO student = new StudentPO();
        BeanUtils.copyProperties(request, student); // 这个是复制属性的
        LambdaUpdateChainWrapper<StudentPO> wrapper = lambdaUpdate().eq(StudentPO::getId, request.getId())
            .eq(StudentPO::getEnabledFlag, 1);
        this.update(student, wrapper);
    }

}

逻辑很简单,就是根据用户传入的更新数据,然后拿到数据库去把id相同并且flag为1的数据给更新了。

语法上是没有任何问题的,update确实有这两个参数的重载方法,项目也能正常跑起来😁。

但是啊,如果调用这个方法,程序就会报错:MybatisPlusException:can not use this method for “getSqlSet”

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

为什么这样写?

可能就有聪明的同学要问了

Q:为什么我不直接用updateById,硬要搞这么麻烦?

A:因为updateById只能判断id是否一样,我还有另一个条件要判断呢。

Q:为什么我不直接使用 lambdaUpdate().set().set().set().eq().eq;

A:这倒也能行,但是这未免太麻烦了一点,如果我的类里面属性很多的话,那我一个一个set就显得太难看了,所以我才希望用可以直接传实体类去更新的。

先讲解决方案

解决方案很简单,不使用 LambdaUpdateChainWrapper  ,而是用 LambdaUpdateWrapper  ,就是说,不能使用中间带个 Chain 的。

如果你使用 UpdateChainWrapper ,那也是不行的,但可以使用 UpdateWrapperLambdaUpdateWrapper  。

比如把上面的代码改成这样:

/**
 * @author 阿杆
 * @version 1.0
 * @date 2022/9/8 21:50
 */

@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapperStudentPOimplements StudentService {

 public void updateStudent(StudentUpdateRequest request) {
        StudentPO student = new StudentPO();
        BeanUtils.copyProperties(request, student); // 这个是复制属性的
        // 仅修改了下面这一小段
        LambdaUpdateWrapper<StudentPO> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StudentPO::getId, request.getId())
            .eq(StudentPO::getEnabledFlag, 1);
        this.update(student, wrapper);
    }

}

这段代码就可以正常运行了,这是为什么呢,感觉好像没什么区别啊?

这个报错的解决方案网上一搜也是一大堆的,但是都讲的很浅显,只说了解决方案,而没有说为什么。

那想要探索原因,我们就一起去看看源码吧!


导致报错的原因

MybatisPlusException:can not use this method for "getSqlSet"

翻译一下这个报错,就是说无法调用 getSqlSet 这个方法,那我们去看看这个方法到底写了些什么吧!

查看源码LambdaUpdateChainWrapper

先直接写一个 lambdaUpdate().getSqlSet();,然后Ctrl + 左键 点进去,我们可以看到:

    @Override
    public String getSqlSet() {
        throw ExceptionUtils.mpe("can not use this method for "%s"""getSqlSet");
    }

噢呦,这直接给我看蒙了哦,直接就抛个异常?难怪报错。

查看源码LambdaUpdateWrapper

那我们再看看 LambdaUpdateWrapper  的 getSqlSet(),这次得写两行代码了:

LambdaUpdateWrapper<IndicatorClassifyPO> wrapper = new LambdaUpdateWrapper<>();
wrapper.getSqlSet();

跟进去可以看到:

    @Override
    public String getSqlSet() {
        if (CollectionUtils.isEmpty(sqlSet)) {
            return null;
        }
        return String.join(StringPool.COMMA, sqlSet);
    }

这个就很正常了,就是把参数拼接一下。

现在我们再去看看 update() 的代码。

查看源码 update()

这里的话不太好找,我们通过打断点来找。

直接给这个类的getSqlSet打个断点,反正我们知道这里一定是会运行并且报错的(注意是LambdaUpdateChainWrapper):

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

然后调用随便写点啥,去调用update方法:

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

然后就可以开启调试了,我们可以直接让程序运行到报错的地方,然后再去看栈里的调用方法顺序:

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

现在已经运行到这句了,我们直接点击左下角栈列表里的方法,然后去看代码逻辑。

这里主要是通过代理来操作的数据,含有大量的反射代理代码,比较复杂,而且看起来也不是很能懂逻辑,我也看不懂 所以就不带大家看这些代码了。

但是我们可以看到的是,确实是由update方法一步一步调用过来的(看不清可以点开放大看):

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常


结论

那根据上面的这些信息,我们可以知道,Mybatis-Plus的开发者不希望用户使用LambdaUpdateChainWrapper作为update的更新条件参数。

这是为何呢?下面讲一下我的理解,不一定对,仅供参考。

在功能上,LambdaUpdateChainWrapper就是一个可以独立执行SQL的类,它内置了执行SQL的方法:

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

而 LambdaUpdateWrapper,是不具备这个能力的,输入update会报红,它只能作为参数传递到更新的方法当中:

MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

这么看的话,LambdaUpdateChainWrapper 其实并不应该被用做一个传递给update方法的wrapper参数,因为它本身就有update的功能。所以我们使用它来作为描述参数的时候就报错咯🤣!


但是不得不吐槽的是,官方给的报错信息(can not use this method for “getSqlSet”),好像并不是太能理解的样子🤧,就不能给个看着明白点的吗。


原文始发于微信公众号(程序员阿杆):MybatisPlus报错Can not use this method for getSqlSet | 带你从源码分析异常

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/207007.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!