您好,登錄后才能下訂單哦!
java JPA中的EntityManager是怎樣的,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
JPA即Java Persistence API,是Java EE中針對持久化數據提供的規范。在使用JPA中,我們經常會提到Entity,Entity就是在內存中短暫存活,在數據庫中被持久化了的對象。Entity和數據庫中的表映射,也就是我們常說的ORM。我們可以持久化一個Entity,刪除一個Entity或者通過Java Persistence Query Language(JPQL)來查詢Entity。
通過注解的方式聲明一個entity如下:
Java代碼
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
private Float price;
private String description;
private String isbn;
private Integer nbOfPage;
private Boolean illustrations;
// Getters, setters
}
Book Entity和數據庫的映射關系如圖:
在JPA中,所有的Entity都是通過javax.persistence.EntityManager的API來管理和操縱的。當EntityManager管理Entity時,所有的Entity都會有一個唯一標識(這個標識通常是主鍵列),Entity的狀態將會和數據庫同步。當Entity脫離EntityManager的管理時,Entity就變成了一個普通的Java對象實例,這時它的狀態是detached。
當我們用new關鍵字創建一個新Entity時,這個Entity對象存在于內存中,JPA對它沒有任何了解。只有當EntityManager開始管理它時,它的狀態才會和數據庫同步。當調用了EntityManager.remove方法后,它就會從數據庫中刪除掉,但Java對象還會在內存中存在,直到被垃圾回收掉。
在我們介紹EntityManager API之前,我們先來看看Persistence Context的概念。一個Persistence Context就是針對一個事物中一段時間內一群被管理的Entity的集合。多個具有相同唯一標識的Entity實例不能存在于同一個Persistence Context中。例如,一個Book實例的ID是12,此時就不能有第二個ID也是12的Book實例存在于相同的Persistence Context中了。只有存在于Persistence Context中的Enitity才會被EntityManager所管理,它們的狀態才會反映到數據庫中。Persistence Context可以被看成一個一級緩存,它可以被EntityManager當作存放Entity的緩存空間。默認情況下,Entity在Persistence Context存活,直到用戶的事物結束。
每個事物用戶都有自己的Persistence Context,多個Persistence Context訪問同一個數據庫的實例如下圖:
我們可以調用EntityManager.persist()方法來持久化一個Entity,也就是向數據庫中插入數據。
Java代碼
Customer customer = new Customer("Antony", "Balla", "tballa@mail.com");
Address address = new Address("Ritherdon Rd", "London", "8QE", "UK");
customer.setAddress(address);
tx.begin();
em.persist(customer);
em.persist(address);
tx.commit();
上例中的Customer和Address是兩個普通的Java對象,當被EntityManager調用了persist方法后,兩個對象都變成了EntityManager所管理的Entity。當Transaction提交后,他們的數據會被插入到數據庫中。這里的Customer對象是對象關系的持有者,它對應的表結構應當有一個外鍵來對應Address對象。
我們注意一下存儲兩個對象的順序。即便是將兩個對象存儲的順序顛倒一下,也不會造成外鍵找不到的錯誤。之前我們已經說過了,Persistence Context可以被看作一級緩存。在事物被提交之前,所有的數據都是在內存中的,沒有對數據庫的訪問,EntityManager緩存了數據,當數據準備好后,以底層數據庫期待的順序將數據更新到數據庫中。
想查找一個Entity,有兩個類似的方法,代碼如下:
Java代碼
Customer customer = em.find(Customer.class, 1234L)
if (customer!= null) {
// 處理對象
}
try {
Customer customer = em.getReference(Customer.class, 1234L)
// 處理對象
} catch(EntityNotFoundException ex) {
// Entity沒有找到
}
find方法會根據主鍵返回一個Entity,如果主鍵不存在數據庫中,會返回null。getReference和find方法很類似,但是只是返回一個Entity的引用,不會返回其中的數據。它用于那些我們需要一個Entity對象和它的主鍵但不需要具體數據的情況。如例所示,當Entity找不到時,會有EntityNotFoundException拋出。
一個Entity可以通過EntityManager.remove()被刪除,一但Entity被刪除,它在數據庫中也會被刪除,并且脫離了EntityManager管理(detached)。此時這個對象不能再和數據庫中的數據同步了。
Java代碼
tx.begin();
em.remove(customer);
tx.commit();
在之前的所有例子中,和數據庫的數據的同步都是發生在事物提交時。所待執行的改變都是需要一個SQL語句的執行。例如在下面的代碼中,兩條insert語句會在事物提交時被執行的數據庫中。
Java代碼
tx.begin();
em.persist(customer);
em.persist(address);
tx.commit();
大多數情況下,這種和數據庫的同步機制能滿足我們程序的需要。如果我們想將對Persistence Context中數據改變立刻反映到數據庫中,可以通過調用flush方法實現。或者我們想將數據庫中的數據重新同步回Persistence Context,可以調用refresh方法。當應用程序在叫用了flush方法后,又調用了rollback方法,所有同步到數據庫的數據又會都被回滾。
這種同步機制很像我們在sqlplus中直接執行多個SQL語句,當顯性調用flush方法時,相當于執行我們已經輸入的SQL語句,但沒有提交事務。當tx.commit方法調用時,事物才真正的被提交。如果沒有調用flush方法,則在tx.commit方法調用時先執行已經輸入的SQL語句再提交事務。
Java代碼
tx.begin();
em.persist(customer);
em.flush();
em.persist(address);
tx.commit();
上面這個代碼例子中,persist執行的順序是要被保證的。因為在調用flush方法時,變化已經被同步到數據庫中了,即SQL語句已經被執行了,如果兩個persist方法順序顛倒一下,則會出現外鍵約束的異常。
refresh方法實現的效果可以通過下面的例子顯示出來:
Java代碼
Customer customer = em.find(Customer.class, 1234L)
assertEquals(customer.getFirstName(), "Antony");
customer.setFirstName("William");
em.refresh(customer);
assertEquals(customer.getFirstName(), "Antony");");
contains方法會返回一個Boolean值,用于檢測當前Persistence Context中是否存在某個Entity
Java代碼
Customer customer = new Customer("Antony", "Balla", "tballa@mail.com");
tx.begin();
em.persist(customer);
tx.commit();
assertTrue(em.contains(customer));
tx.begin();
em.remove(customer);
tx.commit();
assertFalse(em.contains(customer));
clear方法可以清空當前Persistence Context,是所有的Entity都變成detached狀態。detach方法則是只將某個Entity變成detached狀態。前面已經說了detached的Entity不會和數據庫中的數據再進行同步了。
Java代碼
Customer customer = new Customer("Antony", "Balla", "tballa@mail.com");
tx.begin();
em.persist(customer);
tx.commit();
assertTrue(em.contains(customer));
em.detach(customer);
assertFalse(em.contains(customer));
如果我們想使一個detached的Entity重新和數據庫中的數據進行同步,可以調用merge方法。想象有這樣一個場景,我們需要從數據庫中取出某個對象,這個對象從持久層傳到表現層之前變成了detached狀態。在表現層中,Entity的一些數據發生了變化,我們將這個Entity傳回持久層并讓它變成managed狀態以將變化反映到數據庫中。
Java代碼
Customer customer = new Customer("Antony", "Balla", "tballa@mail.com");
tx.begin();
em.persist(customer);
tx.commit();
em.clear();
// 設置一個新的值給一個detached的entity
customer.setFirstName("William");
tx.begin();
em.merge(customer);
tx.commit();
最后我們通過一張圖來表示EntityManager對一個Entity的生命周期的改變。
關于 java JPA中的EntityManager是怎樣的問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。