Spring Data Jpa 各种查询方式总结

Spring Data Jpa 各种查询方式总结

Scroll Down

使用Spring Data Jpa接口中定义的方法查询

继承JpaRepository<T, ID>后的方法列表

image.png

其中的大部分已经在上文一一使用,以下只使用之前未被使用的方法。

根据id倒序查询所有用户

@Test
public void test5() {
        // 方式一:使用类型安全的API定义排序表达式
        Sort sort = Sort.sort(User.class).by(User::getId).descending();
        // 方式二:定义排序表达式
        // Sort sort = Sort.by("id").descending(); // 根据id倒序
        List<User> users = userDao.findAll(sort);
        for (User user : users) {
            System.out.println(user);
        }
 }

分页查询

@Test
public void test6() {
        // 同时还能指定第三参数Sort排序
        // 参数:当前页码,每页条数,排序方式(可选)
        PageRequest page = PageRequest.of(1,2);
        Page<User> userPage = userDao.findAll(page);
        System.out.println("总条数="+userPage.getTotalElements());
        System.out.println("总页数="+userPage.getTotalPages());
        System.out.println("当前页码(从0开始)="+userPage.getNumber());
        System.out.println("每页实际条数="+userPage.getNumberOfElements());
        System.out.println("每页条数="+userPage.getSize());
        List<User> users = userPage.getContent();
        for (User user : users) {
            System.out.println(user);
        }
// Hibernate: select user0_.id as id1_0_, user0_.sys_money as sys_mone2_0_, user0_.sys_password as sys_pass3_0_, user0_.sys_username as sys_user4_0_ from sys_user user0_ limit ?, ?
// 总条数=3
// 总页数=2
// 当前页码(从0开始)=1
// 每页实际条数=1
// 每页条数=2
// User(id=4, username=呵呵, password=123, money=0)
}

使用Example<S>构造条件查询

该方式只能简单的查询,复杂查询看得看JpaSpecificationExecutor

根据用户名精确查询

 @Test
public void test7() {
        // 根据用户名精确查询
        User user = new User();
        user.setUsername("张三");
        Example<User> example = Example.of(user);
        List<User> users = userDao.findAll(example);
        for (User u : users) {
            System.out.println(u);
        }
}

User中的属性必须全部为包装类,否则默认不为Null,会被添加到查询条件中。

查询用户名为张开头的用户

@Test
public void test8() {
        // 查询用户名为张开头的用户
        User user = new User();
        user.setUsername("张");
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("username",GenericPropertyMatchers.startsWith());
//                .withMatcher()   还可以添加多个条件
        Example<User> example = Example.of(user,matcher);
        List<User> users = userDao.findAll(example);
        for (User u : users) {
            System.out.println(u);
        }
}

细节:

  • ExampleMatcher.matching() :默认是返回满足全部条件的用户
  • ExampleMatcher.matchingAny() :只要有一个条件满足即可
  • GenericPropertyMatchers.startsWith() : 匹配开头 等价于 like 张%
  • GenericPropertyMatchers.contains() : 匹配中间 等价于 like %张%
  • GenericPropertyMatchers.endsWith() : 匹配结尾 等价于 like %张
  • GenericPropertyMatchers.ignoreCase(boolean b) : 同时还能指定是否忽略大小写

继承JpaSpecificationExecutor<T>后的方法列表

image.png

查询用户名为张三的用户信息

@Test
public void test9() {
        Specification<User> specification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 获取比较的属性
                Path<Object> username = root.get("username");
                // 构造查询条件
                Predicate predicate = criteriaBuilder.equal(username, "张三");
                return predicate;
            }
        };
        List<User> users = userDao.findAll(specification);
        users.forEach(user-> System.out.println(user));
}
  • root : 查询的根对象(查询的任何属性都可以从根对象中获取)
  • criteriaQuery:顶层查询对象,自定义查询方式(了解:一般不用)
  • criteriaBuilder :查询的构造器,封装了很多的查询条件

根据用户名和密码查询用户信息

@Test
public void test10() {
        Specification<User> specification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 获取比较的属性
                Path<Object> username = root.get("username");
                Path<Object> password = root.get("password");
                // 构造查询条件
                Predicate p1 = criteriaBuilder.equal(username, "张三");
                Predicate p2 = criteriaBuilder.equal(password, "222");
                // 把条件组合到一起
                return criteriaBuilder.and(p1,p2);
            }
        };
        List<User> users = userDao.findAll(specification);
        users.forEach(System.out::println);
}

根据用户名模糊查询

@Test
public void test11() {
        Specification<User> specification = new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 获取比较的属性,并指定比较参数的类型String
                Path<String> username = root.get("username");
                // 构造查询条件
                Predicate p1 = criteriaBuilder.like(username, "张%");
                // 把条件组合到一起
                return p1;
            }
        };
        // 根据id倒序排序
        Sort sort = Sort.by("id").descending();
        List<User> users = userDao.findAll(specification,sort);
        users.forEach(System.out::println);
}

使用JPQL的方式查询

使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询

@Query 注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可

public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
    /*
    * 使用jpql语句,根据用户名查询用户信息
    * 使用占位符形式,从1开始取,1说明是取方法的第一个参数
    * */
    @Query("from User where username=?1")
    User findJpql1(String username);
    /*
     * 使用jpql语句,根据用户名和密码查询用户信息
     * 使用命名参数,必须在参数前使用@Param来绑定参数
     * */
    @Query("from User where username=:uname and password=:pwd")
    User findJpql2(@Param("uname") String username,@Param("pwd") String password);
}

此外,也可以通过使用 @Query 来执行一个更新删除操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询

public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
    /*
     * 使用jpql语句 完成更新、删除操作时
     *      - 需要手动添加事务支持,否则会报错
     * 根据id修改用户名
     * */
    @Modifying
    @Query("update User set username=?2 where id=?1")
    void updateJpql(int id,String username);
    
    // 根据id删除用户
    @Modifying
    @Query("delete User where id=?1")
    void insertJpql(int id);
}

使用SQL语句查询

Spring Data JPA同样也支持sql语句的查询,如下:

    /*
    * 使用sql语句查询
    * */
    @Query(value = "select * from sys_user",nativeQuery = true)
    List<User> findSql();

只要在@Query()添加一个配置nativeQuery=true即可,说明此时使用的是本地查询语句而不是jpql语句。

方法命名规则查询

顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询

按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {
    /*
     * 使用方法名规则查询: 是spring data jpa对jpql语句更进一步的封装
     * 根据用户名查询用户信息
     * */
    User findByUsername(String username);
}

方法命名查询更多