17:12:47.358 [http-nio-11080-exec-2] ERROR c.c.f.w.e.GlobalExceptionHandler - [handleRuntimeException,100] - 请求地址'/xx/xxx/xxx/xxx/xxx/8bbe5b132a7a4d9bb28cedfeac94d69f',发生未知异常.
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'ew.sqlSegment != null and ew.sqlSegment != '''. Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment [com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: can not use this method for "getSqlSegment"]
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:97)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439)
at com.sun.proxy.$Proxy129.delete(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.delete(SqlSessionTemplate.java:304)
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:69)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
at com.sun.proxy.$Proxy205.delete(Unknown Source)
at com.baomidou.mybatisplus.extension.service.IService.remove(IService.java:146)
at com.cn.basedata.service.impl.xxxxImpl.deletexxxIds(xxxxImpl.java:80)
at com.cn.basedata.service.impl.xxxxImpl$$FastClassBySpringCGLIB$$35e8855a.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:792)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707)
at com.cn.basedata.service.impl.xxxxImpl$$EnhancerBySpringCGLIB$$94053a1.deletexxxByIds(<generated>)
at com.cn.basedata.service.impl.xxxxImpl.deletexxxByIds(xxxxImpl.java:172)
at com.cn.basedata.service.impl.xxxxImpl$$FastClassBySpringCGLIB$$17e90df0.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386)
at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703)
at com.cn.basedata.service.impl.xxxxImpl$$EnhancerBySpringCGLIB$$cf8fb23.deletexxxByIds(<generated>)
at com.cn.web.controller.xxx.xxx.remove(xxx.java:221)
at com.cn.web.controller.videom
其中,报错的代码如下 (xxxImpl.deletexxxIds() 方法):
@Transactional(rollbackFor = Exception.class)
public boolean deletexxxIds(List<String> ids) {
return ids != null && ! ids.isEmpty() ? this.remove(this.lambdaQuery().in(xxx::getId, ids)) : false;
}
问题在于:
-
lambdaQuery()
创建的是一个LambdaQueryWrapper
,而remove()
方法内部会尝试获取sqlSegment
-
在某些 MyBatis-Plus 版本中,这种链式调用会导致
getSqlSegment
方法被错误调用
解决方案
方案1:改用传统 QueryWrapper(推荐)
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deletexxxIds(List<String> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
QueryWrapper<xxx> wrapper = new QueryWrapper<>();
wrapper.in("id", ids);
return this.remove(wrapper);
}
方案2:分离 Lambda 表达式构造
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deletexxxIds(List<String> ids) {
if (ids == null || ids.isEmpty()) {
return false;
}
LambdaQueryWrapper<xxx> wrapper = Wrappers.lambdaQuery();
wrapper.in(xxx::getId, ids);
return this.remove(wrapper);
}
方案4:升级 MyBatis-Plus 版本
如果是版本问题(特别是 3.4.x 之前的版本),建议升级到最新稳定版:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
为什么这样修改有效?
原始代码中的链式调用 this.remove(this.lambdaQuery().in(...))
在某些版本中会导致:
-
条件构造器被过早评估
-
内部尝试获取
sqlSegment
时上下文不完整
而分离构造步骤(方案2)或使用传统 QueryWrapper(方案1)可以避免这种内部处理冲突。这是 MyBatis-Plus 实现细节导致的问题,官方文档中也推荐避免过于复杂的链式调用。