JPA原生查询插入时触发PSQLException:无法确定参数$2的数据类型
嘿,我碰到过好几次这个问题了,PostgreSQL在处理原生SQL里的null参数时经常会犯这个“脸盲”——没法确定null对应的具体数据类型,尤其是当参数是自定义类型(比如你的InternalToken)的时候。你这里的问题根源就是:当通过Optional.ofNullable(token.getArh()).orElse(null)给@Param("arh")传null值时,JDBC驱动没法告诉PostgreSQL这个参数对应的数据库列类型是什么,导致数据库抛出了无法确定参数$2的数据类型的异常。
给你几个实用的解决方案,你可以根据自己的场景选:
方案一:在原生SQL里显式指定参数类型
直接在SQL的判断语句里,把:arh参数强制转换为对应的数据库类型。比如假设你的InternalToken对应数据库里的是自定义枚举类型internal_token,或者是varchar类型,就这么改:
case when cast(:arh as internal_token) is not null then :arhToken else null end
这样不管参数是有效值还是null,PostgreSQL都能明确知道它的类型,就不会报错了。
方案二:用TypedParameterValue包装null参数
在调用repository方法的时候,不要直接传null,而是用Spring Data JPA提供的TypedParameterValue来包装,明确指定参数对应的数据库类型。举个例子:
import org.springframework.data.jpa.repository.query.TypedParameterValue; import org.hibernate.type.StandardBasicTypes; // 调用create方法时 repository.create( UUID.fromString(token.getId()), Optional.ofNullable(token.getArh()) .orElse(new TypedParameterValue(StandardBasicTypes.STRING, null)), // 根据实际类型调整StandardBasicTypes // 其他参数... );
这里要注意,StandardBasicTypes的选择要和InternalToken对应的数据库列类型匹配——如果是枚举映射成字符串就用STRING,如果是数字类型就用INTEGER之类的。
方案三:简化SQL逻辑(业务允许的话)
如果业务上允许当arh为null时,直接把对应的字段设为null,那可以简化case语句,比如直接用:arhToken当arh不为null,否则null,不过这个得看你的业务逻辑是否允许,本质上还是要让PostgreSQL能识别参数类型。
最后提个小提醒:一定要确认InternalToken在数据库里对应的列类型是什么,这是选对解决方案的关键哦。
备注:内容来源于stack exchange,提问作者Peter Penzov

