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 實現細節導致的問題,官方文檔中也推薦避免過于復雜的鏈式調用。