Caused by: java.lang.ClassNotFoundException: org.apache.ibatis.cursor.Cursor解决方法:SSM 项目 mybatis-spri

发布时间:2026/10/5 21:09:29
Caused by: java.lang.ClassNotFoundException: org.apache.ibatis.cursor.Cursor解决方法:SSM 项目 mybatis-spri 1. SSM 启动就报 Cursor 找不到先别急着改代码java.lang.ClassNotFoundException: org.apache.ibatis.cursor.Cursor这个报错第一次见的人很容易以为是自己的 Mapper 写错了或者 XML 里 resultType 配错了。实际上它跟你的业务代码基本没关系问题出在依赖版本上。org.apache.ibatis.cursor.Cursor是 MyBatis 从 3.4.0 开始才引入的接口用来支持流式查询Cursor 查询。如果你的mybatis核心包版本低于 3.4.0但mybatis-spring用的是 1.3.x那么 Spring 在启动扫描 Mapper 方法签名时会去反射读取方法参数类型一旦碰到Cursor这个类型类加载器找不到就直接抛NoClassDefFoundError紧接着Caused by: ClassNotFoundException。这个场景在 SSMSpring SpringMVC MyBatis整合项目里特别常见尤其是从网上抄了一份 pom或者用 IDE 自动补全依赖时Maven 帮你选了一个「看起来能用」的版本组合。典型症状是项目编译通过Tomcat 启动到finishBeanFactoryInitialization阶段突然崩堆栈里能看到LocalVariableTableParameterNameDiscoverer、ConstructorResolver.autowireConstructor这些 Spring 内部类最后一行才是Caused by: java.lang.ClassNotFoundException: org.apache.ibatis.cursor.Cursor。很多人盯着最后一行找其实真正的线索在NoClassDefFoundError和mybatis-spring的版本上。适合谁看正在做 SSM 整合、用 Maven 管理依赖、启动时报 Cursor 缺失的 Java 后端同学。看完你能自己用mvn dependency:tree定位版本冲突把mybatis和mybatis-spring对齐到兼容组合并且用统一的 API 通道验证接口是否真的恢复正常而不是靠反复重启碰运气。我试过在一个老项目里pom 里mybatis写的是 3.2.8mybatis-spring写的是 1.3.2启动必崩。把mybatis升到 3.4.1 之后问题当场消失。下面把完整排查和修复过程拆开讲。2. 用 mvn dependency:tree 定位 mybatis-spring 版本错配在动手改 pom 之前先确认到底是谁把mybatis拉成了低版本。Maven 的依赖调解规则是「最短路径优先」如果mybatis-spring自己声明了对mybatis的依赖而你又没显式写mybatis的版本那最终生效的可能是mybatis-spring传递进来的版本。mybatis-spring1.3.x 的 POM 里对mybatis的依赖是provided或者带版本范围的不同小版本行为不一样这就是坑的来源。第一步在项目根目录执行依赖树命令只看 mybatis 相关的分支mvn dependency:tree -Dincludesorg.mybatis:mybatis,org.mybatis:mybatis-spring输出大概长这样[INFO] --- maven-dependency-plugin:3.1.1:tree (default-cli) --- [INFO] com.example:ssm-demo:war:1.0-SNAPSHOT [INFO] - org.mybatis:mybatis-spring:jar:1.3.1:compile [INFO] | \- org.mybatis:mybatis:jar:3.4.1:compile [INFO] \- org.mybatis:mybatis:jar:3.2.8:compile看到没这里出现了两个mybatis一个是mybatis-spring:1.3.1传递进来的 3.4.1另一个是你自己显式声明的 3.2.8。Maven 最终会选哪个取决于声明顺序和路径长度。如果 3.2.8 是你直接写在dependencies里的路径更短它就会赢于是运行时加载的是 3.2.8而 3.2.8 里根本没有Cursor接口mybatis-spring1.3.1 又偏偏要用它冲突就爆了。如果输出里出现omitted for conflict或者omitted for duplicate说明 Maven 已经帮你做了取舍你要看清楚被省略的是哪个版本。更稳妥的做法是用-Dverbose参数mvn dependency:tree -Dverbose -Dincludesorg.mybatis:mybatis它会打印出被省略的节点和原因比如(version managed from 3.4.1; omitted for conflict with 3.2.8)。这一步能让你明确知道「谁赢了、谁被丢了」。还有一种情况是父 POM 或者dependencyManagement里锁死了mybatis版本。这时候dependency:tree显示的是最终生效版本但你看 pom 里写的可能是另一个。检查方法是在项目里搜dependencyManagement看有没有对org.mybatis的版本声明。如果有子模块里再写版本号是无效的必须改父 POM 或者用属性覆盖。定位清楚之后记住一个兼容原则mybatis-spring1.3.x 需要mybatis3.4.0 及以上。官方文档里mybatis-spring1.3.0 的说明是「requires MyBatis 3.4.0 or higher」。所以只要把mybatis提到 3.4.1mybatis-spring用 1.3.1这一对就是稳的。下面给出可复制的配置。3. 可复制的 pom 依赖配置mybatis 3.4.1 与 mybatis-spring 1.3.1 对齐修复的核心就一句话显式声明mybatis版本并且让它不低于 3.4.0同时mybatis-spring用 1.3.x。下面这段可以直接贴进pom.xml的dependencies里。注意 groupId 是org.mybatis不是org.mybatis.spring后者是老的包名别写错。properties mybatis.version3.4.1/mybatis.version mybatis-spring.version1.3.1/mybatis-spring.version spring.version4.3.30.RELEASE/spring.version /properties dependencies !-- MyBatis 核心包必须 3.4.0 才有 Cursor 接口 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version${mybatis.version}/version /dependency !-- MyBatis 与 Spring 整合包1.3.x 对应 mybatis 3.4.x -- dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version${mybatis-spring.version}/version /dependency !-- Spring 相关按你项目实际版本调整 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version${spring.version}/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-tx/artifactId version${spring.version}/version /dependency /dependencies如果你用的是dependencyManagement统一管理版本把上面两个 mybatis 依赖的版本声明挪到dependencyManagement里子模块只写 groupId 和 artifactIddependencyManagement dependencies dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.4.1/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version1.3.1/version /dependency /dependencies /dependencyManagement改完之后一定要重新拉依赖并刷新 IDE。命令行执行mvn clean compile -U-U强制更新快照和 release 元数据避免本地仓库缓存了旧的 POM。IDEA 用户再点一次 Maven 面板的刷新按钮确保External Libraries里mybatis-3.4.1.jar已经出现而不是 3.2.8。这里有个容易忽略的点mybatis-spring1.3.1 的 POM 里对mybatis的依赖 scope 是provided意思是它不会主动帮你传递mybatis。所以你必须自己显式声明mybatis否则运行时会报NoClassDefFoundError: org/apache/ibatis/session/SqlSessionFactory之类的错。很多人只加了mybatis-spring就以为够了这是另一个常见坑。配置对齐后Spring 的SqlSessionFactoryBean在初始化时就能正常反射到Cursor类型LocalVariableTableParameterNameDiscoverer不会再抛异常。接下来验证接口是否真的恢复。4. 验证请求用统一 API 通道确认依赖与接口恢复正常依赖改完、项目能启动不代表 Mapper 接口调用就 100% 正常。有时候Cursor类加载问题解决了但 XML 映射或者事务配置还有隐患。这时候可以用一个统一的 API 通道来跑一次真实请求确认从 Controller 到 Service 到 Mapper 的链路是通的。TaoToken 提供统一的 Key 和 API 入口适合在本地调试阶段快速验证接口。它的 API 地址是https://taotoken.net/api控制台里可以创建 API Key文档里有各语言调用示例。下面用 curl 演示一次请求你可以把它替换成你项目里任意一个查询接口的路径。先准备环境变量避免 Key 写死在命令里export TAOTOKEN_API_KEY你的APIKey export TAOTOKEN_BASE_URLhttps://taotoken.net/api然后发一个请求这里以模型对话接口为例验证通道是否可用curl -sS ${TAOTOKEN_BASE_URL}/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [ {role: user, content: ping} ], max_tokens: 16 }如果返回 JSON 里带choices字段说明 Key 和通道都正常。这一步的意义在于把「网络/鉴权」和「业务代码」分开验证。如果这个请求通了但你的 SSM 接口还是 500那问题就在 Mapper 或事务配置而不是依赖版本。接着验证你的业务接口。假设你有一个/user/list的 GET 接口用 curl 打一次curl -sS http://localhost:8080/ssm-demo/user/list -H Accept: application/json预期返回一个 JSON 数组里面是用户数据。如果返回 500去看 Tomcat 日志里有没有Cursor相关的异常。如果Cursor异常消失了但出现Invalid bound statement (not found)那是 Mapper XML 的 namespace 或 id 对不上跟版本无关。对于 Cursor 流式查询本身可以写一个最小的测试 Mapper 方法来验证。在UserMapper接口里加CursorUser selectAllByCursor();XML 里对应select idselectAllByCursor resultTypecom.example.entity.User select id, name, age from user /selectService 里调用时注意Cursor 必须在事务内使用否则会报Cursor is closedTransactional public void streamUsers() { try (CursorUser cursor userMapper.selectAllByCursor()) { cursor.forEach(user - System.out.println(user.getName())); } catch (IOException e) { throw new RuntimeException(e); } }如果这段代码能跑通说明org.apache.ibatis.cursor.Cursor已经被正确加载版本对齐彻底完成。实测下来只要mybatis是 3.4.1、mybatis-spring是 1.3.1这个 Cursor 查询在 SSM 里是稳定的。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth修完版本问题后验证阶段还可能碰到几类报错。下面按真实报错信息对照排查。第一类401 Unauthorized。用 curl 调 TaoToken 接口时返回{error:{message:Invalid API key provided,type:invalid_request_error}}原因通常是 Key 复制时带了空格或者环境变量没生效。检查方法echo ${TAOTOKEN_API_KEY} | wc -c如果长度明显不对重新在控制台创建 Key。注意请求头格式是Authorization: Bearer sk-xxxBearer 和 Key 之间一个空格别多别少。第二类local proxy failed或connection refused。这通常是你本地配了 HTTP 代理但代理没启动或者代理地址写错了。检查环境变量env | grep -i proxy如果有http_proxy或https_proxy临时清掉再试unset http_proxy https_proxy第三类reading choices相关报错比如json: cannot unmarshal ... reading choices。这多半是请求体格式不对比如messages写成了字符串而不是数组或者model字段拼错。对照文档里的请求示例逐字段检查。还有一种可能是返回的不是 JSON而是 HTML 错误页用curl -i看响应头里的Content-Type就能确认。第四类OAuth相关报错。如果你在配置里用了 OAuth 流程但回调地址或者 client_id 不对会报invalid_grant或redirect_uri_mismatch。这类问题跟 MyBatis 无关属于鉴权配置检查控制台里的回调地址是否和代码里一致。第五类回到 MyBatis 本身。如果启动时报NoClassDefFoundError: org/apache/ibatis/cursor/Cursor变成了NoSuchMethodError说明版本对了但方法签名不匹配通常是mybatis-spring和mybatis跨了大版本。坚持 3.4.1 1.3.1 这一对不要混用 2.x 的mybatis-spring。排查时记住一个顺序先看Caused by最后一行是什么类缺失再用mvn dependency:tree确认实际生效版本最后用 curl 把网络和业务分开验证。这样能避免在无关的地方浪费时间。6. 把 Key、Base URL、Model ID 三件套固定下来后续接入更省事版本问题解决后如果你还要在项目里接入模型能力或者用 Coding Plan 做长期编码辅助建议把三件套固定成配置项Base URL、API Key、Model ID。这样换环境时只改配置不动代码。以settings.json或auth.json这类配置文件为例结构大致如下{ baseUrl: https://taotoken.net/api, apiKey: sk-你的Key, model: gpt-4o-mini }如果你用的是 Cline 或类似的编码插件MCP 配置里同样需要这三项。Base URL 填https://taotoken.net/apiKey 从控制台的 API Keys 页面获取Model ID 按文档里支持的模型名填。三件套对齐后本地调试和线上切换只需要改一个文件。需要创建 Key 的话走 API Keys 页面想看完整接入示例走接入文档想先验证模型是否可用用模型对话页面发一条消息即可如果是长期编码或 Agent 场景Coding Plan 更合适。把依赖版本和 API 通道都固定下来下次再遇到ClassNotFoundException你就能直接定位到是版本还是配置而不是从头猜。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询