JPA教程(基礎API、Spring整合、Springboot整合)
JPA springdata 整合jpa 根據類創建表 無則建有則更 接口增刪改查操作 類比springdata整合mongdb和es等
**一、**常見註解
註解 只有在spring或springboot環境下才可以在屬性上加註解,否則強制getXX方法上加
@Entity 標誌實體
@Table 別名,默認爲實體名
@Id 必不可少 否則報錯 指定主鍵
@GeneratedValue(strategy,generator) mysql支持identity、oracle支持sequence、auto默認自動選擇、table通過表生成
@Column 標註的 columnDefinition 屬性: 表示該字段在數據庫中的實際類型 Date屬性無法自動,String默認對應varchar
@Transient 忽略映射 自定義的getXX方法加上此註解 Spring環境下如果找不到對應屬性會自動忽略
@Basic 表示一個簡單的屬性到數據庫表的字段的映射,對於沒有任何標註的 getXxxx() 方法,默認即爲@Basic
@Basic(fetch = FetchType.LAZY,optional = false) 懶加載、不允許爲空
@Temporal(TemporalType.TIMESTAMP) 指定日期在數據庫的類型 如date--年月日,timestamp年月日時分秒
映射關係相關注解 注意區分單向和雙向映射
@JoinColumn(name="CUSTOMER_ID") 外鍵方
@ManyToOne(fetch=FetchType.LAZY) mappedby不和上面註解一起用 默認EAGER左外連接,懶加載獲取時才查兩次
@ManyToMany
@OneToOne
**二、**實體的狀態:
- 新建狀態: 新創建的對象,尚未擁有持久性主鍵。 new沒ID
- 遊離狀態:擁有持久化主鍵,但是沒有與持久化建立上下文環境new 有ID
- 持久化狀態:已經擁有持久性主鍵並和持久化建立了上下文環境
- 刪除狀態: 擁有持久化主鍵,已經和持久化建立上下文環境,但是從數據庫中刪除
**三、**使用JPA持久化對象的步驟
1,創建 persistence.xml, 在這個文件中配置持久化單元
需要指定跟哪個數據庫進行交互;
需要指定 JPA 使用哪個持久化的框架以及配置該框架的基本屬性
2,創建實體類, 使用 annotation 來描述實體類跟數據庫表之間的映射關係.
使用 JPA API 完成數據增加、刪除、修改和查詢操作
3,創建 EntityManagerFactory可指定屬性如數據表替換或更新、sql的打印;
4,創建 EntityManager (對應 Hibernate 中的Session),也可指定屬性
5,開啓事務,持久化操作,關閉事務
**四、**JPA常用API
-
1,創建EntityManagerFactory,兩個重載構造
-
2,創建管理器EntityManage,兩個重載構造
-
3,事務EntityTransaction:begin commit rollback isActive
-
4,EntityManager的基本操作
find/getReference 前者不存在null,後者存在ok,不存在報錯 用到對象才調用select語句查詢 persist不能有id,更新可先查最後提交事務 或 再次調用方法 remove 只能操作持久化對象,遊離對象不可 merge 臨時對象沒ID創建--複製屬性新對象--insert 3條語句(主鍵查更+insert) 遊離對象有ID創建--緩存存在--複製屬性新對象--update 2條sql 1條查數據庫,緩存了,1條更 遊離對象有ID創建--緩存不存在--數據庫存在select--update 2條(先select數據庫,再update) 遊離對象有ID創建--緩存不存在--數據庫不存在select--複製屬性新對象--insert 4條(先select數 據庫,主鍵查更+insert) flush 同步上下文環境,將未保存實體同步數據庫,兩種模式 auto、commit refresh 更新數據庫實體 clear 清除上下文環境 contains 判斷實例是否被上下文環境管理 isOpen 管理器是否打開 getTran 事務 close createQuery (String qlString):創建一個查詢對象。 createNamedQuery (String name):根據命名的查詢語句塊創建查詢對象。參數爲命名的查詢語句。 createNativeQuery (String sqlString):使用標準 SQL語句創建查詢對象。參數爲標準SQL語句字符串。 createNativeQuery (String sqls, String resultSetMapping):使用標準SQL語句創建查詢對象,並指定返回結果集 Map的 名稱。
五、一對一、一對多、多對多:單向、雙向
注意:@JoinColumn可選,會默認設置映射對象xx_id,若默認命名和該對象屬性重複,則直接以映射對象名生成外鍵。只是可取別名
單向
單向使用一邊註解即可,無需mappby,多的一方獲取少的一方默認是左外連接,區別於SpringData默認接口查詢方法是懶加載
雙向必須通過mappedBy指定關係維護端
雙向
##雙向一對多: (顧客、訂單爲例)
1=被維護端@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.REMOVE},mappedBy="customer")
n=關係維護端@JoinColumn(name="CUSTOMER_ID") //可選 因爲必須通過mapperby指定關係,否則生成表數錯誤 如果兩者都沒,就會在兩邊都建立外鍵造成刪除不了表,執行以下sql纔可刪除
set @@foreign_key_checks=OFF;臨時關閉約束
SET FOREIGN_KEY_CHECKS=0;關閉約束
@ManyToOne(fetch=FetchType.LAZY)
*保存
1)建議先保存1的一方 顧客表採用表主鍵策略,訂單id自增 5條語句:查更+3條insert
2)先保存n的一方 7條sql:2條oder insert+2條主鍵查更+1條customer insert+2條order update
*不能先刪除1的一端,有外鍵約束,設置級聯可連帶刪除n的一端
*在1的一方設置懶加載策略,即兩次查詢,否則默認左外連接
*默認查1的一方即是會左外連接連帶查出n的一方的,只是可以設置加載策略爲懶加載
##雙向一對一:(經理、部門爲例)
1=@OneToOne(fetch=FetchType.LAZY)
1=@OneToOne(mappedBy="mgr") 必須有mapperby 否則兩邊都生成外鍵無法刪除
1)先保存沒有外鍵的一方,2條sql
2)先保存外鍵一方,3條其中最後一條更新
*加載策略可查出來優化 如部門類設置懶加載,經理默認,查部門,3條sql:先查部門,再經理,懶加載部門第二條
*先查經理默認左外連接 1條sql
##雙向多對多:(商品類目、商品爲例)
n=@JoinTable(name="ITEM_CATEGORY",
joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},
inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})
@ManyToMany
n=@ManyToMany(mappedBy="categories")
*一定要有維護關係且只能通過mapperby指定,不能通過@JoinColumn指定,使用一個或多個@JoinColumn都將生成表個數錯誤 都是4張
*多對多保存數據8條sql:2+2+4條橋表
*多對多查數據,兩邊查都一樣的sql語句,默認就是懶加載,區別於上兩種默認左外連接
六、二級緩存
ALL:所有的實體類都被緩存
NONE所有的實體類都不被緩存.
ENABLE_SELECTIVE:標識 @Cacheable(true) 註解的實體類將被緩存
DISABLE_SELECTIVE:緩存除標識 @Cacheable(false) 以外的所有實體類
UNSPECIFIED:默認值,JPA 產品默認值將被使用
默認一級緩存同一個管理器內 相同sql只查一次 類比mybatis緩存同一session
開啓二級緩存 不同管理器相同sql也只查一次 類比mybatis緩存不同session 前提是配置合理
七、Query接口的方法
getSingleResult getResultList setHint緩存
1,createQuery 全部屬性、部分屬性、where、orderby、groupby、外連接、子查詢、多表、內建函數等 對象
2,createNamedQuery query定義在實體中 無需select 對象
3,createNativeQuery setHint 標準sql
4,createNativeQuery 帶結果集參數 標準sql
八、JPA操作數據的幾種方式
-
繼承接口默認的方式,不夠通過通過Query接口自定義JPQL
-
使用JPA API 管理器操作
-
自定義JPQL語言sql的編寫查刪改 JPQL對實體操作不支持insert,對本地sql可以
-
自定義repository@PersistenceContext+管理器操作
注意:增刪改必須加@Modify註解,修改刪除只能返回int或void,且必須在調用方法處聲明事務(SpringData提供默認接口方式不用,Spring環境中調用客戶端管理器操作也要事務)
SpringData相關
一、Repository接口
無任何方法,需按照規定自定義方法
使用方式:1,繼承接口 2,註解@RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)+自定義方法
二、@NoRepositoryBean註解
過濾創建bean 無法注入 註解標識作爲中間接口,不創建代理,如JpaRepo、CrudRepo等
三、CurdRepository、PagingAndSortingRepository、JpaRepository、JpaSpecificationExecutor(分頁+篩選條件)等的使用
自定義JPQL
- ?1 第一個參數
- :name+@Param(不加默認相同名字)第一個參數
- ?#{[0]}第一個參數
- :#{#productInfo.productId} 參數爲封裝對象
- *#{#entityName}取實體
@Query("select t from #{#entityName} t where t.attribute = ?1")
List<T> findAllByAttribute(String attribute);
@Query("select u from User u where u.firstname = ?1 and u.firstname=?#{[0]} and u.emailAddress = ?#{principal.emailAddress}")
List<User> findByFirstnameAndCurrentUserWithCustomQuery(String firstname);
@Query("select u from User u where u.lastname like %:#{[0]}% and u.lastname like %:lastname%")
List<User> findByLastnameWithSpelExpression(@Param("lastname") String lastname);
@Query("select u from User u where u.firstname like %?#{escape([0])}% escape ?#{escapeCharacter()}")
List<User> findContainingEscaped(String namePart);
5.3.7使用SpEL表達式
官方文檔https://docs.spring.io/spring-data/jpa/docs/2.1.10.RELEASE/reference/html/#jpa.modifying-queries對象參數https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions
@Query("select u from User u where u.age = ?#{[0]}")
List<User> findUsersByAge(int age);
@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
由於JPA、lombok引起的CleanUp問題
https://blog.csdn.net/qq_22327273/article/details/88578187?tdsourcetag=s_pctim_aiomsg