JPQL和命名查詢
在使用Spring Data JPA的過程中,框架通過解析方法名稱的方式生成對應(yīng)的SQL,確實為我們減少了很多的工作量,但是,也特殊情況,需要我們手寫SQL,當(dāng)然,這里是JPQL(一種面向?qū)ο蟮腟QL語法結(jié)構(gòu))
使用@Query注解創(chuàng)建查詢,將該注解貼在dao的方法上,然后提供一個需要的JPQL語句即可,如:
@Query("SELECT p FROM Person p WHERE name LIKE %?1%")
Person findByName(String name);
如果不使用Query注解,那么Spring Data JPA為我們生成的SQL應(yīng)該是:
Hibernate: select person0_.id as id1_0_, person0_.age as age2_0_, person0_.name as name3_0_
from Person person0_ where person0_.name=?
使用注解之后執(zhí)行的SQL:
Hibernate: select person0_.id as id1_0_, person0_.age as age2_0_, person0_.name as name3_0_
from Person person0_ where person0_.name like ?
所以,我們可以通過這種方式來自定義需要執(zhí)行的SQL語句,這樣可以讓我們開發(fā)者更加自如的來完成我們的需求
很多開發(fā)者在創(chuàng)建 JPQL 時喜歡使用命名參數(shù)來代替位置編號,@Query 也對此提供了支持。JPQL 語句中通過”: 變量”的格式來指定參數(shù)乳丰,同時在方法的參數(shù)前面使用 @Param 將方法參數(shù)與 JPQL中的命名參數(shù)對應(yīng)口锭,示例如下:
@Query("SELECT p FROM Person p WHERE name LIKE %:name%")
Person findByName(@Param("name") String name);
此時大家應(yīng)該會想一個問題,上面我們都在說如何執(zhí)行查詢操作,查詢的SQL可以自動生成也可自定義,那么增刪改操作的SQL可以嗎?也可以自定生成響應(yīng)的SQL嗎?
答案是肯定的,這里,我們需要使用@Modifying注解來標識該方法執(zhí)行的是更新或者刪除操作,如:
@Modifying
@Query("UPDATE Person p SET p.name = :name WHERE p.id = :id")
void updatePersonName(@Param("id") Integer id, @Param("name") String name);
如此這般,框架執(zhí)行的就不是查詢的SQL,而是更新的SQL
通過調(diào)用 JPA 命名查詢語句創(chuàng)建查詢
命名查詢是 JPA 提供的一種將查詢語句從方法體中獨立出來类嗤,以供多個方法共用的功能祈餐。Spring Data JPA 對命名查詢也提供了很好的支持瀑踢。用戶只需要按照 JPA 規(guī)范在 orm.xml 文件或者在實體類中使用 @NamedQuery(或 @NamedNativeQuery)定義好查詢語句扳还,唯一要做的就是為該語句命名時,需要滿足”DomainClass.methodName”的命名規(guī)則丘损。假設(shè)定義了如下接口:
Person findByName(@Param("name") String name);
同時在實體類中定義JPQL或者SQL
@NamedQuery(name = "Person.findByName", query = "SELECT p FROM Person p WHERE p.name LIKE :name")
public class Person {
}
此時name屬性的值需要按照規(guī)則定義,Spring Data JPA根據(jù)name屬性的值找到對應(yīng)的JPQL語句并執(zhí)行
Spring Data JPA的查詢策略
以上,我們說到了三種執(zhí)行SQL的方式,
- 框架通過解析方法名稱,生成對應(yīng)的SQL語句
- 使用@Query聲明JPQL,這樣就可以執(zhí)行我們自定義的語句
- Spring Data JPA所支持的命名查詢
這里我們來看看框架是如何選擇使用哪一種的執(zhí)行查詢的方式:
Spring Data JPA 在為接口創(chuàng)建代理對象時普办,如果發(fā)現(xiàn)同時存在多種上述情況可用,它該優(yōu)先采用哪種策略呢徘钥?為此衔蹲,<jpa:repositories> 提供了 query-lookup-strategy 屬性,用以指定查找的順序呈础。它有如下三個取值:
create —- 通過解析方法名字來創(chuàng)建查詢舆驶。即使有符合的命名查詢,或者方法通過 @Query 指定的查詢語句而钞,都將會被忽略沙廉。
create-if-not-found —- 如果方法通過 @Query 指定了查詢語句,則使用該語句實現(xiàn)查詢臼节;如果沒有撬陵,則查找是否定義了符合條件的命名查詢珊皿,如果找到,則使用該命名查詢巨税;如果兩者都沒有找到蟋定,則通過解析方法名字來創(chuàng)建查詢。這是 query-lookup-strategy 屬性的默認值草添。
use-declared-query —- 如果方法通過 @Query 指定了查詢語句驶兜,則使用該語句實現(xiàn)查詢;如果沒有远寸,則查找是否定義了符合條件的命名查詢抄淑,如果找到,則使用該命名查詢驰后;如果兩者都沒有找到肆资,則拋出異常。
為接口中的部分方法提供自定義實現(xiàn)
在實際開發(fā)中,我們會遇到一些需要自定義持久層實現(xiàn)的需求,也就是Spring Data JPA的實現(xiàn)不能滿足我們的要求,所以Spring Data JPA考慮到了這一點,為我們提供了自定義實現(xiàn)持久層的方式
將需要開發(fā)者手動實現(xiàn)的方法從持久層接口(假設(shè)為 UserDao )中抽取出來灶芝,獨立成一個新的接口(假設(shè)為 IUserDaoBase )迅耘,并讓 IUserDao 繼承 IUserDaoBase;
為 IUserDaoBase 提供自定義實現(xiàn)(假設(shè)為 IUserDaoBaseImpl )监署;
將 IUserDaoBaseImpl 配置為 Spring Bean;
在 <jpa:repositories> 中按下面的方式進行配置纽哥。
<jpa:repositories base-package="cn.wolfcode.spring_jdbc_jpa.dao">
<jpa:repository id="userDao" repository-impl-ref=" userDaoBase " /></jpa:repositories>
<bean id="userDaoBase" class="......."/>
此外钠乏,<jpa:repositories > 提供了一個 repository-impl-postfix 屬性,用以指定實現(xiàn)類的后綴春塌。如:
<jpa:repositories base-package="cn.wolfcode.spring_jdbc_jpa.dao"
repository-impl-postfix="Impl"/>
在框架掃描到 IUserDao 接口時晓避,它將嘗試在相同的包目錄下查找 IUserDaoImpl.java,如果找到只壳,便將其中的實現(xiàn)方法作為最終生成的代理類中相應(yīng)方法的實現(xiàn)俏拱。
到此,Spring Data JPA的基本使用我們就先到這