Spring Boot原生MySQL查询自动添加()引发语法异常求助
Spring Boot 3.x 原生JPA查询List参数被自动加括号导致MySQL语法错误
问题场景
在Spring Boot 2.4.4中正常运行的原生MySQL查询,升级到Spring Boot 3.0.6后,IN子句和FIELD函数中的List参数被自动包裹额外括号,引发MySQL语法异常。
原Repository查询代码:
@Query(value = "SELECT id FROM example WHERE id IN ?1 ORDER BY FIELD(id , ?1) " ,nativeQuery = true) List<String> testQuery(List<String> ids);
Spring Boot 3.x中生成的错误SQL示例:
SELECT id FROM example WHERE id IN (('id1','id2')) ORDER BY FIELD(id , ('id1','id2'))
多余的嵌套括号导致MySQL报错。
解决方案
方案1:使用SpEL表达式展开List参数
通过Spring Data JPA的SpEL表达式,手动将List展开为符合MySQL语法的参数格式:
@Query(value = "SELECT id FROM example WHERE id IN (?#{T(org.springframework.data.jpa.repository.query.QueryUtils).toInClauseString(#ids)}) " + "ORDER BY FIELD(id, ?#{#ids.stream().collect(T(java.util.stream.Collectors).joining('\',\''))})", nativeQuery = true) List<String> testQuery(@Param("ids") List<String> ids);
QueryUtils.toInClauseString用于生成正确的IN子句参数- 流操作将List转为逗号分隔的字符串,适配FIELD函数的参数要求
方案2:直接使用NamedParameterJdbcTemplate手动执行查询
完全绕过JPA的参数处理逻辑,手动拼接SQL并执行,精准控制参数格式:
@Repository public class ExampleCustomRepository { private final NamedParameterJdbcTemplate jdbcTemplate; public ExampleCustomRepository(NamedParameterJdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public List<String> testQuery(List<String> ids) { // 生成对应数量的占位符 String placeholders = String.join(",", Collections.nCopies(ids.size(), "?")); String sql = String.format("SELECT id FROM example WHERE id IN (%s) ORDER BY FIELD(id, %s)", placeholders, placeholders); // 合并参数:IN子句和FIELD函数各需要一次ids列表 List<Object> params = new ArrayList<>(ids); params.addAll(ids); return jdbcTemplate.query(sql, params.toArray(), (rs, rowNum) -> rs.getString("id")); } }
在Controller中注入ExampleCustomRepository替代原JPA Repository即可。
方案3:拆分List参数为固定数量的独立参数(仅适用于参数长度固定场景)
如果传入的List长度固定,可以直接拆分为多个参数:
@Query(value = "SELECT id FROM example WHERE id IN (?1, ?2, ?3) ORDER BY FIELD(id, ?1, ?2, ?3)", nativeQuery = true) List<String> testQuery(String id1, String id2, String id3);
注意:此方法仅适合参数数量固定的场景,灵活性较差。
方案4:临时降级Hibernate版本(不推荐长期使用)
在Spring Boot 3.x的pom.xml中指定兼容的Hibernate版本,临时规避参数处理逻辑的变化:
<properties> <hibernate.version>6.1.7.Final</hibernate.version> </properties>
该方案可能引入其他兼容性问题,仅作为临时应急方案。
内容的提问来源于stack exchange,提问作者Akhil
相关产品推荐
相关产品推荐

