一、引言
Spring Data JPA provides repository support for the Jakarta Persistence API (JPA). It eases development of applications with a consistent programming model that need to access JPA data sources.
Spring Data JPA为Jakarta Persistence API (JPA)提供了存储库支持。它简化了使用需要访问JPA数据源的一致编程模型的应用程序的开发。
Spring Data JPA旨在简化基于JPA(Jakarta Persistence API)的数据访问层开发。通过使用Spring Data JPA,开发者可以更加专注于业务逻辑的实现,而无需过多关注底层数据访问的细节。这有助于提高开发效率,减少错误和重复工作,使项目更加易于维护和扩展。
二、核心接口
- CrudRepository Interface
最最核心接口,提供了Crud功能。
Crud: c(creat) r(read) u(update) d(deletd)
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
// … more functionality omitted.
}
保存给定的实体。
返回由给定ID标识的实体。
返回所有实体。
返回实体的数量。
删除给定实体。
指示给定ID的实体是否存在。
PagingAndSortingRepository interface
该接口添加了额外的方法来简化对实体的分页访问。public interface PagingAndSortingRepository<T, ID> { Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable); }
其中,findAll(Sort sort) 不会返回分页的结果,而是返回所有匹配的记录(尽管它们会按照指定的顺序返回)。如果你需要分页和排序的结果,你应该使用 findAll(Pageable pageable) 方法,其中 Pageable 对象可以同时包含分页和排序信息。
三、规范
上述提到的方法确实能够满足大部分简单的增删改查功能,但对于涉及多表连接的综合查询,这些方法可能无法直接实现。在这种情况下,Spring Data JPA 提供了JpaSpecificationExecutor 接口,用于构建复杂的查询条件,从而支持多表连接和更高级别的数据检索需求。
public interface JpaSpecificationExecutor<T> {
Optional<T> findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
boolean exists(Specification<T> spec);
long delete(Specification<T> spec);
<S extends T, R> R findBy(Specification<T> spec, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
}
返回由给定 Specification 匹配的单个实体。
返回由给定 Specification 匹配的所有实体的列表。
返回与给定 Specification 匹配的实体的分页列表。Pageable 对象定义了分页信息。
根据给定的 Specification 查找实体,并根据 Sort 对象对结果进行排序。
返回与给定 Specification 匹配的实体的数量。
是否存在与给定 Specification 匹配的实体。
删除与给定 Specification 匹配的所有实体,并返回被删除实体的数量。
Specification接口定义如下:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
当使用JpaSpecificationExecutor时,通常会结合Specification接口来构建查询条件。Specification 这个规范就需要我们根据自己的需求灵活的设计,已满足特定的查询。
四、示例
定义实体:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
// getters and setters
}
仓库层:
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User>, {
// 通过定义接口方法来声明自定义的查询
// Spring Data JPA提供了基于方法名的查询创建功能,允许你根据定义的方法名自动生成查询语句。
User findByUsername(String username);
}
Specification接口:
public class UserSpecifications {
public static Specification<User> containingName(String name) {
return new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("name").as(String.class), String.format("%s%%", name));
}
};
}
}
上面这段代码可以用Lambda表达式简化为:
public static Specification<User> containingName(String name) {
return (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("name").as(String.class), String.format("%s%%", name));
}
service层:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User findUserByUsername(String username) {
return userRepository.findByUsername(username);
}
default Page<Account> page(String name, @NotNull Pageable pageable) {
Specification<User> specification = AccountSpecs.containingName(name);
return this.findAll(specification, pageable);
}
}
五、总结
toPredicate方法是Specification接口的核心方法,可以使用它定义复杂的查询条件。
灵活使用Specification接口几乎可以满足所有复杂的综合查询,所以不必使用@query注解手写sql语句,容易出错。
Lambda表达式可以简化代码。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。