QueryDSL转SQL时第二个常量出现$p引发语法错误
问题
在SpringBoot项目中为了性能优化使用QueryDSL编写查询逻辑,代码如下:
Double aSumAll = select(tableA.sumColumn.sum()) .from(tableA) .where(tableA.tableAnother.id.eq(tableAnotherId)) .fetchOne(); if (aSumAll == null) aSumAll = 1.0; Double bSumAll = select(tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight).sum()) .from(tableA) .innerJoin(tableA.tableAnotherB, tableAnotherB) .where(tableA.tableAnother.id.eq(tableAnotherId)) .fetchOne(); if (bSumAll == null) bSumAll = 1.0; return select(Projections.constructor(tableAResponseDto.class, tableA.id, tableAnotherD.id, tableAnotherD.unitNm, tableAnotherC.id, tableAnotherC.itemNm, tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight), tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight) .divide(Expressions.constant(aSumAll)), tableA.sumColumn, tableA.sumColumn .divide(Expressions.constant(bSumAll)), Expressions.constant(bSumAll), Expressions.constant(aSumAll))) .from(tableA) .innerJoin(tableA.tableAnotherB, tableAnotherB) .innerJoin(tableA.tableAnotherB.tableAnotherC, tableAnotherC) .innerJoin(tableA.tableAnotherD, tableAnotherD) .where(tableA.tableAnother.id.eq(tableAnotherId)) .orderBy(tableA.id.asc()) .fetch();
生成的SQL中,第二个除法表达式的cast语句出现了$p参数(标注处):
select fpo1_0.id, fpo1_0.another_d_id, fup1_0.unit_nm, fp1_0.another_c_id, oi1_0.item_nm, (fpo1_0.sum_column*oi1_0.weight), ((fpo1_0.sum_column*oi1_0.weight)/cast(3084.3474 as float(53))), fpo1_0.sum_column, (fpo1_0.sum_column/cast(1834.3474 as float($p))) -- here from table_a fpo1_0 join table_another_b fp1_0 on fp1_0.id=fpo1_0.another_b_id join table_another_c oi1_0 on oi1_0.id=fp1_0.another_c_id join table_another_d fup1_0 on fup1_0.id=fpo1_0.another_d_id where fpo1_0.another_id = 'testValue' and fpo1_0.table_another_id=9 order by fpo1_0.id;
这导致语法错误:
ERROR: syntax error at or near "$"
尝试将.divide方法中的Expressions.constant(aSumAll)和Expressions.constant(bSumAll)替换为直接使用aSumAll、bSumAll,问题仍未解决。请问为何会出现该$p参数?
分析与解决
原因
这是QueryDSL处理Double类型常量时的类型转换BUG:
- 当传入Double类型常量(无论是通过
Expressions.constant()还是直接传变量),QueryDSL自动推断SQL类型时,错误地将float类型的精度参数识别为绑定参数(即$p),而非直接写入固定精度值。 - 该问题多出现于QueryDSL与PostgreSQL等数据库的适配逻辑中,底层类型处理模块未正确处理Double常量的精度配置。
解决方法
显式指定常量的SQL类型
使用Expressions.constant()时明确指定类型,避免自动推断出错:// 方式1:指定Java类型 tableA.sumColumn.multiply(tableAnotherB.tableAnotherC.weight) .divide(Expressions.constant(aSumAll, Double.class)) // 方式2:指定数据库特定类型(如PostgreSQL的Float8Type) tableA.sumColumn.divide(Expressions.constant(bSumAll, Float8Type.DEFAULT))绕开自动类型转换
将Double值转为字符串后再转为数值表达式,规避类型推断逻辑:tableA.sumColumn.divide(Expressions.asNumber(bSumAll.toString()))升级QueryDSL版本
该BUG在QueryDSL 5.x及以后的稳定版本中已被修复,直接升级依赖即可解决底层适配问题。
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

