# 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`