/**
持久化服務
1.託管與非託管實體
Persistener context是由一組受託管的實體對象實例所構成的集合,他受entity manager的管理.一旦persistent context被
關閉,所有的實體對象都會脫離EntityManager而成為非託管對象.JPA中有兩種類型的persistent context,分別是
i.transaction-scoped persistence
他只能在事物範圍內存在著,他們會在事務結束后被關閉,transaction-scope persistent將被銷毀,託管實體對象實例也將處於
只有受伺服器管理的persistent context才可以是事物範圍的,換言之,必須被註解@PersistentContext表示的EntityManager實
列才可以是事務管理的.看代碼.
*/ @persistenceContext(UnitName="EntityName") EntityManager entityManager; @TransactionAttribute(REQUIRED) public Customer someMethod(){ Customer cust = entityManager.find(Customer.class,new Integer(1)); cust.setName("new name"); return cust; } /** |
由entityManager返回的Customer實例會在整個JTA事物內保持存在姿態,當JTA事務完成後,有setName調用引起的數據更改會被同步
到資料庫中.entityManager對象將會被銷毀,改對象不在託管了.
ii.Extented persistent context
我們也可以將persistent context配置成超出事務的範圍,與Extented persistent context向關聯的對象會一直保持託管狀態,甚至
在事務提交后也是如此,在某些場景下特別有用,你想保持資料庫連接,又不希望使用長事務,長事務會在佔用JDBC連接,這樣的數據
寶貴資源.
2.為persistent Unit打包
每個EntityManager負責將一定數量的一組類映射到資料庫中,這組類就叫做persistent Unit.它是在persistent.xml文件中定義的,根據
JPA標準的要求,改部署文件是必須的.一個persistent.xml可以定義一個或多個persistent unit.他被放在各類的文件的meta-inf目錄中.
每個persistent unit只能關聯一個且僅一個數據源,在javaEE環境中,我們通過persistent.xml文件來配置,下面我們來分析下persistent
.xml文件的格式.
<?xml version="1.0" encoding="GBK"?> <persistence> <persistence-unit name="" transaction-type=""> <description></description> <provider></provider> <class></class> <mapping-file /> <jar-file /> <property name=""></property> </persistence-unit> </persistence> |
參看上面的代碼,name定義了unit的引用名,,提供注入用註解.該屬性是必須的.屬性transaction-type指明了你是希望persistent unit受JavaEE事務管理
並與之集成,還是使用resource-local來管理.後者在JavaSE環境中使用.provider指定了實現javax.persistence.PersistenceProvider介面的類的全局
限定名稱.property元素定義了一組廠商的專有屬性.建議使用class元素來定義需要映射到關係資料庫中的類.
3.獲得EntityManager
如果是在EJB環境中應用JPA,強烈建議使用@PersistenceContext註解或等價的XML描述.看代碼:
*/ @Stateless public class MySessionBean implements MySessionRemote{ @PersistenceContext(unitName="titan") private EntityManager entitymanager; ... } /** |
需要注意的是:默認情況下,在使用@PersistenceContext註解時,容器會將一個transaction-scoped類型的persistent context注入EJB.類型為Extended的Entity
Manager只能注入到statefull session bean中.看代碼:
*/ @Stateful public class MyStatefulBean implements MyStatefulRemote{ @PersistenceContext(unitName="titan", type=PersistenceContextType.EXTENDED) private EntityManager entitymanager; ... } |
4.操作EntityManager
i.持久化實體:就是將對象插入到資料庫中,你所持久化的還是未曾保持到資料庫中的實體,要持久化實體,要為實體分配內存,然後設置成員屬性,並設置好與其他
對象可能存在的任何關聯關係,你就可以調用EntityManager.persist()方法來保持該實體了.
*/ Customer cust = new Customer(); cust.setName("Bill"); entityManager.persist(cust); /** |
當調用persist()方法后,EntityManager會將Customer添加到等待資料庫插入的隊列中,對象實例即處於託管狀態,實際的操作要看:如果實在事務範圍內調用,插入操作
可能馬上就執行,也可能在事務提交時執行,這依賴於flush模式,任何時候你都可以通過flush操作在一個事務內強制插入操作.
ii.查找實體:提供了2種方法:find(),getReference().
*/ public interface EntityManager{ T find(Class entityClass, Object primayKey); T getReference(Class entityClass, Object primarykey); } /** |
2個方法都接受實體的class和代表實體主鍵的對象作為參數,區別是如果找不到指定實體時,find方法會返回null,getReference方法會拋出javax.persistent.EntityNotFound
Exception,並且該方法並不保證實例的內部狀態不會被初始化.若是transaction-scope persistence contenxt,則返回遊離對象(記住是在事務範圍之外調用這2個方法).
*/ Customer cust = entityManager.find(Customer.class,1); /** |
我們還可以使用EJB QL來查詢,使用CreateNativeQuery()來創建Query對象來進行查詢.
*/ Query query = entityManager.CreateQuery("FROM Customer c WHERE id=2"); Customer cust = (Customer)query.getSingleResult(); /** |
由於你一旦調用了find(),getResource()方法,或使用查詢對象執行了一次查詢,所得的entity bean 在persisten測 context關閉前仍將處於託管狀態,在此期間,你可以像其他
對象那樣隨便更改entity bean實例的狀態,任何更改都將自動過手動地同步到資料庫中.
iii.合併實體:你可以使用EntityManager的meger()方法,將遊離實體的狀態合併到資料庫中,假設有一個Swing客戶端,它調用了TravleAgent Session bean的遠程方法,用以查找
資料庫中的cabinet實體.看代碼:
*/ @persistenceContext EntityManager entityManager; @TransactionAttribute(REQUIRED) public Cabin findCabin(int pid){ return entityManager.find(Cabin.class, pid); } /** |
在findCabin()結束后,persistence context被銷毀,entity bean 處於非託管狀態,當Cabin實例被序列化,並被送到遠程的Swing客戶端,此時,該Cabin實例是一個普通的Java對象
.Swing客戶端更改了這一Cabin實例的狀態,然後將其重新送回伺服器.看代碼:
*/ Cabin cabin = trvalAgent.findCabin(1); cabin.setBedCount(4); trvalAgent.updateCabin(cabin); //--------------------------------------------// @persistenceContext EntityManager entityManager; @TransactionAttribute(REQUIRED) public void updateCabin(Cabin cabin){ Cabin copy = entityManager.merge(cabin); } /** |
需要注意2中情況:
1.若EntityManager未曾管理與傳入的cabin參數有著相同的Cabin實例,則merge()方法會創建該參數的一份完整拷貝做為方法的返回值,該拷貝受entityManager對象的管理,並且任何
針對該份操作做的更改,而傳入的cabin參數仍將保持遊離狀態,不受託管.
2.若擁有與傳入的Cabin參數有著相同的Cabin實例,則託管到託管的對象實例中,其餘的同上操作.
本文出自 「stoneli88」 博客http://stoneli88.blog.51cto.com/333387/220543
[火星人 ] 編程基礎:JPA學習筆記(二)已經有1040次圍觀