JPA自定义原生Query处理NULL值报错:bytea转uuid失败
解决JPA原生查询UUID字段NULL值绑定错误的问题
问题原因
自定义原生查询中,当model_id(UUID类型)为NULL时,Hibernate将参数绑定为VARBINARY类型,而PostgreSQL无法将bytea(对应VARBINARY)转换为UUID,导致报错。而CrudRepository.save()方法能自动识别UUID类型,将NULL值绑定为OTHER类型,因此可以正常工作。
解决方案
方案1:在SQL中显式转换参数类型
在原生SQL里,对可能为NULL的UUID参数使用CAST强制转换为UUID类型,明确告知PostgreSQL参数类型:
@Modifying @Query(value = "insert into devices (id, model_id) values " + "(:#{#device.id}, CAST(:#{#device.modelId} AS UUID)) " + "ON CONFLICT (id) DO UPDATE SET model_id = CAST(:#{#device.modelId} AS UUID)", nativeQuery = true) void store(DeviceEntity device);
注:冲突更新时无需重复设置id(冲突依据就是id,值不会改变),可简化SET语句。
方案2:通过SpEL表达式指定参数类型
利用Spring Data JPA的SpEL扩展,在参数引用时指定Hibernate的UUID类型,强制绑定为UUID类型:
@Modifying @Query(value = "insert into devices (id, model_id) values " + "(:#{#device.id, type=org.hibernate.type.UUIDCharType}, " + ":#{#device.modelId, type=org.hibernate.type.UUIDCharType}) " + "ON CONFLICT (id) DO UPDATE SET model_id = :#{#device.modelId, type=org.hibernate.type.UUIDCharType}", nativeQuery = true) void store(DeviceEntity device);
如果你的UUID采用二进制存储,可改用org.hibernate.type.UUIDBinaryType。
方案3:使用@Param注解配合显式类型绑定
拆分参数并通过@Param注解声明,直接指定每个参数的类型:
@Modifying @Query(value = "insert into devices (id, model_id) values " + "(:id, :modelId) " + "ON CONFLICT (id) DO UPDATE SET model_id = :modelId", nativeQuery = true) void store(@Param("id") UUID id, @Param(value = "modelId", type = UUIDCharType.class) UUID modelId);
这种方式参数职责更清晰,类型绑定更直接。
验证
修改后重新运行测试,查看调试日志,参数应被绑定为OTHER类型(对应UUID),此时NULL值可被PostgreSQL正确识别,不会再出现类型转换错误。
内容的提问来源于stack exchange,提问作者Alex Tbk
相关产品推荐
相关产品推荐

