Spring Data JPA——原理剖析、Spring Data JPA的四種查詢方式

目錄


一、Spring Data JPA的內部原理剖析

跳轉到目錄

1、Spring Data JPA的常用接口分析

在客戶的案例中,我們發現在自定義的CustomerDao中,並沒有提供任何方法就可以使用其中的很多方法,那麼這些方法究竟是怎麼來的呢?答案很簡單,對於我們自定義的Dao接口,由於繼承了JpaRepositoryJpaSpecificationExecutor,所以我們可以使用這兩個接口的所有方法。
在這裏插入圖片描述
在使用Spring Data JPA時,一般實現JpaRepository和JpaSpecificationExecutor接口,這樣就可以使用這些接口中定義的方法,但是這些方法都只是一些聲明,沒有具體的實現方式,那麼在 Spring Data JPA中它又是怎麼實現的呢?

2、Spring Data JPA的實現過程

  • 通過對客戶案例,以debug斷點調試的方式,通過分析Spring Data JPA的原來來分析程序的執行過程

在這裏插入圖片描述
斷點執行到方法上時,我們可以發現注入的customerDao對象,本質上是通過JdkDynamicAopProxy生成的一個代理對象

  • 代理對象中方法調用的分析

當程序執行的時候,會通過JdkDynamicAopProxy的invoke方法,對customerDao對象生成動態代理對象。根據對Spring Data JPA介紹而知,要想進行findOne查詢方法,最終還是會出現JPA規範的API完成操作,那麼這些底層代碼存在於何處呢?答案很簡單,都隱藏在通過JdkDynamicAopProxy生成的動態代理對象當中,而這個動態代理對象就是SimpleJpaRepository

在這裏插入圖片描述
通過SimpleJpaRepository的源碼分析,定位到了findOne方法,在此方法中,返回em.find()的返回結果,那麼em又是什麼呢?
在這裏插入圖片描述
帶着問題繼續查找em對象,我們發現em就是EntityManager對象,而他是JPA原生的實現方式,所以我們得到結論Spring Data JPA只是對標準JPA操作進行了進一步封裝,簡化了Dao層代碼的開發;

3、Spring Data JPA完整的調用過程分析

在這裏插入圖片描述

二、Spring Data JPA的查詢方式

1、使用Spring Data JPA中接口定義的方法進行查詢

跳轉到目錄
在繼承JpaRepository,和JpaRepository接口後,我們就可以使用接口中定義的方法進行查詢
在這裏插入圖片描述

2、使用JPQL的方式查詢

跳轉到目錄
使用Spring Data JPA提供的查詢方法已經可以解決大部分的應用場景,但是對於某些業務來說,我們還需要靈活的構造查詢條件,這時就可以使用@Query註解,結合JPQL的語句方式完成查詢;

@Query 註解的使用非常簡單,只需在方法上面標註該註解,同時提供一個JPQL查詢語句即可

public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {

    /**
     * 案例: 根據客戶名稱查詢客戶
     *      使用jpql的形式查詢
     * jpql: from Customer where custName = ?
     *
     * 配置jpql語句, 使用@Query註解
     */
    @Query("from Customer where custName = ?")
    public Customer findJpql(String custName);

    /**
     * 案例:根據客戶名稱和客戶id查詢客戶
     *      jpql: from Customer where custName = ? and custId = ?
     *
     *  對於多個佔位符參數
     *      賦值的時候,默認的情況下,佔位符的位置需要和方法參數中的位置保持一致
     *
     *  可以指定佔位符參數的位置
     *      ? 索引的方式,指定此佔位的取值來源
     */
    // @Query("from Customer where custName = ? and custId = ?")
    // public Customer findCustNameAndId(String name, Long id);
    @Query("from Customer where custName = ?2 and custId = ?1")
    public Customer findCustNameAndId(Long id, String name);

    /**
     * 使用jpql完成更新操作
     *      案例 : 根據id更新,客戶的名稱
     *          更新4號客戶的名稱,將名稱改爲“黑馬程序員”
     *
     *  sql  :update cst_customer set cust_name = ? where cust_id = ?
     *  jpql : update Customer set custName = ? where custId = ?
     *
     *  @Query : 代表的是進行查詢
     *      * 聲明此方法是用來進行更新操作
     *  @Modifying
     *      * 當前執行的是一個更新操作
     *
     */
    @Query("update Customer set custName = ?2 where custId = ?1")
    @Modifying
    public void updateCustomer(long custId,String custName);
}

測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JpqlTest {

    @Autowired
    private CustomerDao customerDao;

    @Test
    public void testFindJPQL() {
        Customer customer = customerDao.findJpql("bb");
        System.out.println("customer = " + customer);
    }

    @Test
    public void testFindNameAndId() {
        // Customer customer = customerDao.findCustNameAndId("gzy1", 2L);
        Customer customer = customerDao.findCustNameAndId(2L, "gzy1");
        System.out.println("customer = " + customer);
    }

    /**
     * 測試jpql的更新操作
     *  * springDataJpa中使用jpql完成 更新/刪除操作
     *         * 需要手動添加事務的支持
     *         * 默認會執行結束之後,回滾事務
     *   @Rollback : 設置是否自動回滾
     *          false | true
     */
    @Test
    @Transactional //添加事務的支持
    @Rollback(value = false)
    public void testUpdateCustomer() {
        customerDao.updateCustomer(4L,"桂朝陽");
    }
}

此外,也可以通過使用 @Query 來執行一個更新操作,爲此,我們需要在使用 @Query 的同時,用 @Modifying 來將該操作標識爲修改查詢,這樣框架最終會生成一個更新的操作,而非查詢

3、使用SQL語句查詢

跳轉到目錄
Spring Data JPA同樣也支持sql語句的查詢,如下:

public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
	/**
     * 使用sql的形式查詢:
     *     查詢全部的客戶
     *  sql : select * from cst_customer;
     *  Query : 配置sql查詢
     *      value : sql語句
     *      nativeQuery : 查詢方式
     *          true : sql查詢
     *          false:jpql查詢
     *
     */
    @Query(value = "select * from cst_customer", nativeQuery = true)
    public List<Object[]> findSql();

    /**
     * 根據條件來查詢
     */
    @Query(value = "select * from cst_customer where cust_name like ?1", nativeQuery = true)
    public List<Object[]> findSqlCondition(String likeName);
}

測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JpqlTest {

	@Autowired
    private CustomerDao customerDao;

	//測試sql查詢
    @Test
    public void testFindSql() {
        List<Object[]> list = customerDao.findSql();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
    }

    // 根據條件來查詢
    @Test
    public void testFindSqlCondition() {
        List<Object[]> objs = customerDao.findSqlCondition("g%");
        for (Object[] obj : objs) {
            System.out.println(Arrays.toString(obj));
        }
    }
}

4、使用方法命名規則查詢

跳轉到目錄
顧名思義,方法命名規則查詢就是根據方法的名字,就能創建查詢。只需要按照Spring Data JPA提供的方法命名規則定義方法的名稱,就可以完成查詢工作。Spring Data JPA在程序執行的時候會根據方法名稱進行解析,並自動生成查詢語句進行查詢

按照Spring Data JPA 定義的規則,查詢方法以findBy開頭,涉及條件查詢時,條件的屬性用條件關鍵字連接,要注意的是:條件屬性首字母需大寫。框架在進行方法名解析時,會先把方法名多餘的前綴截取掉,然後對剩下部分進行解析。

  • findBy + 屬性名稱 (根據屬性名稱進行完成匹配的查詢=)

  • findBy + 屬性名稱 + “ 查詢方式(Like | isnull)”

  • 多條件查詢
    findBy + 屬性名 + “查詢方式” + “多條件的連接符(and|or)” + 屬性名 + “查詢方式”

public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
    /**
     * 方法名的約定:
     *      findBy : 查詢
     *            對象中的屬性名(首字母大寫) : 查詢的條件
     *            CustName
     *            * 默認情況 : 使用 等於的方式查詢
     *                  特殊的查詢方式
     *
     *  findByCustName   --   根據客戶名稱查詢
     *
     *  再springdataJpa的運行階段
     *          會根據方法名稱進行解析  findBy    from  xxx(實體類)
     *                                      屬性名稱      where  custName =
     *
     *
     *      1.findBy  + 屬性名稱 (根據屬性名稱進行完成匹配的查詢=)
     *
     *      2.findBy  + 屬性名稱 + “查詢方式(Like | isnull)”
     *          findByCustNameLike
     *
     *      3.多條件查詢
     *          findBy + 屬性名 + “查詢方式”   + “多條件的連接符(and|or)”  + 屬性名 + “查詢方式”
     */

    // 根據名稱查詢
    public Customer findByCustName(String custName);

    //使用客戶名稱模糊匹配查詢
    public List<Customer> findByCustNameLike(String custName);

    //使用客戶名稱模糊匹配和客戶所屬行業精準匹配的查詢
    public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);
}

測試

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class JpqlTest {

    // 測試方法命名規則的查詢
    @Test
    public void testNaming() {
        Customer custName = customerDao.findByCustName("gzy1");
        System.out.println("custName = " + custName);
    }

    @Test
    public void testFindByCustNameLike() {
        List<Customer> list = customerDao.findByCustNameLike("g%");
        for (Customer customer : list) {
            System.out.println("customer = " + customer);
        }
    }

    @Test
    public void testFindByCustNameLikeAndCustIndustry() {
        Customer customer = customerDao.findByCustNameLikeAndCustIndustry("g%", "leaf");
        System.out.println("customer = " + customer);
    }
}

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

三、總結

跳轉到目錄

* SpringDataJpa

第一 springDataJpa的概述

第二 springDataJpa的入門操作
	案例:客戶的基本CRUD
	i.搭建環境
		創建工程導入座標
		配置spring的配置文件(配置spring Data jpa的整合)
		編寫實體類(Customer),使用jpa註解配置映射關係
	ii.編寫一個符合springDataJpa的dao層接口
		* 只需要編寫dao層接口,不需要編寫dao層接口的實現類
		* dao層接口規範
			1.需要繼承兩個接口(JpaRepository,JpaSpecificationExecutor)
			2.需要提供響應的泛型
	
	* 
		findOne(id) :根據id查詢
		save(customer):保存或者更新(依據:傳遞的實體類對象中,是否包含id屬性)
		delete(id) :根據id刪除
		findAll() : 查詢全部

第三 springDataJpa的運行過程和原理剖析
	1.通過JdkDynamicAopProxy的invoke方法創建了一個動態代理對象
	2.SimpleJpaRepository當中封裝了JPA的操作(藉助JPA的api完成數據庫的CRUD)
	3.通過hibernate完成數據庫操作(封裝了jdbc)


第四 複雜查詢
	i.藉助接口中的定義好的方法完成查詢
		findOne(id):根據id查詢
	ii.jpql的查詢方式
		jpql : jpa query language  (jpq查詢語言)
		特點:語法或關鍵字和sql語句類似
			查詢的是類和類中的屬性
			
		* 需要將JPQL語句配置到接口方法上
			1.特有的查詢:需要在dao接口上配置方法
			2.在新添加的方法上,使用註解的形式配置jpql查詢語句
			3.註解 : @Query

	iii.sql語句的查詢
			1.特有的查詢:需要在dao接口上配置方法
			2.在新添加的方法上,使用註解的形式配置sql查詢語句
			3.註解 : @Query
				value :jpql語句 | sql語句
				nativeQuery :false(使用jpql查詢) | true(使用本地查詢:sql查詢)
					是否使用本地查詢
					
	iiii.方法名稱規則查詢
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章