SpringBoot如何使用where参数查询数据库单条数据
问题根因
你当前的代码存在多处实现错误,直接触发了IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 4报错:
- 核心触发原因:
MessageRepository中getByUser方法上的@Query(value = "select * from users")没有加login过滤条件,实际执行的是全表查询。你在接口内写的JdbcTemplate查询逻辑完全不会生效:Spring Data JPA的Repository是基于动态代理实现的,标记了@Query的方法会被框架直接生成查询实现,覆盖你写的Kotlin接口默认方法体,最终查回全表4条数据,但方法返回值定义为单条User?,框架期望结果集只有1条,直接抛出异常。 - 严重安全问题:就算你写的JdbcTemplate逻辑能执行,直接用
$login拼接SQL字符串会造成SQL注入漏洞,生产环境绝对禁止这种写法。 - 用法错误:不要在Repository层手动
new JdbcTemplate(),Spring托管的组件需要从容器获取注入的实例,手动new的实例不会加载你配置的数据源,根本无法正常操作数据库。
正确实现方式
按login字段查询单条用户数据不需要手写复杂实现,Spring Data JPA提供了两种极简的正确写法:
方案1:方法名派生查询(无SQL,最推荐)
遵循Spring Data的方法命名规则写方法声明,框架会自动生成对应查询逻辑,不需要手写SQL、不需要写方法实现:
interface MessageRepository : CrudRepository<User, String> { // 原有全表查询方法保留 @Query("select * from users") fun findMessages(): List<User> // 按login查询单条:方法名以findBy开头,后接字段名Login,框架自动生成 where login = ? 的查询 fun findByLogin(login: String): User? }
对应调整Service层的调用逻辑,把原来调用getByUser的位置改为调用findByLogin即可,Controller层代码无需改动。
注意:使用这种写法需要保证
login字段在USERS表中是唯一的,建议给该字段加唯一索引,避免同一个login对应多条数据时再次触发结果集大小不匹配的错误。
方案2:显式声明查询语句
如果需要自定义SQL,直接在@Query注解中写完整逻辑,用命名参数传值,不要写方法体:
interface MessageRepository : CrudRepository<User, String> { @Query("select * from users") fun findMessages(): List<User> // :login 是命名参数占位符,nativeQuery = true 表示执行原生SQL @Query(value = "select * from users where login = :login", nativeQuery = true) fun getByUser(login: String): User? }
这种写法不需要额外写方法实现,框架会自动完成参数绑定、结果映射,也不会存在SQL注入问题。
额外注意事项
- 不要在Service、Repository这类Spring托管的Bean中手动new JdbcTemplate、数据源等组件,要通过构造器注入获取容器中的实例,否则会出现配置不生效、数据库连接泄漏等问题。
- 用户密码禁止明文存储在数据库中,必须加盐哈希后再存储,避免数据泄露造成安全事故。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

