Session bean or MD bean對Entity bean的操作包括所有的query insert update delete操作都是通過EntityManager執行個體來完成的EntityManager是由EJB 容器自動地管理和配置的不需要使用者自己建立 請注意Entity Bean被EntityManager管理時EntityManager會跟蹤他的狀態改變在任何決定更新實體Bean的時候便會把發生改變的值同步 到資料庫中跟hibernate一樣但是如果entity Bean從EntityManager分離後他是不受管理的EntityManager無法跟蹤他的任何狀態改變 1get entity find or getReference 2insert persist 3update 分2種情況 執行emmergeperson方法時容器的工作規則 4Delete Remove 5HPQL query createQuery 7Refresh entity refresh 8Check entity是否在EntityManager管理當中 contains 9分離所有當前正在被管理的實體 clear 10 將實體的改變立刻重新整理到資料庫中 flush 11 改變實體管理器的Flush模式 setFlushMode 12 擷取持久化實現者的引用 getDelegate
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 的訪問。