三 JPA复杂查询的几种方式

Posted joe-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三 JPA复杂查询的几种方式相关的知识,希望对你有一定的参考价值。

多条件查询有很多方式

接口命名策略

按照JPA的命名策略命名,就可以实现单条件或者多条件的等值查询
命名策略 要以find或者findAll开头,单字段查询,find后跟字段的属性名字,参数传入字段的属性类型,多个条件中间用and区分开。

实例:

接口:

Order findByExpressNo(String expressNo);

List<Order> findByUserId(Integer userId);

List<Order> findByUserNameAndUserAddress(String userName, String userAddress);

测试类:

@Test
public void testFindByXXX() {
    //按照订单号查询
    Order order = orderRepository.findByExpressNo("201802215678");
    log.info("按照订单号查询结果:{}", order);

    //按照用户编号查询
    List<Order> orderList = orderRepository.findByUserId(2);
    log.info("按照用户编号查询订单:{}", orderList);

    //按照收货人和收货地址查询
    List<Order> orderList2 = orderRepository.findByUserNameAndUserAddress("张无忌", "光明顶");
    log.info("按照收货人和收货地址查询订单:{}", orderList2);
}

说明:
1).后缀跟的是字段名对应的Java类属性名,不是字段名。

2).定义接口的返回值,要区分开始返回一条记录还是多条记录。如果返回多条记录,用一个记录去接收,会报错。

Predicate构建查询条件

方法:
List<T> findAll(@Nullable Specification<T> var1);
Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);

实例:

@Test
public void testPredicate(){

    Pageable page = PageRequest.of(0, 2, Sort.by(Sort.Direction.DESC, "orderDate"));//按照订单日期倒叙,查询第一页,每页两条数据

    Specification<Order> userSpecification = new Specification<Order>() {
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
            List<Predicate> list = new ArrayList<>();//查询条件集 
            list.add(criteriaBuilder.like(root.get("userName").as(String.class),  "张" + "%"));//收货人以张开头   like
            list.add(criteriaBuilder.equal(root.get("orderStatus").as(String.class), "已完成"));//订单状态为已完成  =
            list.add(criteriaBuilder.ge(root.get("orderAmount").as(BigDecimal.class), new BigDecimal("100")));//订单金额大于100  >
            list.add(criteriaBuilder.isNotNull(root.get("userAddress").as(String.class)));//收货地址不为空  is not null
            return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
        }
    };

    Page<Order> all = orderRepository.findAll(userSpecification, page);
    log.info("条件查询结果:{}",all.getContent());
}

说明:
主要借助CriteriaBuilderPredicate两个类完成拼接条件,
CriteriaBuilder 提供了 .and(且) .or(或) .like(模糊) .equals(=) isNotNull(非空) .ge(大于) 等方法来构造查询条件,具体使用参见实例。

自定义SQL

JPA同样允许自己写SQL操作记录。

实例:

接口:

@Query(value = "select * from order_info where user_name = ?1 and user_address = ?2", nativeQuery = true)
List<Order> selectByNameAndAddress(String name, String address);

@Modifying
@Transactional
@Query(value = "update order_info set user_address = ?1 where order_id = ?2", nativeQuery = true)
void updateAddressByOrderId(String address, Integer orderId);

测试:

@Test
public void testBySQL() {

    //根据名字和地址查询
    List<Order> orders = orderRepository.selectByNameAndAddress("张无忌", "光明顶");
    log.info("自定义SQL根据名字和地址查询:{}", orders);

    //修改订单地址
    orderRepository.updateAddressByOrderId("武当山2114", 1);
}

说明:
1). 自定义SQL可以随便命名方法名

2).需要用@Query注解,如果是更新删除操作还需要有 @Modifying@Transactional 注解

3). SQL里的?表示的占位符,编译和执行的时候,取值是取接口的入参,?后的数字是第几个参数,从0开始

















以上是关于三 JPA复杂查询的几种方式的主要内容,如果未能解决你的问题,请参考以下文章

Golang实践录:查询数据表的几种方式

spring boot + jpa 生成id 的几种方式:

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式