如何向Hibernate查询传递方法参数?解决QueryException报错问题
修复Hibernate查询命名参数传递问题
你的问题主要出在两个地方:错误的参数引用语法和不符合JPQL规范的更新语句写法,下面一步步给你解决:
错误原因解析
- 你在
@Query里用了#{cinema}这种Spring表达式语言(SpEL)的语法,但JPA的@Query注解中,引用命名参数应该使用冒号:,而不是#,这就是报错unexpected char: '#'的直接原因。 - JPQL不支持直接把整个实体赋值给查询中的实体变量(也就是
set cin = #{cinema}这种写法),必须明确指定要更新的字段。 - 另外,
@Modifying修饰的update/delete方法,返回值应该是int(表示受影响的行数),而不是实体对象,因为JPQL的更新语句不会返回更新后的实体。
修复方案
方案1:正确使用命名参数,逐个字段更新
修改你的代码,用冒号引用参数,同时明确更新每个字段:
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @Modifying @Query("update Cinema cin set cin.name = :cinema.name, cin.address = :cinema.address where cin.id = :cinema.id") int updateCinema(@Param("cinema") Cinema cinema);
- 这里
:cinema.name会直接引用传入的cinema对象的name属性,Spring Data JPA会自动帮你解析。 - 返回值
int会告诉你这次更新影响了多少条数据,如果你需要获取更新后的实体,可以在调用这个方法后,再调用findById(cinema.getId())来查询。
方案2:用Spring Data JPA自带的save()方法(更简洁)
其实Spring Data JPA已经提供了现成的更新逻辑,如果你不需要自定义JPQL,直接用save()方法即可:
Cinema updateCinema(Cinema cinema);
或者直接复用默认的save()方法:
Cinema save(Cinema cinema);
当你传入的Cinema对象的id已经存在于数据库中时,Spring Data JPA会自动执行update操作,把所有非空字段更新到数据库里;如果id不存在,则执行insert。这种方式不需要写任何@Query注解,非常简洁。
方案3:使用原生SQL更新(不推荐,除非特殊需求)
如果因为某些原因必须用SQL直接更新整个实体,可以用原生SQL,但要注意数据库兼容性:
@Modifying @Query(value = "UPDATE cinema SET name = :name, address = :address WHERE id = :id", nativeQuery = true) int updateCinema(@Param("id") Long id, @Param("name") String name, @Param("address") String address);
不过这种方式需要手动传递每个字段,不如方案1或2方便。
额外注意事项
- 如果你使用
@Modifying进行更新/删除操作,别忘了在调用这个方法的业务层方法上加上@Transactional注解,否则会报错。 - 如果需要在更新后立即获取最新的实体数据,建议在更新后调用查询方法,因为JPQL的update操作不会返回实体。
内容的提问来源于stack exchange,提问作者Nico_99
相关产品推荐
相关产品推荐

