• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • springboot jpa實現多條件動態查詢

    標簽: springboot  jpa

    最近學習了springboot項目,用到了對條件動態查詢,做一些必要的筆記,一來是對自己學習的知識的鞏固,二來對有同樣問題的人有參考作用



    一 原理簡介

    使用Spring Data JPA進行數據操作的時候一般有操作的復雜程度分為三個檔次。

    1、使用Spring Data JPA接口

    JpaRepository繼承于PagingAndSortingRepository,所以它傳遞性地擁有了以上接口的所有方法,同時,它還繼承了另外一個QueryByExampleExecutor接口,擁有了該接口匹配指定樣例的能力,JpaRepository接口定義如下。

    package org.springframework.data.jpa.repository;
     
    import java.io.Serializable;
    import java.util.List;
     
    import javax.persistence.EntityManager;
     
    import org.springframework.data.domain.Example;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.repository.NoRepositoryBean;
    import org.springframework.data.repository.PagingAndSortingRepository;
    import org.springframework.data.repository.query.QueryByExampleExecutor;
     
    @NoRepositoryBean
    public interface JpaRepository<T, ID extends Serializable>
    		extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
     
    	List<T> findAll(); // 查詢所有實體
     
    	List<T> findAll(Sort sort); // 查詢所有實體并排序
     
    	List<T> findAll(Iterable<ID> ids); // 根據ID集合查詢實體
     
    	<S extends T> List<S> save(Iterable<S> entities); // 保存并返回(修改后的)實體集合
     
    	void flush(); // 提交事務
     
    	<S extends T> S saveAndFlush(S entity); // 保存實體并立即提交事務
     
    	void deleteInBatch(Iterable<T> entities); // 批量刪除實體集合
     
    	void deleteAllInBatch();// 批量刪除所有實體
     
    	T getOne(ID id); // 根據ID查詢實體
     
    	@Override
    	<S extends T> List<S> findAll(Example<S> example); // 查詢與指定Example匹配的所有實體
     
    	@Override
    	<S extends T> List<S> findAll(Example<S> example, Sort sort);// 查詢與指定Example匹配的所有實體并排序
     
    }
    

    QueryByExampleExecutor接口允許開發者根據給定的樣例執行查詢操作,接口定義如下。

    package org.springframework.data.repository.query;
     
    import org.springframework.data.domain.Example;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
     
    public interface QueryByExampleExecutor<T> {
     
    	<S extends T> S findOne(Example<S> example); // 查詢與指定Example匹配的唯一實體
     
    	<S extends T> Iterable<S> findAll(Example<S> example); // 查詢與指定Example匹配的所有實體
     
    	<S extends T> Iterable<S> findAll(Example<S> example, Sort sort); // 查詢與指定Example匹配的所有實體并排序
     
    	<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);// 分頁查詢與指定Example匹配的所有實體
     
    	<S extends T> long count(Example<S> example); // 查詢與指定Example匹配的實體數量
     
    	<S extends T> boolean exists(Example<S> example); // 判斷與指定Example匹配的實體是否存在
    }
    

    以部門實體資源庫接口DepartmentRepository為例,只需繼承CrudRepository接口便會自動擁有基礎的增刪查改功能,無須編寫一條SQL。

    @Repository
    public interface DepartmentRepository extends CrudRepository<Department, Long> {
     
    }
    

    2、自定義查詢方法

    除了可以直接使用Spring Data JPA接口提供的基礎功能外,Spring Data JPA還允許開發者自定義查詢方法,對于符合以下命名規則的方法,Spring Data JPA能夠根據其方法名為其自動生成SQL,除了使用示例中的 find 關鍵字,還支持的關鍵字有:query、get、read、count、delete等。

    在這里插入圖片描述
    另外,Spring Data JPA 還提供了對分頁查詢、自定義SQL、查詢指定N條記錄、聯表查詢等功能的支持,以員工實體資源庫接口EmployeeRepository為例,功能代碼示意如下。

    @Repository
    public interface EmployeeRepository extends JpaRepository<Employee, Long> {
     
    	/**
    	 * 根據部門ID獲取員工數量
    	 */
    	int countByDepartmentId(Long departmentId);
     
    	/**
    	 * 根據部門ID分頁查詢
    	 */
    	Page<Employee> queryByDepartmentId(Long departmentId, Pageable pageable);
     
    	/**
    	 * 根據員工ID升序查詢前10條
    	 */
    	List<Employee> readTop10ByOrderById();
     
    	/**
    	 * 根據員工姓名取第一條記錄
    	 */
    	Employee getFirstByName(String name, Sort sort);
     
    	/**
    	 * 聯表查詢
    	 */
    	@Query("select e.id as employeeId,e.name as employeeName,d.id as departmentId,d.name as departmentName from Employee e , Department d where e.id= ?1 and d.id= ?2")
    	EmployeeDetail getEmployeeJoinDepartment(Long eid, Long did);
     
    	/**
    	 * 修改指定ID員工的姓名
    	 */
    	@Modifying
    	@Transactional(timeout = 10)
    	@Query("update Employee e set e.name = ?1 where e.id = ?2")
    	int modifyEmployeeNameById(String name, Long id);
     
    	/**
    	 * 刪除指定ID的員工
    	 */
    	@Transactional(timeout = 10)
    	@Modifying
    	@Query("delete from Employee where id = ?1")
    	void deleteById(Long id);
     
    }
    

    3、Specification進行多條件動態查詢

    在使用Spring Data JPA的時候,只要我們的Repo層繼承JpaSpecificationExecutor接口就可以使用Specification進行多條件動態查詢了,我們先看下JpaSpecificationExecutor接口:

    public interface JpaSpecificationExecutor<T> {
        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);
    }
    

    可以看到提供了5個方法,方法的參數和返回值已經很明顯的表達了其意圖。其中的參數,PageableSort應該是比較簡單的,分別是分頁參數和排序參數,而重點就是Specification參數,先看下這個接口的定義:

    public interface Specification<T> {
        Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
    }
    

    其中就一個方法,返回的是動態查詢的數據結構。

    javax.persistence.criteria.Predicate toPredicate(javax.persistence.criteria.Root<T> root,
    javax.persistence.criteria.CriteriaQuery<?> query,
    javax.persistence.criteria.CriteriaBuilder cb);
    

    這里使用的都是Java EE中的規范,具體實現本人采用的是Hibernate,當然也可以選擇其他實現了JPA規范的數據持久層框架。

    這里需要再次回過頭看看Criteria API中的一些東西:

    Predicate類:一個簡單或復雜的謂詞類型,用來拼接條件。

    Criteria 查詢是以元模型的概念為基礎的,元模型是為具體持久化單元的受管實體定義的,這些實體可以是實體類,嵌入類或者映射的父類。

    Root接口:代表Criteria查詢的根對象,能夠提供查詢用到的數據庫字段

    CriteriaQuery接口:代表一個specific的頂層查詢對象,用來執行最后的操作,它包含著查詢的各個部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery對象只對實體類型或嵌入式類型的Criteria查詢起作用

    CriteriaBuilder接口:表示具體的比較條件。

    其中支持的方法非常之強大,下面給出一個示例,大家可以參考一下,同樣的,可以根據示例,自己可以寫出更為復雜的查詢。

    二 代碼舉例

    1、問題描述

    使用jpa實現多條件分頁動態查詢用戶數據。

    2、實體類

    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    import javax.persistence.*;
    
    @Entity
    @EntityListeners(AuditingEntityListener.class)
    public class User {
        
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        private String sex;
    
        private String phone;
    
        private Integer age;
    
        public User() {
        }
    
        public User(String name, String sex, String phone, Integer age) {
            this.name = name;
            this.sex = sex;
            this.phone = phone;
            this.age = age;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", sex='" + sex + '\'' +
                    ", phone='" + phone + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    2、JPA代碼

    import com.wyh.jpatest.entity.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    
    public interface UserRepository extends JpaRepository<User, Long>,  JpaSpecificationExecutor<User> {
    }
    

    3、Service接口和Service實現類

    接口代碼:

    mport com.wyh.jpatest.entity.User;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    
    public interface UserService {
        Page<User> findByCondition(Integer page,  Integer size, String sex, Integer ageBegin, Integer ageEnd);
    }
    

    接口實現類代碼:

    import com.wyh.jpatest.dao.UserRepository;
    import com.wyh.jpatest.entity.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;
    
    import javax.persistence.criteria.Predicate;
    import java.util.ArrayList;
    import java.util.List;
    
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserRepository userRepository;
    
        @Override
        public Page<User> findByCondition(Integer page,  Integer size, String sex, Integer ageBegin, Integer ageEnd) {
            Pageable pageable = PageRequest.of(page, size);
            return userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<Predicate>();
    
                if (!StringUtils.isEmpty(sex)){             //性別
                    predicates.add(criteriaBuilder.equal(root.get("sex"),sex));
                }
    
                if (ageBegin != null){          //年齡大于ageBegin
                    predicates.add(criteriaBuilder.greaterThan(root.get("age"),ageBegin));
                }
    
                if (ageEnd != null){            //年齡小于ageEnd
                    predicates.add(criteriaBuilder.lessThan(root.get("age"),ageEnd));
                }
    
                return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            },pageable);
        }
    }
    

    4、Controller層

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @RestController
    public class UserController {
        @Autowired
        private UserService userService;
    
        //page表示頁數,默認是第0頁
        //size表示每頁顯示條數,默認顯示10條
        @PostMapping
        public Object findByCondition(@RequestParam(value = "page", defaultValue = "0") Integer page,
                                @RequestParam(value = "size", defaultValue = "10") Integer size,
                                @RequestParam(value = "sex", defaultValue = "男") String sex,
                                @RequestParam(value = "ageBegin") Integer ageBegin,
                                @RequestParam(value = "ageEnd") Integer ageEnd){
             List<User> list = userService.findByCondition(page, size, sex, ageBegin, ageEnd).getContent();
             Map<String, Object> map = new HashMap();
             map.put("num", list.size());
             map.put("listData", list);
    
             return map;
        }
    }
    

    5、application.properties配置代碼

    spring.datasource.url=jdbc:mysql://localhost:3306/jpa?characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2b8
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.jpa.database=mysql
    spring.jpa.show-sql=true
    spring.jpa.hibernate.ddl-auto=update
    

    6、測試結果

    查詢年齡大于14,小于30,性別為男的用戶,并返回第0頁的數據,每頁顯示設置為3條數據。

    在這里插入圖片描述


    三 總結

    如有錯誤懇請指正,如有侵權請聯系我刪除
    參考文章: Spring Boot使用JPA多條件查詢mysql
                    springboot jpa實現多條件動態查詢
                    SpringBoot重點詳解–使用JPA操作數據庫

    版權聲明:本文為qq_39007083原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_39007083/article/details/106888268

    智能推薦

    SpringBoot+Jpa實現Excel的導入導出(動態Sql、分頁查詢、聯表join)

    Excel (SpringBoot + JPA)   最近做了一個項目甲方需求中要求數據的導入導出到Excel文件,Excel的復雜表頭和數據格式一直是個頭疼的問題,使用poi或者jexcelapi的話就需要花費大量時間處理表頭以及數據格式問題,但是整個項目的開發時間只有一周,對接和聯調一周,那就只能去找快速的“黑科技”了–EasyExcel...

    JPA 多表多條件分頁查詢

    業務場景:  主表:訂單表,與客戶表、產品表、物流表存在一對一關系,映射字段為id,現需要根據訂單編號、訂單日期、客戶名稱、客戶編號、產品名稱、產品編號、快遞單號查詢該筆訂單,需要支持模糊查詢和分頁。 Order實體類中的需要進行一對一關系映射: Dao中的需要繼承JpaRepository,JpaSpecificationExecuto兩個接口: Service中的寫法:  ...

    JPA多表多條件查詢解決思路

    JPA單表多條件查詢 可以在Service層使用Predicate實現 ServiceImpl實現類,查詢條件可以自定義 JPA多表多條件查詢 如果針對多表多條件查詢,可以使用原生SQL實現 使用EntityManager定義多條件查詢 在服務實現類中注入EntityManager,自定義HQL查詢數據,并且可以通過多表數據組裝對象 JPA多表數據組織實體對象 需要在JPQL中使用構造方法創建對象...

    Unity_Shader高級篇_13.1_Unity Shader入門精要

    13.4 再談邊緣檢測 在12.3中,我們曾使用Sobel算子對屏幕圖像進行邊緣測試,實現描邊的效果。但是,這種直接利用顏色信息進行邊緣檢測的方法會產生很對我們不希望得到的邊緣線,如圖13.8所示。 可以看出,物體的紋理、陰影等位置也被描上黑邊,而這往往不是我們希望看到的。在本節中,我們將學習如何在深度和法線上進行邊緣檢測,這些圖像不會受紋理和光照的影響,而僅僅保存了當前渲染物體的模型信息,通過這...

    Seata AT 模式 原理詳解

    目錄 前提 整體機制 寫隔離 讀隔離 工作機制 一階段 二階段-回滾 二階段-提交 附錄 回滾日志表 前提 基于支持本地 ACID 事務的關系型數據庫。 Java 應用,通過 JDBC 訪問數據庫。 整體機制 兩階段提交協議的演變: 一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。 二階段: 提交異步化,非常快速地完成。 回滾通過一階段的回滾日志進行反向補償。 寫隔離 ...

    猜你喜歡

    Python爬蟲 | 滑動驗證碼**

    極驗驗證碼:需要手動拼合滑塊來完成的驗證,相對圖形驗證碼識別難度上升了幾個等級。下面用程序識別并通過極驗驗證碼的驗證,其中有分析識別思路、識別缺口位置、生成滑塊拖動、模擬實現滑塊拼合通過驗證等步驟。需要用到Chrome 瀏覽器,并配置 ChromeDriver ,要用到的 Python 庫是 Selenium。 1、 對極驗驗證碼了解   極驗驗證碼官網:http://www.geetest.co...

    MobaXterm root用戶連接虛擬機時出現Access denied

    1.linux打開ssh服務 2.新建連接 首先在romote host中填入要連接的主機ip specify username中填入連接的用戶名 port為連接端口默認為22 輸入連接用戶的密碼 linux默認不顯示密碼 發現密碼正確但是連接不上 問題解決 /etc/ssh/sshd_config 配置問題: #PermitRootLogin prohibit-password將該行改為Perm...

    Linux C 預處理命令

    預處理命令 一、宏定義 C語言標準允許在程序中用一個標識符來表示一個字符串,成為宏。標識符為宏名 ,在編譯預處理時,將程序中所有的宏名用相應的字符串來替換,這個過程稱為宏替換,宏分為兩種:無參數的宏和有參數的宏。 1.無參數的宏 無參數宏定義的一般形式為:#define 標識符字符串 “#”代表本行是編譯預處理命令。define是宏定義的關鍵詞,標識符是宏名。字符串是宏名所...

    有意思的算法(一)----冒泡排序

        冒泡排序的基本思想是:每次比較兩個相鄰的元素,如果它們的順序錯誤就把他們交換過來。     下面舉一個具體的例子來介紹一下冒泡排序。     有12,35,99,18,76五個數進行從大到小的排序,既然是從大到小排序,也就是說越小的越靠后,可不要把這句當成廢話,這可是最關...

    cordova學習筆記_創建一個cordova項目

    環境和工具 webstorm Node.js JDK git 打開git bash,進入你要創建項目的目錄,鍵入以下命令 進入cordovaDemo這個文件夾: 添加Android平臺 cordova platforms add android platforms中已經有了一個Android平臺 下面打開webstorm,然后file - open 找到cordovaDemo打開 現在在webst...

    精品国产乱码久久久久久蜜桃不卡