Spring JPA:如何创建仅含查询方法、无CRUD操作的JpaRepository?
这确实是个非常实用的场景——当已经有专门的仓库负责实体的增删改操作时,我们当然不想让统计类仓库带上一堆多余的CRUD方法,既显得冗余还容易误调用。Spring JPA完全有优雅的解决方案,根本不需要去重写方法抛异常,下面给你两个最常用的实现方式:
方案1:自定义只读基础仓库(推荐,可扩展)
首先创建一个标记为@NoRepositoryBean的基础接口,告诉Spring不要把它当作可实例化的仓库,你可以在里面放一些通用的只读方法(如果需要的话),也可以留空:
@NoRepositoryBean public interface ReadOnlyRepository<T, ID> extends Repository<T, ID> { // 这里可以按需添加通用只读方法,比如: // Optional<T> findById(ID id); }
然后让你的统计仓库继承这个自定义的只读接口,而不是JpaRepository:
@Repository public interface StatisticRepo extends ReadOnlyRepository<PaymentList, Long> { @Query("SELECT pd.date, SUM(pd.totalPayment) " + "FROM PaymentDetails pd WHERE pd.date BETWEEN :date_from AND :date_until " + "GROUP BY pd.date") List<Object[]> getDailyExpensesStatistic(@Param("date_from") Date dateFrom, @Param("date_until") Date dateUntil); }
这样你的StatisticRepo就只会包含你自己定义的统计查询方法,完全没有CRUD相关的方法,干净又安全。
方案2:直接继承顶层Repository接口
如果你的统计仓库连通用的只读方法都不需要,那就更简单了——直接让仓库继承Spring Data最顶层的Repository<T, ID>接口,它本身没有任何默认方法,所以你的仓库只会有你自定义的@Query方法:
@Repository public interface StatisticRepo extends Repository<PaymentList, Long> { @Query("SELECT pd.date, SUM(pd.totalPayment) " + "FROM PaymentDetails pd WHERE pd.date BETWEEN :date_from AND :date_until " + "GROUP BY pd.date") List<Object[]> getDailyExpensesStatistic(@Param("date_from") Date dateFrom, @Param("date_until") Date dateUntil); }
补充说明
之前你用JpaRepository会带上CRUD方法,是因为JpaRepository继承了CrudRepository和PagingAndSortingRepository,这两个接口自带了全套的增删改查及分页排序方法。而我们选择的Repository或自定义ReadOnlyRepository则完全避开了这些冗余方法,完美适配纯统计查询的场景。
另外,建议把返回值List改成List<Object[]>,因为你的查询返回了两个字段(日期和总金额),用泛型可以让类型更安全,后续处理结果时也更清晰。
内容的提问来源于stack exchange,提问作者Юрий Яхница

