JPA 教程(三)

JPA的編程結構及重要的API

JavaEE 5.0中所定義的JPA接口個數並不多,它們位於javax.persistence和javax.persistence.spi兩個包中。 javax.persistence包中大部分API都是註解類,除此之外還包括EntityManager、Query等持久化操作接口。

而 javax.persistence.spi包中的4個API,是JPA的服務層接口。

 

下面,我們就來認識一下這些重要的接口

 

EntityManager的類型實體對象由實體管理器進行管理,JPA使用javax.persistence.EntityManager代表實體管理器。

實體管理器和持久化上下文關聯,持久化上下文是一系列實體的管理環境,我們通過EntityManager和持久化上下文進行交互。

 

有兩種類型的實體管理器:

容器型: 容器型的實體管理器由容器負責實體管理器之間的協作,在一個JTA事務中,一個實體管理器的持久化上下文的狀態會自動廣播到所有使用EntityManager的應用程序組件中。Java EE應用服務器提供的就是管理型的實體管理器;

應用程序型: 實體管理器的生命週期由應用程序控制,應用程序通過javax.persistence.EntityManagerFactory的createEntityManager創建EntityManager實例。

 

EntityManager的創建過程 
javax.persistence.spi.PersistenceProvider接口由JPA的實現者提供,該接口由啓動者調用,以便創建一個EntityManagerFactory實例。

 

它定義了創建一個EntityManagerFactory實例的方法:
EntityManagerFactorycreateContainerEntityManagerFactory(PersistenceUnitInfo info, Map map)
javax.persistence.spi.PersistenceUnitInfo入參提供了創建實體管理器所需要的所有信息,這些信息根據JPA的規範,必須放置在META-INF/persistence.xml文件中。


PersistenceUnitInfo接口擁有了一個void addTransformer(ClassTransformer transformer)方法,通過該方式可以添加一個javax.persistence.spi.ClassTransformer,並通過 PersistenceProvider開放給容器,以便容器在實體類文件加載到JVM之前進行代碼的增強,使元數據生效。

 

JPA廠商負責提供 ClassTransformer接口的實現。

 

實體的狀態 
實體對象擁有以下4個狀態,這些狀態通過調用EntityManager接口方法發生遷移:
新建態: 新創建的實體對象,尚未擁有持久化主鍵,沒有和一個持久化上下文關聯起來。

受控態: 已經擁有持久化主鍵並和持久化上下文建立了聯繫;

遊離態: 擁有持久化主鍵,但尚未和持久化上下文建立聯繫;

刪除態: 擁有持久化主鍵,已經和持久化上下文建立聯繫,但已經被安排從數據庫中刪除。

 

EntityManager 的API

 

Java代碼  收藏代碼
  1. void persist(Object entity)  

通過調用EntityManager的persist()方法,新實體實例將轉換爲受控狀態。這意謂着當persist ()方法所在的事務提交時,實體的數據將保存到數據庫中。如果實體已經被持久化,那麼調用persist()操作不會發生任何事情。如果對一個已經刪除的實體調用persist()操作,刪除態的實體又轉變爲受控態。如果對遊離狀的實體執行persist()操作,將拋出 IllegalArgumentException。

在一個實體上調用persist()操作,將廣播到和實體關聯的實體上,執行相應的級聯持久化操作;

 

Java代碼  收藏代碼
  1. void remove(Object entity)  

通過調用remove()方法刪除一個受控的實體。如果實體聲明爲級聯刪除(cascade=REMOVE 或者cascade=ALL ),被關聯的實體也會被刪除。在一個新建狀態的實體上調用remove()操作,將被忽略。如果在遊離實體上調用remove()操作,將拋出 IllegalArgumentException,相關的事務將回滾。 如果在已經刪除的實體上執行remove()操作,也會被忽略;

 

Java代碼  收藏代碼
  1. void flush()  

將受控態的實體數據同步到數據庫中;

 

Java代碼  收藏代碼
  1. T merge(T entity)  

 將一個遊離態的實體持久化到數據庫中,並轉換爲受控態的實體;

 

Java代碼  收藏代碼
  1. T find(Class entityClass, Object primaryKey)  

 以主鍵查詢實體對象,entityClass是實體的類,primaryKey是主鍵值,如以下的代碼查詢Topic實體:

Java代碼  收藏代碼
  1. Topic t = em.find(Topic.class,1);  
  2. Query createQuery(String qlString)  

 

Query 
JPA使用javax.persistence.Query接口代表一個查詢實例,Query實例由EntityManager通過指定查詢語句構建。該接口擁有衆多執行數據查詢的接口方法:
◆Object getSingleResult():執行SELECT查詢語句,並返回一個結果;

◆List getResultList() :執行SELECT查詢語句,並返回多個結果;

◆Query setParameter(int position, Object value):通過參數位置號綁定查詢語句中的參數,如果查詢語句使用了命令參數,則可以使用Query setParameter(String name, Object value)方法綁定命名參數;

◆Query setMaxResults(int maxResult):設置返回的最大結果數;

◆int executeUpdate():如果查詢語句是新增、刪除或更改的語句,通過該方法執行更新操作;

 

 

JPA的查詢語言 
JPA的查詢語言是面向對象而非面向數據庫的,它以面向對象的自然語法構造查詢語句 ,可以看成是Hibernate HQL的等價物。

Sql代碼  收藏代碼
  1. SELECT DISTINCT t FROM Topic t WHERE t.topicTitle = ?1  

通過WHERE指定查詢條件,?1表示用位置標識參數,爾後,我們可以通過Query的setParameter(1, "主題1")綁定參數。而DISTINCT表示過濾掉重複的數據。

如果需要以命名綁定綁定數據,可以改成以下的方式:

Sql代碼  收藏代碼
  1. SELECT DISTINCT t FROM Topic t WHERE t.topicTitle = :title  

這時,需要通過Query的setParameter("title", "主題1")綁定參數。

 

關聯查詢:從One的一方關聯到Many的一方

返回PollOptions對應的PollTopic對象,可以使用以下語句:

Sql代碼  收藏代碼
  1. SELECT DISTINCT p FROM PollTopic p, IN(p.options) o WHERE o.optionItem LIKE ?1  

這個語法和SQL以及HQL都有很大的區別,它直接實體屬性連接關聯的實體,這裏我們通過PollTopic的options屬性關聯到PollOption實體上,對應的SQL語句爲:

Sql代碼  收藏代碼
  1. SELECT DISTINCT t0.TOPIC_ID, t0.TOPIC_TYPE, t0.TOPIC_TITLE,  
  2. t0.TOPIC_TIME, t0.TOPIC_VIEWS, t0.MULTIPLE, t0.MAX_CHOICES   
  3.   
  4. FROM T_TOPIC t0,T_POLL_OPTION t1   
  5.   
  6. WHERE (((t1.OPTION_ITEM LIKE ?) AND (t0.TOPIC_TYPE = ?))  
  7. AND (t1.TOPIC_ID = t0.TOPIC_ID))  

該查詢語句的另外兩種等價的寫法分別是:

Sql代碼  收藏代碼
  1. SELECT DISTINCT p FROM PollTopic p JOIN p.options o WHERE o.optionItem LIKE ?1  
  2.   
  3. 和  
  4.   
  5. SELECT DISTINCT p FROM PollTopic p WHERE p.options.optionItem LIKE ?1  

 

關聯查詢:從Many的一方關聯到One的一方

從Many一方關聯到One一方的查詢語句和前面所講的也很相似。如我們希望查詢某一個調查主題下的所示調查項,則可以編寫以下的查詢語句:

Sql代碼  收藏代碼
  1. SELECT p FROM PollOption p JOIN p.pollTopic t WHERE t.topicId = :topicId  

 

小結

在不久的將來,Sun可能會將JPA作爲一個單獨的JSR對待,同時JPA還可能作爲Java SE的一部分。不過這些都不太重要,重要的是,我們現在已經可以在脫離容器的情況下、在Java SE應用中使用JPA了。
JPA已經作爲一項對象持久化的標準,不但可以獲得Java EE應用服務器的支持,還可以直接在Java SE中使用。開發者將無需在現有多種ORM框架中艱難地選擇, 這對開發人員來說是個福音。

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