1. 程式人生 > >三 JPA復雜查詢的幾種方式

三 JPA復雜查詢的幾種方式

rspec rep .get 很多 兩個 page 金額 ati con

多條件查詢有很多方式

接口命名策略

按照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復雜查詢的幾種方式