Spring Data JDBC派生批量删除查询运行报错问题咨询
Spring Data JDBC 2.3.5 非主键条件批量删除派生查询异常问题
问题复现场景
- 自定义Repository继承
CrudRepository<Customer, Long>,定义派生删除方法,期望删除所有匹配指定businessId的实体。businessId是非主键、允许重复值的非唯一列,单个值可对应多条数据记录。 - 测试逻辑:先持久化2条
businessId相同的Customer记录,再调用如下Repository方法:
fun deleteAllByBusinessId(businessId: Long)
- 调用后抛出异常:
org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 2 at org.springframework.dao.support.DataAccessUtils.nullableSingleResult(DataAccessUtils.java:100) at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:244)
从异常栈可以确认,框架执行删除前先按条件查询单条匹配实体,实际命中2条导致报错,需要确认2.3.5版本是否对这类批量删除派生查询存在支持缺陷。
问题根因
该问题属于Spring Data JDBC 2.3.5版本的已知实现缺陷。
2.3.x版本分支中,派生删除方法的解析逻辑没有正确识别deleteAllByXXX的批量操作语义:无论方法名是否携带All关键字,框架都会默认按单实体删除逻辑处理,先调用queryForObject拉取唯一匹配的实体对象,再执行单条删除操作。只要查询条件命中记录数超过1,就会抛出上述结果集大小不匹配的异常。
该逻辑问题在3.0.0及以上正式版本中才被修复,2.3.x作为旧维护分支没有合入该逻辑调整。
2.3.5版本兼容解决方案
- 方案1:手动编写自定义删除SQL,绕开派生查询的解析缺陷:
@Modifying @Query("DELETE FROM customer WHERE business_id = :businessId") fun deleteAllByBusinessId(businessId: Long)
- 方案2:拆分查询+批量删除两步执行,使用Repository自带的批量删除方法:
// 先在Repository中定义条件查询方法 fun findAllByBusinessId(businessId: Long): List<Customer> // 业务逻辑中执行删除 val matchCustomers = customerRepository.findAllByBusinessId(targetBusinessId) customerRepository.deleteAll(matchCustomers)
内容的提问来源于stack exchange,提问作者user1100243
相关产品推荐
相关产品推荐

