MyBatis报错2
为了拆分库表,为了省事在xml文件中直接注释:
1 | <select id="queryValidGroupBuyActivityId" resultMap="GroupBuyActivityMap"> |
这里直接自动注释了 Ctrl + /
但是应该这样
1 | <select id="queryValidGroupBuyActivityId" resultMap="GroupBuyActivityMap"> |
导致一直报错
这个问题你问得非常到位,而且你刚刚的判断是对的:
在 MyBatis 的 Mapper.xml 里,用
--注释“并不安全”
你现在这种现象,正是 MyBatis + SQL 注释 + 参数解析的经典坑。
我给你一个结论先行 + 原理解释 + 正确做法,你一看就通透。
一、先给结论(重要)
👉 在 MyBatis 的 <select> 里,不要用 -- 注释包含参数的 SQL 行
👉 推荐只用 XML 注释 <!-- -->,不要混用 SQL 注释
你刚才:
1 | -- WHERE source = #{source} AND channel = #{channel} |
👉 这行虽然“看起来”被注释了,但 MyBatis 在某些情况下仍然会解析到 #{channel}
所以你会看到这种诡异错误:
1 | Parameter index out of range (2 > number of parameters, which is 1) |
二、为什么“去掉注释就好了”?(核心原理)
1️⃣ MyBatis 做了两件事(不是你以为的一步)
MyBatis 处理 Mapper XML 时,大致是:
- 先解析 XML
- 再解析 SQL 占位符(
#{})生成 ParameterMapping - 最后才交给 JDBC 执行
⚠️ 重点:
👉 MyBatis 的参数解析 ≠ 数据库的 SQL 执行
2️⃣ -- 是“数据库注释”,不是“MyBatis 注释”
你写的是:
1 | -- WHERE source = #{source} AND channel = #{channel} |
对 MySQL 来说:
这是注释 ✔
但对 MyBatis SQL 解析器 来说:
❌ 它可能已经扫描到了
#{channel}并生成了 ParameterMapping
结果就是:
- SQL 真正执行时:只有 1 个
? - MyBatis 绑定参数时:想绑定 2 个参数
- JDBC:直接炸 💥
3️⃣ 这就是你看到的异常链
1 | MyBatis 认为有 channel 参数 |
👉 完全解释得通
三、为什么你“刚刚去掉注释就好了”?
因为你现在的 SQL 变成了:
1 | WHERE activity_id = #{activityId} AND status = 1 |
- MyBatis 只解析到
#{activityId} - PreparedStatement 也只有 1 个
? - 参数数量一致 ✅
- 一切恢复正常 ✅
四、MyBatis 中“正确 / 错误”的注释方式对比
❌ 不推荐(你刚才踩的坑)
1 | -- WHERE source = #{source} AND channel = #{channel} |
⚠️ 凡是 SQL 注释中带 #{},都有风险
✅ 推荐方式 1:XML 注释(最安全)
1 | <!-- WHERE source = #{source} AND channel = #{channel} --> |
👉 MyBatis 完全不会解析
✅ 推荐方式 2:干脆删掉不用的 SQL(最省心)
1 | WHERE activity_id = #{activityId} AND status = 1 |
✅ 推荐方式 3(进阶):用 <if> 控制,而不是注释
1 | WHERE status = 1 |
👉 这才是 MyBatis 的正宗玩法
五、你这个问题和 multiThread() 的关系(帮你“解心结”)
你一开始以为:
“我卡在
MarketNode.multiThread()”
现在你应该已经明白了:
✅ multiThread 本身完全没问题
❌ 是线程里的 DAO → MyBatis → SQL 注释导致异常
而且因为是:
- 子线程抛异常
- 主线程在
Future.get()才感知
👉 所以“看起来”像是卡在多线程
其实是 数据库层面的参数解析炸了
六、一句经验总结(以后你看到就能条件反射)
MyBatis Mapper.xml 中:
- ❌ 不要在 SQL 注释里写
#{}- ✅ 只用
<!-- -->注释- ✅ 条件逻辑用
<if>,不用“注释开关”
