You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spock测试时SQL语句出现H2语法错误,运行应用则正常

问题描述

仅在执行测试用例时出现SQL语法错误,运行应用或直接执行查询均正常。

报错信息

org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement

涉及的SQL查询语句

SELECT
  C.idCampaign,
  SUM(DATEDIFF(IFNULL(CPM.actual_end, CURDATE()),CPM.actual_start)) AS daysPaused
FROM Campaign C
JOIN CampaignPauseManagement CPM
ON C.idCampaign = CPM.idCampaign
WHERE C.idCampaign IN (:campaignIds)
GROUP BY C.idCampaign;

已尝试的无效操作

  • 修改变量名
  • 用COALESCE替换IFNULL
  • 改用CASE语句处理空值

以上操作均未解决问题,错误提示在SUM括号内的表达式末尾标记了[*],错误位置如下:

SELECT C.idCampaign, SUM(DATEDIFF(IFNULL(CPM.actual_end, CURDATE()),CPM.actual_start)[*]) AS daysPaused

解决方案

问题根源是测试环境使用的H2数据库和生产/运行环境的数据库(如MySQL、PostgreSQL)函数语法不兼容:

  1. 核心问题:DATEDIFF参数差异
    不同数据库中DATEDIFF的参数规则不一样:

    • 比如MySQL中是DATEDIFF(结束时间, 起始时间),直接返回天数差;
    • 但H2中必须指定时间单位,且参数顺序为DATEDIFF(单位, 起始时间, 结束时间),你的写法不符合H2的语法要求,才会报语法错误。
  2. 修正后的SQL(适配H2)

SELECT
  C.idCampaign,
  SUM(DATEDIFF('DAY', CPM.actual_start, IFNULL(CPM.actual_end, CURRENT_DATE))) AS daysPaused
FROM Campaign C
JOIN CampaignPauseManagement CPM
ON C.idCampaign = CPM.idCampaign
WHERE C.idCampaign IN (:campaignIds)
GROUP BY C.idCampaign;

这里把CURDATE()换成CURRENT_DATE,也是为了提升跨数据库的兼容性。

  1. 更优的测试环境适配方案
    不用修改SQL,直接给H2开启目标数据库的兼容模式即可。比如生产用MySQL,就在H2的连接URL中添加;MODE=MySQL参数,让H2模拟MySQL的语法规则,这样测试用例就能直接使用生产环境的SQL,避免语法差异问题。

内容的提问来源于stack exchange,提问作者user3413540

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:55:09