在现有项目结构下,如何无需实现即可使用JPA默认findAll方法?
嘿,我来帮你拆解一下这个问题,其实核心是Spring Data JPA的接口实现机制在搞事情~
第一个问题:能不能无需实现就使用CrudRepository的默认findAll/findById方法?
答案是完全可以,但你现在的实现方式不对,导致覆盖了Spring的默认实现。
你现在让UserDAOImpl直接实现了UserDAO(而UserDAO继承自CrudRepository),这就意味着你必须手动实现UserDAO里的所有方法——包括CrudRepository自带的findAll、findById。这就是为什么你现在这两个方法返回null,因为你没实现它们,而Spring的默认代理实现被你的自定义Impl覆盖了。
正确的做法是用Spring Data JPA的自定义实现拆分机制,步骤如下:
- 保留
UserDAO继承CrudRepository,里面放你的查询方法(比如带@NamedQuery的findAllQuery、findByIdQuery) - 新建一个自定义接口,比如
UserDAOCustom,里面只放你需要自己写逻辑的方法(如果有的话) - 让
UserDAO继承UserDAOCustom - 写
UserDAOCustomImpl来实现UserDAOCustom,而不是直接实现UserDAO
这样一来,CrudRepository的默认方法(findAll、findById)会由Spring动态生成代理实现,你的自定义逻辑只在UserDAOCustomImpl里维护,两者互不干扰,完全不需要你手动实现默认方法。
第二个问题:除了EntityManager,还有其他方式使用JPA默认findAll方法吗?
除了上面说的标准拆分方式,还有两种可选方案:
方案1:让自定义Impl继承SimpleJpaRepository
Spring Data JPA的默认方法其实都是在SimpleJpaRepository里实现的,你可以让你的UserDAOImpl直接继承这个类,复用它的默认实现:
public class UserDAOImpl extends SimpleJpaRepository<User, Long> implements UserDAO { public UserDAOImpl(JpaEntityInformation<User, Long> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); } // 这里只需要实现你自己的自定义方法,findAll/findById会自动复用父类的实现 }
不过这种方式需要处理构造函数依赖,相对拆分接口的方式来说没那么灵活。
方案2:避免直接实现主Repository接口
如果你只是想给UserDAO加一些自定义方法,完全没必要让Impl类直接实现UserDAO。坚持用拆分自定义接口的方式,是Spring Data JPA官方推荐的最佳实践,既能保留默认方法,又能清晰分离自定义逻辑。
总结一下,最省心的方式就是用自定义接口+Impl的拆分模式,这样你既不用实现默认方法,又能正常使用CrudRepository自带的所有功能,和你之前没加UserDAOImpl时的体验完全一致。
内容的提问来源于stack exchange,提问作者moroyoung11

