一條看似正常的 UPDATE 在 iBatis 執行時拋出 Error 1064: You have an error in your SQL syntax near 'WHERE id = 12'。本文完整復盤從異常堆棧分析、錯誤碼誤導、動態 SQL 多餘逗號定位、到最終修復的全過程,揭示「錯誤碼不靠譜,動態 SQL 需防多餘逗號」的核心教訓。
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE id = 12' at line 1
關鍵提示:near 'WHERE id = 12' —— 語法錯誤發生在 WHERE 關鍵字前,說明 SET 子句結構有問題。
搜索「MySQL 1064」多數結果稱「列名與關鍵字衝突需加反引號」。
嘗試給 name 加反引號 \`name\`,重跑單測 —— 依然報 1064。
教訓:錯誤碼僅提示「語法錯誤」,具體原因需具體分析,切勿盲目套用網上方案。
配置 log4j 打印 iBatis 執行的最終 SQL,但單測無輸出(可能事務回滾導致日志未刷出)。
無奈只能肉眼審閱動態 SQL 模板。
<update id="updateById" parameterClass="Org">
UPDATE org SET name = #name:VARCHAR#,
<isNotNull property="tree_level">tree_level = #tree_level#, </isNotNull>
<isNotNull property="yn">yn = #yn#, </isNotNull>
<isNotNull property="route">route = #route:VARCHAR#, </isNotNull>
`version` = `version` + 1,
<isNotNull property="editor">editor = #editor:VARCHAR# </isNotNull>
WHERE id = #id#
</update>
當 editor 為 null 時,最後一個 isNotNull 不輸出內容,但前面 version = version + 1, 留下的逗號變成:
UPDATE org SET name = ?, version = version + 1, WHERE id = ?
多餘逗號導致語法錯誤,MySQL 報錯位置指向 WHERE。
<update id="updateById" parameterClass="Org">
UPDATE org SET
<isNotNull property="name">`name` = #name:VARCHAR#, </isNotNull>
<isNotNull property="tree_level">tree_level = #tree_level#, </isNotNull>
<isNotNull property="yn">yn = #yn#, </isNotNull>
<isNotNull property="route">route = #route:VARCHAR#, </isNotNull>
<isNotNull property="editor">editor = #editor:VARCHAR#, </isNotNull>
`version` = `version` + 1
WHERE id = #id#
</update>
version = version + 1 不加逗號。SET,語法合法。單測通過。去掉反引號 \`name\`、\`version\` 亦正常運行,證實關鍵字衝突非本次根因。
STDOUT_LOGGING 或 P6Spy。這 30 分鐘的排查,換來的是對動態 SQL 模板編寫的肌肉記憶:逗號前置,邊界測試,真實 SQL 可見。