Spring Boot升级至2.7.16后DepartmentRepository出现findAll属性不存在报错
问题原因分析
Spring Boot 2.7.16对应的Spring Data JPA版本中,CrudRepository接口已内置两个findAll方法:
Iterable<T> findAll():无参查询所有实体Iterable<T> findAll(Iterable<ID> ids):根据ID集合查询实体
你的自定义DepartmentRepository中,两个findAll方法与父接口方法存在冲突:
- 无参
List<Department> findAll():虽然返回值是父接口方法的协变类型,但Spring Data升级后的解析逻辑会将其误判为自定义查询方法,尝试解析findAll对应的实体属性,导致报错。 - 带参
Iterable<Department> findAll(Iterable<Long> deptIds):与父接口方法签名完全一致,但未添加@Override注解,Spring Data会将其当作需要生成查询的自定义方法,而非继承父接口的实现,进而触发属性查找错误。
而Spring Boot 1.5.3对应的旧版Spring Data JPA解析逻辑更宽松,允许此类重写或重复定义,因此原代码可正常运行。
解决方案
以下三种方案任选其一:
方案一:改用JpaRepository替代CrudRepository
JpaRepository继承自CrudRepository,且默认findAll()返回List<T>,无需自定义重复方法,同时保留所有CRUD能力:
import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.auth.middleware.domain.Department; @Repository public interface DepartmentRepository extends JpaRepository<Department, Long> { Department findByDeptId(Long deptId); Department findByDeptName(String deptName); void deleteByDeptId(Long deptId); }
方案二:重命名自定义方法避免冲突
如果需要保留CrudRepository,可修改自定义方法名,同时调整业务代码中的调用:
import java.util.List; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.auth.middleware.domain.Department; @Repository public interface DepartmentRepository extends CrudRepository<Department, Long> { @Transactional(timeout = 8) List<Department> findAllDepartments(); Department findByDeptId(Long deptId); Department findByDeptName(String deptName); void deleteByDeptId(Long deptId); @Transactional(timeout = 8) Iterable<Department> findAllByIds(Iterable<Long> deptIds); }
方案三:添加@Override注解明确重写父接口方法
通过@Override告诉Spring Data这是重写父接口的方法,而非自定义查询方法,同时保留事务注解:
import java.util.List; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.auth.middleware.domain.Department; @Repository public interface DepartmentRepository extends CrudRepository<Department, Long> { @Override @Transactional(timeout = 8) List<Department> findAll(); Department findByDeptId(Long deptId); Department findByDeptName(String deptName); void deleteByDeptId(Long deptId); @Override @Transactional(timeout = 8) Iterable<Department> findAll(Iterable<Long> deptIds); }
内容的提问来源于stack exchange,提问作者Sreejesh
相关产品推荐
相关产品推荐

