Spring Data JPA原生更新查询报错:冒号后不允许空格的解决方法
Spring Data JPA原生更新查询报错分析与解决
报错原因
你在原生SQL查询中使用了Spring SpEL表达式(:#{#emp.firstName})来引用DTO属性,但这个语法仅适用于JPQL查询。当标记nativeQuery = true时,Spring Data JPA会采用原生SQL解析器处理语句,它无法识别SpEL的嵌套写法,会将:#{#emp.firstName}视为普通参数,解析时判定冒号后存在非法空格结构,从而抛出"Space is not allowed after parameter prefix ':'"错误。
此外还有两处细节错误:
- Repository中的参数注解写错了,应该是
@Param(单数)而非@Params - 更新类查询需要
@Modifying和@Transactional注解,否则无法正常执行
解决方法
提供两种可行方案:
方案1:拆分DTO参数,使用原生SQL直接绑定
将DTO的属性拆分为独立参数传递,避开SpEL:
- 修改Repository接口:
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; public interface EmployeeRepository extends JpaRepository<Employee, Integer> { @Modifying @Transactional @Query(value = "update employee set first_name = :firstName, last_name = :lastName, address = :address where id = :id", nativeQuery = true) void updateEmployeeRecord(@Param("id") int id, @Param("firstName") String firstName, @Param("lastName") String lastName, @Param("address") String address); }
- 服务层调用时拆分DTO属性:
employeeRepository.updateEmployeeRecord(empDto.getId(), empDto.getFirstName(), empDto.getLastName(), empDto.getAddress());
方案2:改用JPQL查询(推荐,支持SpEL)
如果无需严格使用原生SQL,改用JPQL即可直接通过SpEL引用DTO属性:
- 修改实体类的命名查询为JPQL类型:
import javax.persistence.NamedQuery; import javax.persistence.Entity; @NamedQuery(name = "Employee.updateEmployeeRecord", query = "update Employee e set e.firstName = :#{#emp.firstName}, e.lastName = :#{#emp.lastName}, " + "e.address = :#{#emp.address} where e.id = :#{#emp.id}" ) @Entity public class Employee { // 实体类属性(JPQL使用实体属性名,而非数据库列名) private int id; private String firstName; private String lastName; private String address; // getter、setter方法 }
- 修改Repository接口,移除
nativeQuery = true并添加必要注解:
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; public interface EmployeeRepository extends JpaRepository<Employee, Integer> { @Modifying @Transactional @Query(name = "Employee.updateEmployeeRecord") void updateEmployeeRecord(@Param("emp") EmployeeDTO empDto); }
- 服务层调用保持原有写法不变:
employeeRepository.updateEmployeeRecord(empDto);
关键注意事项
- 执行更新、删除类的查询时,必须添加
@Modifying注解,告知Spring Data这是修改操作;同时需要@Transactional开启事务,否则会触发执行错误。 - JPQL使用实体类的属性名,原生SQL使用数据库表的列名,二者不要混淆。
- 参数绑定注解是
@Param(单数形式),错误的@Params会导致参数无法正确映射。
内容的提问来源于stack exchange,提问作者JATHURSHAN SUMANDIRAN
相关产品推荐
相关产品推荐

