EntityManager使用方法

Session bean or MD bean對Entity bean的操作(包括所有的query, insert, update, delete操作)都是通過EntityManager實例來完成的。EntityManager是由EJB 容器自動地管理和配置的,不需要用戶自己創建。

那麼Session bean or MD bean如何獲得EntityManager實例呢??
非常簡單,就是通過下列代碼進行依賴注入:
Public class sessionbean1{
@PersistenceContext
EntityManager em;
。。。
}

注意:如果persistence.xml文件中配置了多個<persistence-unit>。那麼在注入EntityManager對 象時必須指定持久化名稱,通過@PersistenceContext註釋的unitName屬性進行指定,例:

@PersistenceContext(unitName="foshanshop")
EntityManager em;

如果只有一個<persistence-unit>,不需要明確指定。


請注意:Entity Bean被EntityManager管理時,EntityManager會跟蹤他的狀態改變,在任何決定更新實體Bean的時候便會把發生改變的值同步 到數據庫中(跟hibernate一樣)。但是如果entity Bean從EntityManager分離後,他是不受管理的,EntityManager無法跟蹤他的任何狀態改變。


EntityManager一些常用的API(包含query, insert, update, delete操作)

1)get entity —— find() or getReference()
Person person = em.find(Person.class,1);

當在數據庫中沒有找到記錄時,getReference()和find()是有區別的,find()方法會返回null,而getReference() 方法會拋出javax.persistence.EntityNotFoundException例外,另外getReference()方法不保證 entity Bean已被初始化。如果傳遞進getReference()或find()方法的參數不是實體Bean,都會引發 IllegalArgumentException例外

2)insert —— persist()
Person person = new Person();
person.setName(name);
//把數據保存進數據庫中
em.persist(person);

如果傳遞進persist()方法的參數不是實體Bean,會引發IllegalArgumentException

3)update —— 分2種情況
情況1:當實體正在被容器管理時,你可以調用實體的set方法對數據進行修改,在容器決定flush時(這個由container自行判斷),更新的數據 纔會同步到數據庫,而不是在調用了set方法對數據進行修改後馬上同步到數據庫。如果你希望修改後的數據馬上同步到數據庫,你可以調用 EntityManager.flush()方法。
public void updatePerson() {
try {
Person person = em.find(Person.class, 1);
person.setName("lihuoming"); //方法執行完後即可更新數據
} catch (Exception e) {
e.printStackTrace();
}
}


    情況2:在實體Bean已經脫離了EntityManager的管理時,你調用實體的set方法對數據進行修改是無法同步更改到數據庫的。你必須調用 EntityManager.merge()方法。調用之後,在容器決定flush時(這個由container自行判斷),更新的數據纔會同步到數據 庫。如果你希望修改後的數據馬上同步到數據庫,你可以調用EntityManager.flush()方法。
   
public boolean updatePerson(Person person) {
try {
em.merge(person);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}

下面的代碼會調用上面的方法。因爲下面的第二行代碼把實體Bean 返回到了客戶端,這時的實體Bean已經脫離了容器的管理,在客戶端對實體Bean進行修改,最後把他返回給EJB 容器進行更新操作:

PersonDAO persondao = (PersonDAO) ctx.lookup("PersonDAOBean/remote");
Person person = persondao.getPersonByID(1); //此時的person 已經脫離容器的管理
person.setName("張小豔");
persondao.updatePerson(person);

執行em.merge(person)方法時,容器的工作規則:
1>     如果此時容器中已經存在一個受容器管理的具有相同ID的person實例,容器將會把參數person的內容拷貝進這個受管理的實例,merge()方法 返回受管理的實例,但參數person仍然是分離的不受管理的。容器在決定Flush時把實例同步到數據庫中。

2>容器中不存在具有相同ID的person實例。容器根據傳進的person參數Copy出一個受容器管理的person實例,同時 merge()方法會返回出這個受管理的實例,但參數person仍然是分離的不受管理的。容器在決定Flush時把實例同步到數據庫中。

如果傳遞進merge ()方法的參數不是實體Bean,會引發一個IllegalArgumentException。


4)Delete —— Remove()
Person person = em.find(Person.class, 2);
//如果級聯關係cascade=CascadeType.ALL,在刪除person 時候,也會把級聯對象刪除。
//把cascade屬性設爲cascade=CascadeType.REMOVE 有同樣的效果。
em.remove (person);

如果傳遞進remove ()方法的參數不是實體Bean,會引發一個IllegalArgumentException


5)HPQL query —— createQuery()

除了使用find()或getReference()方法來獲得Entity Bean之外,你還可以通過JPQL得到實體Bean。

要執行JPQL語句,你必須通過EntityManager的createQuery()或createNamedQuery()方法創建一個Query 對象

Query query = em.createQuery("select p from Person p where p. name=’黎明’");
List result = query.getResultList();
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
//處理Person
}

// 執行更新語句
Query query = em.createQuery("update Person as p set p.name =?1 where p. personid=?2");
query.setParameter(1, “黎明”);
query.setParameter(2, new Integer(1) );
int result = query.executeUpdate(); //影響的記錄數

// 執行更新語句
Query query = em.createQuery("delete from Person");
int result = query.executeUpdate(); //影響的記錄數


6)SQL query —— createNaiveQuery()
注意:該方法是針對SQL語句,而不是HPQL語句

//我們可以讓EJB3 Persistence 運行環境將列值直接填充入一個Entity 的實例,
//並將實例作爲結果返回.
Query query = em.createNativeQuery("select * from person", Person.class);
List result = query.getResultList();
if (result!=null){
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
Person person= (Person)iterator.next();
… ..
}
}

// 直接通過SQL 執行更新語句
Query query = em.createNativeQuery("update person set age=age+2");
query.executeUpdate();


7)Refresh entity —— refresh()
如果你懷疑當前被管理的實體已經不是數據庫中最新的數據,你可以通過refresh()方法刷新實體,容器會把數據庫中的新值重寫進實體。這種情況一般發 生在你獲取了實體之後,有人更新了數據庫中的記錄,這時你需要得到最新的數據。當然你再次調用find()或getReference()方法也可以得到 最新數據,但這種做法並不優雅。

Person person = em.find(Person.class, 2);
//如果此時person 對應的記錄在數據庫中已經發生了改變,
//可以通過refresh()方法得到最新數據。
em.refresh (person);


8)Check entity是否在EntityManager管理當中 —— contains()
contains()方法使用一個實體作爲參數,如果這個實體對象當前正被持久化內容管理,返回值爲true,否則爲false。如果傳遞的參數不是實體 Bean,將會引發一個IllegalArgumentException.

Person person = em.find(Person.class, 2);
。。。
if (em.contains(person)){
//正在被持久化內容管理
}else{
//已經不受持久化內容管理
}


9)分離所有當前正在被管理的實體 —— clear()
在處理大量實體的時候,如果你不把已經處理過的實體從EntityManager中分離出來,將會消耗你大量的內存。調用EntityManager 的clear()方法後,所有正在被管理的實體將會從持久化內容中分離出來。有一點需要說明下,在事務沒有提交前(事務默認在調用堆棧的最後提交,如:方 法的返回),如果調用clear()方法,之前對實體所作的任何改變將會掉失,所以建議你在調用clear()方法之前先調用flush()方法保存更 改。


10)             將實體的改變立刻刷新到數據庫中 —— flush()
當EntityManager對象在一個session bean 中使用時,它是和服務器的事務上下文綁定的。EntityManager在服務器的事務提交時提交併且同步它的內容。在一個session bean 中,服務器的事務默認地會在調用堆棧的最後提交(如:方法的返回)。

例子1:在方法返回時才提交事務
public void updatePerson(Person person) {
try {
Person person = em.find(Person.class, 2);
person.setName("lihuoming");
em.merge(person);
//後面還有衆多修改操作
} catch (Exception e) {
e.printStackTrace();
}
//更新將會在這個方法的末尾被提交和刷新到數據庫中
}

爲了只在當事務提交時纔將改變更新到數據庫中,容器將所有數據庫操作集中到一個批處理中,這樣就減少了代價昂貴的與數據庫的交互。當你調用 persist( ), merge( )或remove( )這些方法時,更新並不會立刻同步到數據庫中,直到容器決定刷新到數據庫中時纔會執行,默認情況下,容器決定刷新是在“相關查詢”執行前或事務提交時發 生,當然“相關查詢”除find()和getreference()之外,這兩個方法是不會引起容器觸發刷新動作的,默認的刷新模式是可以改變的,具體請
考參下節。

如果你需要在事務提交之前將更新刷新到數據庫中,你可以直接地調用EntityManager.flush()方法。這種情況下,你可以手工地來刷新數據 庫以獲得對數據庫操作的最大控制。
public void updatePerson(Person person) {
try {
Person person = em.find(Person.class, 2);
person.setName("lihuoming");
em.merge(person);
em.flush();//手動將更新立刻刷新進數據庫

//後面還有衆多修改操作
} catch (Exception e) {
e.printStackTrace();
}
}


11)             改變實體管理器的Flush模式 —— setFlushMode()

的Flush模式有2種類型:AUTO and COMMIT。AUTO爲缺省模式。你可以改變他的值,如下:
entityManager.setFlushMode(FlushModeType.COMMIT);

FlushModeType.AUTO:刷新在查詢語句執行前(除了find()和getreference()查詢)或事務提交時才發生,使用場合:在 大量更新數據的過程中沒有任何查詢語句(除了find()和getreference()查詢)的執行。

FlushModeType.COMMIT:刷新只有在事務提交時才發生,使用場合:在大量更新數據的過程中存在查詢語句(除了find()和 getreference()查詢)的執行。

其實上面兩種模式最終反映的結果是:JDBC 驅動跟數據庫交互的次數。JDBC 性能最大的增進是減少JDBC 驅動與數據庫之間的網絡通訊。FlushModeType.COMMIT模式使更新只在一次的網絡交互中完成,而FlushModeType.AUTO 模式可能需要多次交互(觸發了多少次Flush 就產生了多少次網絡交互)

12)             獲取持久化實現者的引用 —— getDelegate()

用過getDelegate()方法,你可以獲取EntityManager持久化實現者的引用,如Jboss EJB3的持久化產品採用Hibernate,可以通過getDelegate()方法獲取對他的訪問,如:
HibernateEntityManager manager = (HibernateEntityManager)em.getDelegate();

獲得對Hibernate的引用後,可以直接面對Hibernate進行編碼,不過這種方法並不可取,強烈建議不要使用。在Weblogic 中,你也可以通過此方法獲取對Kodo 的訪問。

轉自:EntityManager使用方法

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