SpringBoot JPA學習概要總結

JPA是什麼?

其實JPA也不是第一天聽說,Coding中也用了一段時間了,突然想起來JPA到底是什麼東西,想幹什麼? 似乎很高深的樣子^_^, 自己反而說不敢肯定地說這東西是什麼,感覺查了一把,原來就是三個字:ORM, 還好,沒有理解錯(慚愧,這段時間經常有點信心缺失的感覺)。 下面是一些官樣文字:

JPA是Java Persistence API的簡稱,中文名Java持久層API,是JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中。
應該是SUN提出來的。
JPA由EJB 3.0軟件專家組開發,作爲JSR-220實現的一部分。
這是一個概念框架,而不是實現。
Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的實現
JPA包括以下3方面的技術:
- ORM映射元數據 JPA支持XML和JDK5.0註解兩種元數據的形式,元數據描述對象和表之間的映射關係
- API 用來操作實體對象,執行CRUD操作,框架在後臺替代我們完成所有的事情,開發者從繁瑣的JDBC和SQL代碼中解脫出來
- 查詢語言 通過面向對象而非面向數據庫的查詢語言查詢數據,避免程序的SQL語句緊密耦合


Hibernate和JPA的關係

一般用JPA時,使用的是 javax.persistence.xxx, 但是有些類,在Hibernate中也有定義,該用誰呢? 網上的說法是:當需要擴展的時候,Hibernate會提供自己的對象,但一般都是繼承了JPA的。


EntityManager是幹什麼的?

先看這篇文章JavaEE – JPA(4):EntityManager相關核心概念

public interface EntityManager {
    public void persist(Object entity);
    public <T> T merge(T entity);
    public void remove(Object entity);
    public <T> T find(Class<T> entityClass, Object primaryKey);
    // ......
}

我的理解:EntityManager只是定義了持久化Entity的接口,通過這些接口可以保存和讀取對象,但是對象的管理是有另外一個叫PersistenceContext的對象來管理的,類似於內存池的管理,多個EM對象可以使用同一個PC對象。

遺留問題: 在SpringBoot中如何操作EntityManager?


SpringBoot中使用JPA+Mysql

  1. 項目文件配置
    我的項目是用Gradle配置的
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile 'mysql:mysql-connector-java'
  1. 資源文件配置

    spring:
    datasource:
    url: jdbc:mysql://localhost:3306/test_db
    username: root
    password: xxxxx
    jpa:
    show-sql: true

    使用這個配置,沒有指定ddl屬性,對於mysql來說,不會做任何事情,不會自動創建表也不會刪除表,這其實是項目中常用的模式,先建表,再寫代碼^_^。

    這裏還有個小插曲,在src/main目錄下建了一個resources目錄後,把application.yml放進去,運行起來報錯,似乎是沒有認到這個資源文件,一開始百思不得其解,後來無意中發現,要在build.gradle上點右鍵–refresh gradle project,然後eclipse就會resource目錄和src/main/java/顯示在一起,再運行就正常了。


Entity的定義和使用

一般的Entity類定義如下:

@Entity(name = "t_student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long id;

    public String name;

我不太喜歡寫get,set,直接就把變臉定義爲public。

註解 作用
@Entity 指定表的名字, mysql上的結果來看,表名用大寫,小寫,混寫都沒有關係
@Id 指定ID字段,JPA要求每一個實體Entity,必須有且只有一個主鍵,這個註解沒屬性需要設置
@GeneratedValue 和@Id配合使用,指定主鍵的生成策略,詳見2, 一般來說就是自增長/序列號這種,JPA默認的是Auto,會自動根據使用的數據庫來確定策略,那麼mysql就是自增長,oracle就是序列了。
@Column 指定字段名,有name, unique, nullable,insertable,table等屬性. 實踐中,大多可以不用這個註解來顯式指定字段名,JPA會根據默認規則去進行映射:
1. 表字段名爲單個單詞,比如name, 那麼entity屬性直接用字段名就好了;
2. 表字段名帶下劃線,比如target_name, 那麼entity屬性就是targetName
3. 在Repo中定義的方法中引用屬性名的時候,也是按此規則做反向解析。

Repository的概述

Repository真的是什麼都不幹,僅僅定了一個接口

public interface Repository<T, ID extends Serializable> {
}

接下來有幾個子類擴展了Repository,實現不同的操作。

類名 內容
CrudRepository 繼承知Repository,定義了基本的CRUD方法,我們也可以擴展,比如findByxxxx
PagingAndSortingRepository 繼承自CrudRepository,支持排序和分頁
JpaRepository 繼承自PagingAndSortingRepository,QueryByExampleExecutor 擴展的功能待研究

##自定義Repository
有幾種方式來擴展Repository

  1. 直接用字段名來指定查詢條件,比如findBy, deleteBy, 可以使用的語法可以參考官方文檔4
  2. @NamedQuery, @Query註解,自己寫sql語句

    我喜歡用@Query, 這種方式不好的地方就是數據字段名改了的話得跟着改sql語句。

  3. select的例子

    @Query("select new com.test.Student (h.no, h.name) from t_student h")
    List<Student> getAllStudent();

    有時候我們只是需要返回表中的部分字段,此時需要在entity中定義對應參數的構造方法。

  4. update的例子

    @Transactional
    @Modifying(clearAutomatically = true)
    @Query(value = "update t_student p set p.name=?2 where p.id=?1", nativeQuery = true)
    int updateName(long id, String name);

不想寫原生SQL怎麼辦?

對於簡單的場景,直接寫sql,簡單明瞭,但是從工程角度來說,維護性又差了一點, 比如表的字段名改了就要跟着改sql語句。
JPA提供了幾種方式來處理這個問題,這篇文章做了介紹,就個人來說,比較喜歡Querydsl。


QueryDsl

這篇文章,我覺得講得比較詳細spring boot-jpa整合QueryDSL來簡化複雜操作

環境的建立 如果用的是Gradle,可以參考我的另外一篇文章來配置環境。

今天在簡書上看到一位仁兄恆宇少年寫的QueryDsl系列文章,非常地詳細,本來我也想整理類似文章,看來用不着了,大家請移步:http://www.jianshu.com/p/99a5ec5c3bd5

Spring Boot JPA - 使用 Querydsl 處理複雜的操作 這篇文章也不錯


返回自定義字段

很多時候,我們的查詢是從幾個關聯表裏面各自取幾個字段作爲結果返回,但是這些字段怎麼映射爲DTO對象返回給用戶呢?

  • 如果是JPA,那得自己寫SQL語句, 在其中new DTO,把結果字段作爲new的參數;
  • 如果用QueryDsl,有Project方法來幫助完成這個轉換。

事務處理

使用起來比較簡單,App上加@EnableTransactionManagement,然後在需要的方法上加@Transactional就行了。
詳細內容可以參考catoop寫的這篇文章-Spring Boot 事務的使用


L1 Cache

普遍的說法是L1 Cache和EntityManage掛在一起的,那就有個問題了,我們的工程中,EM對象只有一個,如果每次查詢都把數據cache起來,那且不是數據量很大,而且現在大家都搞分佈式開發,同一個工程部署在多個機器上,在其中一臺機器上對一個對象做update,另外一臺機器上如果前面有該對象的cache,且不是不會知道這個變化,從而一直都是返回舊的對象? 這個疑問,在頭腦裏面想了很久,一直不太明白, 今天寫了點代碼來測試了一下,結果發現不會有這種情況,緩存是跟單次請求的執行過程或者說線程掛在一起的,一個外部請求過來,系統必然分配一個線程去執行,這一次執行過程中的結果會cache,結束以後感覺就釋放掉了。下一次即使是同樣的請求再來,又起一個線程來執行,是不會用到上次的cache結果的,會首先從數據庫中讀取數據。而且如果你執行過程中,啓動另外一個新線程,那這個線程的cache是獨立的, 這樣有可能會導致問題,反而需要注意:
1. 主線程讀取entity,結果會cache;
2. 啓動子線程,對該entity做update;
3. 再主線程中再次讀取,返回的是cache結果。

當然實際代碼中,這種寫法應該非常稀罕。

另外這個L1 Cache只有findOne這個方法執行的時候纔會自動把結果cache起來,我們自己寫的sql語句的結果是不會保存的。(findById,findAll感覺都沒有cache)。


本Markdown編輯器使用StackEdit修改而來,用它寫博客,將會帶來全新的體驗哦:

  • Markdown和擴展Markdown簡潔的語法
  • 代碼塊高亮
  • 圖片鏈接和圖片上傳
  • LaTex數學公式
  • UML序列圖和流程圖
  • 離線寫博客
  • 導入導出Markdown文件
  • 豐富的快捷鍵

快捷鍵

  • 加粗 Ctrl + B
  • 斜體 Ctrl + I
  • 引用 Ctrl + Q
  • 插入鏈接 Ctrl + L
  • 插入代碼 Ctrl + K
  • 插入圖片 Ctrl + G
  • 提升標題 Ctrl + H
  • 有序列表 Ctrl + O
  • 無序列表 Ctrl + U
  • 橫線 Ctrl + R
  • 撤銷 Ctrl + Z
  • 重做 Ctrl + Y

Markdown及擴展

Markdown 是一種輕量級標記語言,它允許人們使用易讀易寫的純文本格式編寫文檔,然後轉換成格式豐富的HTML頁面。 —— [ 維基百科 ]

使用簡單的符號標識不同的標題,將某些文字標記爲粗體或者斜體,創建一個鏈接等,詳細語法參考幫助?。

本編輯器支持 Markdown Extra ,  擴展了很多好用的功能。具體請參考Github.

表格

Markdown Extra 表格語法:

項目 價格
Computer $1600
Phone $12
Pipe $1

可以使用冒號來定義對齊方式:

項目 價格 數量
Computer 1600 元 5
Phone 12 元 12
Pipe 1 元 234

定義列表

Markdown Extra 定義列表語法:
項目1
項目2
定義 A
定義 B
項目3
定義 C

定義 D

定義D內容

代碼塊

代碼塊語法遵循標準markdown代碼,例如:

@requires_authorization
def somefunc(param1='', param2=0):
    '''A docstring'''
    if param1 > param2: # interesting
        print 'Greater'
    return (param2 - param1 + 1) or None
class SomeClass:
    pass
>>> message = '''interpreter
... prompt'''

腳註

生成一個腳註1.

目錄

[TOC]來生成目錄:

數學公式

使用MathJax渲染LaTex 數學公式,詳見math.stackexchange.com.

  • 行內公式,數學公式爲:Γ(n)=(n1)!nN
  • 塊級公式:

x=b±b24ac2a

更多LaTex語法請參考 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/“>這兒.

UML 圖:

可以渲染序列圖:

Created with Raphaël 2.1.0張三張三李四李四嘿,小四兒, 寫博客了沒?李四愣了一下,說:忙得吐血,哪有時間寫。

或者流程圖:

Created with Raphaël 2.1.0開始我的操作確認?結束yesno
  • 關於 序列圖 語法,參考 這兒,
  • 關於 流程圖 語法,參考 這兒.

離線寫博客

即使用戶在沒有網絡的情況下,也可以通過本編輯器離線寫博客(直接在曾經使用過的瀏覽器中輸入write.blog.csdn.net/mdeditor即可。Markdown編輯器使用瀏覽器離線存儲將內容保存在本地。

用戶寫博客的過程中,內容實時保存在瀏覽器緩存中,在用戶關閉瀏覽器或者其它異常情況下,內容不會丟失。用戶再次打開瀏覽器時,會顯示上次用戶正在編輯的沒有發表的內容。

博客發表後,本地緩存將被刪除。 

用戶可以選擇 把正在寫的博客保存到服務器草稿箱,即使換瀏覽器或者清除緩存,內容也不會丟失。

注意:雖然瀏覽器存儲大部分時候都比較可靠,但爲了您的數據安全,在聯網後,請務必及時發表或者保存到服務器草稿箱

瀏覽器兼容

  1. 目前,本編輯器對Chrome瀏覽器支持最爲完整。建議大家使用較新版本的Chrome。
  2. IE9以下不支持
  3. IE9,10,11存在以下問題
    1. 不支持離線功能
    2. IE9不支持文件導入導出
    3. IE10不支持拖拽文件導入


  1. 這裏是 腳註內容.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章