Mybatis-Plus报错:can not use this method for “getSqlSet“ | 带你从源码层面解析异常

Mybatis-Plus报错:can not use this method for “getSqlSet” | 带你从源码层面解析异常

背景

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

@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, StudentPO> implements 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”

在这里插入图片描述

为什么这样写?

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

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<StudentMapper, StudentPO> implements 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

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

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):

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

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

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

在这里插入图片描述


结论

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

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

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

在这里插入图片描述

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

在这里插入图片描述

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


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

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿杆.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值