You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 修改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);
}
  1. 服务层调用时拆分DTO属性:
employeeRepository.updateEmployeeRecord(empDto.getId(), empDto.getFirstName(), empDto.getLastName(), empDto.getAddress());

方案2:改用JPQL查询(推荐,支持SpEL)

如果无需严格使用原生SQL,改用JPQL即可直接通过SpEL引用DTO属性:

  1. 修改实体类的命名查询为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方法
}
  1. 修改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);
}
  1. 服务层调用保持原有写法不变:
employeeRepository.updateEmployeeRecord(empDto);

关键注意事项

  • 执行更新、删除类的查询时,必须添加@Modifying注解,告知Spring Data这是修改操作;同时需要@Transactional开启事务,否则会触发执行错误。
  • JPQL使用实体类的属性名,原生SQL使用数据库表的列名,二者不要混淆。
  • 参数绑定注解是@Param(单数形式),错误的@Params会导致参数无法正确映射。

内容的提问来源于stack exchange,提问作者JATHURSHAN SUMANDIRAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:05:07