4

一、引言

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,开发者可以更加专注于业务逻辑的实现,而无需过多关注底层数据访问的细节。这有助于提高开发效率,减少错误和重复工作,使项目更加易于维护和扩展。

二、核心接口

  1. 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的实体是否存在。
  1. 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表达式可以简化代码。


吴季分
345 声望12 粉丝

引用和评论

0 条评论