SpringDataJpa學習

# SpringBoot Jdbc JPAJPA是`Java Persistence API`的簡稱,中文名Java持久層API,是JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中基於模板Dao的實現,使得這些具體實體的Dao層已經變的很是「薄」,有一些具體實體的Dao實現可能徹底就是對模板Dao的簡單代理,而且每每這樣的實現類可能會出如今不少實體上。`Spring-data-jpa`的出現正可讓這樣一個已經很「薄」的數據訪問層變成只是一層接口的編寫方式JPA的主要目標之一就是提供更加簡單的編程模型:在JPA框架下建立實體和建立Java 類同樣簡單,沒有任何的約束和限制,只須要使用 `javax.persistence.Entity`進行註釋,JPA的框架和接口也都很是簡單,沒有太多特別的規則和設計模式的要求,開發者能夠很容易的掌握。JPA基於非侵入式原則設計,所以能夠很容易的和其它框架或者容器集成。# JPA sql 語法 JPQL查詢語法主要分爲三類:* 查詢用的 SELECT 語法* 更新用的 UPDATE 語法* 刪除用的 DELETE 語法SELECT 語法結構由幾個部份組成:    SELECT 子句 FROM 字句 [WHERE 子句] [GROUP BY 子句] [HAVING 子句] [ORDER BY 子句]一個基本的 SELECT 語句以下所示:    SELECT u.id, u.name FROM User u WHERE u.age > 10 AND u.age < 20其中`User u`是個路徑表示`(path expression)`,路徑表示有三種:範圍變數(Range variable)路徑表示、羣集成員(Collection member)路徑表示與關聯導覽(Association traversing)表示。User u是範圍變數路徑表示的一個例子,指定查詢的實體爲User與別名爲u。一個羣集成員路徑表示用來指定物件中的羣集成員,例如:    SELECT u FROM User u, IN(u.emails) e WHERE e.address LIKE '%.%@openhome.cc'其中IN中指定的,就是羣集成員路徑表示,而>、<、AND、IN、LIKE等都是WHERE子句中條件表示式,簡單列出一些條件表示式以下:        比較陳述   =、>、>=、<、<=、<>    BETWEEN 陳述 [NOT BETWEEN    LIKE 陳述    [NOT] LIKE    IN 陳述  [NOT] IN    NULL 陳述    IS [NOT] NULL    EMPTY 陳述   IS [NOT] EMPTY    EXISTS 陳述  [NOT] EXISTSLIKE中,能夠用_表示比對單一字元,用%表示比對任意數目字元。  關聯導覽表示則提供SQL語法中JOIN的功能,包括了`INNER JOIN`、`LEFT OUTER JOIN`、`FETCH`等,如下爲INNER JOIN的實際例子:        SELECT u FROM User u INNER JOINu.emails e WHERE e.address LIKE '%.%@openhome.cc'  JOIN關鍵字能夠省略,上式等同於:          SELECT u FROM User u JOINu.emails e WHERE e.address LIKE '%.%@openhome.cc'  LEFT OUTER JOIN的OUTER關鍵字能夠省略,一個例子以下:        SELECT u FROM User u LEFT JOIN u.emails e WHERE e.address LIKE'%.%@openhome.cc'  在做INNER JOIN、LEFT OUTER JOIN能夠加上FETCH關鍵字,以預先擷取相關資料,例如:    SELECT u FROM User u LEFT JOIN FETCH u.emails e WHERE e.address LIKE'%.%@openhome.cc'  SELECT中可使用匯集函式,例如:    SELECT AVG(u.age) FROM User u  SELECT中可使用建構表示,直接將一些資料封裝爲指定的物件,例如:    SELECT NEW SomeObject(u.id, u.name, o.number) FROM User u JOIN Order o WHERE u.id = 1975  WHERE子句中可使用LENGTH()、LOWER()、UPPER()、SUBSTRING()等JPQL函式。  能夠對查詢結果使用ORDER BY進行排序:    SELECT u FROM User u ORDER BY u.age  ORDER預設是ASC昇冪排序,可以使用DESC降冪排序:    SELECT u FROM User u ORDER BY u.age DESC  可同時指定兩個以上的排序方式,例如先按照"age"降冪排序,若是"age"相同,則按照"name"昇冪排列:    SELECT u FROM User u ORDER BY u.age DESC, u.name  能夠配合GROUP BY子句,自動將指定的欄位依相同的內容羣組,例如依欄位"sex"分組並做平均:    SELECT u.sex, AVG(u.age) FROM User u GROUP BY u.sex  GROUP BY一般搭配HAVING來使用,例如:    SELECT u.sex, avg(u.age) FROM User u GROUP BY u.sex HAVING AVG(u.age) > 20  可使用UPDATE語法來更新資料,例如:    UPDATE User u SET u.name='momor' WHERE u.name='bbb'  能夠透過DELETE來刪除資料,例如:    DELETE User u WHERE u.name='bush'## 選擇查詢編輯    SELECT <select_expression>    FROM <from_clause>    [WHERE <conditional_expression>]    [ORDER BY <order_by_clause>]## 聚合查詢編輯    SELECT <select_expression>    FROM <from_clause>    [WHERE <conditional_expression>]    [GROUP BY <group_by_clause>]    [HAVING <conditional_expression>]    [ORDER BY <order_by_clause>]## 更新查詢編輯    UPDATE <entity name>[ [AS ] <identification variable>]    SET <update_statement>{,<update_statement>}*    [WHERE <conditional_expression>]## 刪除查詢編輯    DELETE FROM <entity name>[ [AS ] <identification variable>]    [WHERE <conditional_expression>]# 項目引入繼承自`JpaRepository`的接口就能完成數據訪問Spring-data-jpa依賴於Hibernatejap 相關依賴,        <!-- jpa  -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-jpa</artifactId>        </dependency>在`application.xml`中配置:數據庫鏈接信息(如使用嵌入式數據庫則不須要)、自動建立表結構的設置,例如使用mysql的狀況以下:    spring.datasource.url=jdbc:mysql://localhost:3306/test    spring.datasource.username=root    spring.datasource.password=123456    spring.datasource.driver-class-name=com.mysql.jdbc.Driver        # hibernate的配置屬性,其主要做用是:自動建立、更新、驗證數據庫表結構    spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop       `spring.jpa.properties.hibernate.hbm2ddl.auto`是hibernate的配置屬性,其主要做用是:自動建立、更新、驗證數據庫表結構。  該參數的幾種配置以下:  * `create`:每次加載hibernate時都會刪除上一次的生成的表,而後根據你的model類再從新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是致使數據庫表數據丟失的一個重要緣由。* `create-drop`:每次加載hibernate時根據model類生成表,可是sessionFactory一關閉,表就自動刪除。* `update`:最經常使用的屬性,第一次加載hibernate時根據model類會自動創建起表的結構(前提是先創建好數據庫),之後加載hibernate時根據model類自動更新表結構,即便表結構改變了但表中的行仍然存在不會刪除之前的行。要注意的是當部署到服務器後,表結構是不會被立刻創建起來的,是要等應用第一次運行起來後纔會。* `validate`:每次加載hibernate時,驗證建立數據庫表結構,只會和數據庫中的表進行比較,不會建立新表,可是會插入新值。  至此已經完成基礎配置,若是您有在Spring下整合使用過它的話,相信你已經感覺到Spring Boot的便利之處:JPA的傳統配置在persistence.xml文件中,可是這裏咱們不須要。固然,最好在構建項目時候按照以前提過的最佳實踐的工程結構來組織,這樣以確保各類配置都能被框架掃描到。## 實體關聯給實體添加`@Entity` 類註解,屬性添加相應的註解`@Id`, `@GeneratedValue`, `@Column`等## 建立對應的接口實現對該實體的數據訪問建立接口以`Repository`方式命名便於理解,接口繼承自`JpaRepository` # JPA api文檔https://docs.spring.io/spring-data/data-jpa/docs/current/api/## JPA 經過解析方法名建立查詢    User findByName(String name)    User findByNameAndAge(String name, Integer age)    上面分別實現了按name查詢User實體和按name和age查詢User實體,能夠看到咱們這裏沒有任何類SQL語句就完成了兩個條件查詢方法|   Keyword     |       Sample      |   JPQL snippet    | |   --------    |       -----:      |   :----:          ||   IsNotNull    |  findByAgeNotNull|...  where x.age not null    ||   Like    |   findByNameLike|...  where x.name like ?1    ||   NotLike    |    findByNameNotLike    | ...  where x.name not like ?1    ||   StartingWith    |  findByNameStartingWith    |    ...  where x.name like ?1(parameter bound with appended %)    ||   EndingWith    |    findByNameEndingWith    |  ...  where x.name like ?1(parameter bound with prepended %)    ||   Containing    |    findByNameContaining    |  ...  where x.name like ?1(parameter bound wrapped in %)    ||   OrderBy    |   findByAgeOrderByName    |  ...  where x.age = ?1 order by x.name desc    ||   Not    |   findByNameNot    | ...  where x.name <> ?1    ||   In    |    findByAgeIn    |   ...  where x.age in ?1    ||   NotIn    | findByAgeNotIn    |    ...  where x.age not in ?1    ||   True    |  findByActiveTrue    |  ...  where x.avtive = true    ||   Flase    | findByActiveFalse    | ...  where x.active = false    ||   And     |  findByNameAndAge    |  ...  where x.name = ?1 and x.age = ?2    ||   Or    |    findByNameOrAge    |   ...  where x.name = ?1 or x.age = ?2    ||   Between    |   findBtAgeBetween    |  ...  where x.age between ?1 and ?2    ||   LessThan    |  findByAgeLessThan    | ...  where x.age  <  ?1    ||   GreaterThan    |   findByAgeGreaterThan    |  ...  where x.age > ?1    ||   After/Before    |  ...    |   ...    ||   IsNull    |    findByAgeIsNull    |   ...  where x.age is null    |## JpaRepository相關查詢功能> a.Spring Data JPA框架在進行方法名解析時,會先把方法名多餘的前綴截取掉,好比`find`、`findBy`、`read`、`readBy`、`get`、`getBy`,而後對剩下部分進行解析。> b.假如建立以下的查詢:`findByUserDepUuid()`,框架在解析該方法時,首先剔除`findBy`,而後對剩下的屬性進行解析,假設查詢實體爲Doc。1:先判斷`userDepUuid` (根據POJO 規範,首字母變爲小寫)是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,繼續第二步;2:從右往左截取第一個大寫字母開頭的字符串此處爲`Uuid`),而後檢查剩下的字符串是否爲查詢實體的一個屬性,若是是,則表示根據該屬性進行查詢;若是沒有該屬性,則重複第二步,繼續從右往左截取;最後假設user爲查詢實體的一個屬性;3:接着處理剩下部分(`DepUuid`),先判斷user 所對應的類型是否有`depUuid`屬性,若是有,則表示該方法最終是根據「 `Doc.user.depUuid`」 的取值進行查詢;不然繼續按照步驟2 的規則從右往左截取,最終表示根據「`Doc.user.dep.uuid`」 的值進行查詢。4:可能會存在一種特殊狀況,好比Doc包含一個`user` 的屬性,也有一個`userDep` 屬性,此時會存在混淆。能夠明確在屬性之間加上"_" 以顯式表達意圖,好比"`findByUser_DepUuid()`" 或者"`findByUserDep_uuid()`"> c.特殊的參數: 還能夠直接在方法的參數上加入分頁或排序的參數,好比:```Page<UserModel> findByName(String name, Pageable pageable);List<UserModel> findByName(String name, Sort sort);```> d.也可使用JPA的`NamedQueries`,方法以下:1:在實體類上使用`@NamedQuery`,示例以下:```@NamedQuery(name = "UserModel.findByAge",query = "select o from UserModelo where o.age >= ?1")```2:在本身實現的DAO的Repository接口裏面定義一個同名的方法,示例以下:```public List<UserModel> findByAge(int age);```3:而後就可使用了,Spring會先找是否有同名的NamedQuery,若是有,那麼就不會按照接口定義的方法來解析。> e.還可使用@Query來指定本地查詢,只要設置`nativeQuery`爲`true`,好比:```@Query(value="select * from tbl_user where name like %?1" ,nativeQuery=true)public List<UserModel> findByUuidOrAge(String name);```注意:當前版本的本地查詢不支持翻頁和動態的排序> f.使用命名化參數,使用`@Param`便可,好比:```@Query(value="select o from UserModel o where o.name like %:nn")public List<UserModel> findByUuidOrAge(@Param("nn") String name);```> g.一樣支持更新類的Query語句,添加`@Modifying`便可,好比:```@Modifying@Query(value="update UserModel o set o.name=:newName where o.name like %:nn")public int findByUuidOrAge(@Param("nn") String name,@Param("newName") StringnewName);```注意:  1:方法的返回值應該是int,表示更新語句所影響的行數  2:在調用的地方必須加事務,沒有事務不能正常執行> h.建立查詢的順序    Spring Data JPA 在爲接口建立代理對象時,若是發現同時存在多種上述狀況可用,它該優先採用哪一種策略呢?  <jpa:repositories> 提供了`query-lookup-strategy `屬性,用以指定查找的順序。它有以下三個取值:1:`create-if-not-found`:若是方法經過@Query指定了查詢語句,則使用該語句實現查詢;若是沒有,則查找是否認義了符合條件的命名查詢,若是找到,則使用該命名查詢;若是二者都沒有找到,則經過解析方法名字來建立查詢。這是`querylookup-strategy` 屬性的默認值  2:`create`:經過解析方法名字來建立查詢。即便有符合的命名查詢,或者方法經過@Query指定的查詢語句,都將會被忽略  3:`use-declared-query`:若是方法經過@Query指定了查詢語句,則使用該語句實現查詢;若是沒有,則查找是否認義了符合條件的命名查詢,若是找到,則使用該命名查詢;若是二者都沒有找到,則拋出異常## JPA 經過SQL查下提供經過使用`@Query` 註解來建立查詢,您只須要編寫JPQL語句,並經過相似「:name」來映射@Param指定的參數,就像例子中的第三個findUser函數同樣在`@Query`  有個參數定義爲是否實用實體JPA查詢,或者純SQL查詢. `nativeQuery`  
相關文章
相關標籤/搜索