JDBI执行SQL被截断引发PostgreSQL类型错误的原因是什么
问题原因
@Define占位符无法在SQL单引号内生效
JDBI 中@Define注解的作用是做SQL模板的字符串替换,默认规则下解析器不会识别单引号包裹内容中的<占位符>标记。你代码中将<timeInterval>写在INTERVAL '<timeInterval>'的单引号内部,导致占位符没有被实际传入的参数替换,原样保留在了待执行的SQL中。- 特殊字符触发SQL截断
未被替换的<timeInterval>起始的<字符会被JDBI的模板解析器识别为占位符起始标记,因为没有匹配的结束标记,解析逻辑直接丢弃了该符号之后的所有SQL内容,最终生成的执行SQL到AND modification_date就结束了。
此时WHERE条件的最后一段相当于AND modification_date,modification_date是时间戳类型,不符合PostgreSQL要求的「AND关键字后面必须接布尔表达式」的语法规则,所以抛出了你看到的异常。
修复方案
你可以选择任意一种方式修改:
- 方案1:将单引号移到占位符外侧,保证
@Define能正常识别占位符
@Override @SqlQuery("SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_CAMPAIGN_ID + " = :campaignId AND " + COLUMN_STATUS + " = 0 AND " + COLUMN_STAGE_ID + " IS NULL AND " + COLUMN_MODIFICATION_DATE + " < NOW() - INTERVAL <timeInterval>") List<Idea> getDraftIdeasBeforeTime(@Bind("campaignId") long campaignId, @Define("timeInterval") String timeInterval);
调用方法时传入的 timeInterval 参数需要自带单引号,例如 getDraftIdeasBeforeTime(campaignId, "'7 days'")。
- 方案2:改用类型转换写法,直接绑定参数更安全
@Override @SqlQuery("SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_CAMPAIGN_ID + " = :campaignId AND " + COLUMN_STATUS + " = 0 AND " + COLUMN_STAGE_ID + " IS NULL AND " + COLUMN_MODIFICATION_DATE + " < NOW() - CAST(:timeInterval AS INTERVAL)") List<Idea> getDraftIdeasBeforeTime(@Bind("campaignId") long campaignId, @Bind("timeInterval") String timeInterval);
该方案不需要用 @Define,直接用 @Bind 传参即可,还能避免SQL注入风险。
内容的提问来源于stack exchange,提问作者Aakash Verma
相关产品推荐
相关产品推荐

