在SpringBoot中,当我们实现JpaRepository接口,就可以对实例进行基本的CRUD操作。同时SpringBoot也提供了以下几种方式来满足一些复杂的查询需求。
- @Query注解
- Named Queries
- Specification and JPA Criteria API
JpaRepository
我们先来看下JpaRepository的实现
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>
- T表示实体
ID 表示实体的主键
JpaRepository的继承层次如下
可以看到JpaRepository实现了基本的CRUD操作,同时由于继承了PagingAndSortingRepository接口,也拥有了分页排序的功能。
下面再来详细说明下上述几种查询方式,我们先定义一个Entity
@Entity
@Getter
@Setter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String address;
private Date birthday;
}
@Query
JPQL与Native Query
@Query支持两种类型的SQL,一种是JPQL,一种是native query,即数据库原生的SQL
@Query中的nativeQuery参数用来标识这两种查询方式,为true表示使用native query,默认为false
两种其中一个区别就是,JPQL将Entity(标有@Entity的类)的名称作为表名,而native query的表名就是数据库中的表名。
排序
对于JPA原生提供的方法,可以直接通过Sort来进行排序
@Repository
public interface UserDao extends JpaRepository<User, Integer>{
}
// 按照name进行倒叙排序
userDao.findAll(new Sort(Sort.Direction.DESC, "name"))
但是native query不支持Sort,只能在SQL中使用order by
@Query(value = "select * from user order by name", nativeQuery = true)
List<User> getUsersOrderByName();
分页
对于JPQL查询,可以直接使用Pageable进行分页
@Query("select u from User order by id")
Page<User> findUsersWithPageable(Pageable pageable);
对于native query,可以通过参数countQuery来实现分页的功能
@Query(value = "select * from user order by id",
countQuery = "select count(*) from user order by id",nativeQuery = true)
Page<User> findWithPage(Pageable pageable);
参数传递
我们可以通过两种方式将方法中的参数传递到查询中
- 通过参数顺序
- 通过参数名称
通过参数顺序
不论是JPQL还是native query,Spring都会按照方法声明中参数出现的顺序传递给查询
@Query("select u from User u where u.name = ?1 and u.address = ?2")
List<User> findUserByNameAndAddress(String name, String address);
@Query("select u from user u where u.name = ?1 and u.address = ?2",nativeQuery=true)
List<User> findUserByNameAndAddress(String name, String address);
通过参数名称
另外我们还可以@Param来传递参数,JPQL与native query的使用姿势一致
@Query("select u from User u where u.name = :name and u.address = :address")
List<User> findUserByNameAndAddressParam(@Param("name") String name,
@Param("address") String address);
@Query("select u from user u where u.name = :name and u.address = :address",nativeQuery=true)
List<User> findUserByNameAndAddressParam(@Param("name") String name,
@Param("address") String address);
Named Querys
Spring JPA支持根据方法名称自动生成查询语句
// 等同于执行SQL:select * from user where name like "%?1%" and address like "%?2%"
List<User> findUserByNameLikeAndAddressLike(String name, String address);
是不是很神奇,Spring JPA是怎么实现这个功能的我会在另外一篇博客中进行展开
Specification and JPA Criteria API
@Query和Named Querys两种方式比较方便简单,但是对于一些动态查询或者更加灵活的查询就不是很适用了,此时就需要Criteria API
JPA Criteria API
@Service
public class UserQueryService {
@Resource
private EntityManager entityManager;
public List<User> findByName(String name){
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
//1. 创建对应entity的query
CriteriaQuery<User> query = builder.createQuery(User.class);
//2. 查询对应的entity
Root<User> root = query.from(User.class);
//3. 查询条件
Predicate predicate = builder.equal(root.get("name"), name);
query.where(predicate);
//4. 执行查询语句
return entityManager.createQuery(query.select(root)).getResultList();
}
}
Specification
Specification在Criteria API上在封装了一层,让SQL语句模块化,并且可读性更强
1.首先需要实现JpaSpecificationExecutor接口
public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor {}
2.创建不同的查询条件
public class UserSpecifications {
// 根据name查询
public static Specification<User> userHasName(String name){
return (Specification<User>) (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("name"),name);
}
// address不为null
public static Specification<User> userAddressNotNull(){
return ((root, query, criteriaBuilder) -> criteriaBuilder.isNotNull(root.get("address")));
}
// 根据birthday查询
public static Specification<User> userBirthday(){
LocalDate today = LocalDate.now();
return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("birthday"),today);
}
}
3.执行语句
userDao.findAll(userHasName("").and(userAddressNotNull()).and(userBirthday())
通过示例可以看到,Specification可以组合不同的Specification进行查询
##参考文献