JPA重整ORM山河

1.JPA概述 
JPA(Java Persistence API)做爲Java EE 5.0平臺標準的ORM規範,將獲得全部Java EE服務器的支持。Sun此次吸收了以前EJB規範慘痛失敗的經歷,在充分吸取現有ORM框架的基礎上,獲得了一個易於使用、伸縮性強的ORM規範。從目前的開發社區的反應上看,JPA受到了極大的支持和讚賞,JPA做爲ORM領域標準化整合者的目標應該不難實現。 
JPA經過JDK 5.0註解或XML描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中,圖 1很好地描述了JPA的結構:
Sun引入新的JPA ORM規範出於兩個緣由:其一,簡化現有Java EE和Java SE應用的對象持久化的開發工做;其二,Sun但願整合對ORM技術,實現天下歸一。 
JPA由EJB 3.0軟件專家組開發,做爲JSR-220實現的一部分。但它不囿於EJB 3.0,你能夠在Web應用、甚至桌面應用中使用。JPA的宗旨是爲POJO提供持久化標準規範,因而可知,通過這幾年的實踐探索,可以脫離容器獨立運行,方便開發和測試的理念已經深刻人心了。目前Hibernate 3.二、TopLink 10.1.3以及OpenJpa都提供了JPA的實現。
JPA的整體思想和現有Hibernate、TopLink,JDO等ORM框架大致一致。總的來講,JPA包括如下3方面的技術: 
ORM映射元數據,JPA支持XML和JDK 5.0註解兩種元數據的形式,元數據描述對象和表之間的映射關係,框架據此將實體對象持久化到數據庫表中; 
JPA 的API,用來操做實體對象,執行CRUD操做,框架在後臺替咱們完成全部的事情,開發者從繁瑣的JDBC和SQL代碼中解脫出來。 
查詢語言,這是持久化操做中很重要的一個方面,經過面向對象而非面向數據庫的查詢語言查詢數據,避免程序的SQL語句緊密耦合。 
2.實體對象 
訪問數據庫前,咱們老是要設計在應用層承載數據的領域對象(Domain Object),ORM框架將它們持久化到數據庫表中。爲了方便後面的講解,咱們用論壇應用爲例,創建如下的領域對象:
Topic是論壇的主題,而PollTopic是調查性質的論壇主題,它擴展於Topic,一個調查主題擁有多個選項PollOption。這三個領域對象很好地展示了領域對象之間繼承和關聯這兩大核心的關係。這3個領域對象將被映射到數據庫的兩張表中:
其中,Topic及其子類PollTopic將映射到同一張t_topic表中,並用topic_type字段區分二者。而PollOption映射到t_polloption中。
具備ORM元數據的領域對象稱爲實體(Entity),按JPA的規範,實體具有如下的條件: 
必須使用javax.persistence.Entity註解或者在XML映射文件中有對應的 元素; 
必須具備一個不帶參的構造函數,類不能聲明爲final,方法和須要持久化的屬性也不能聲明爲final;
若是遊離狀的實體對象須要以值的方式進行傳遞,如通Session bean的遠程業務接口傳遞,則必須實現Serializable接口; 
須要持久化的屬性,其訪問修飾符不能是public,它們必須經過實體類方法進行訪問。
 
3.使用註解元數據 
基本註解 
首先,咱們對Topic領域對象進行註解,使其成爲一個合格的實體類: 
代碼清單1:Topic實體類的註解
       
       
       
       
package com.baobaotao.domain;



import javax.persistence.Column;

import javax.persistence.DiscriminatorColumn;

import javax.persistence.DiscriminatorType;

import javax.persistence.DiscriminatorValue;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Inheritance;

import javax.persistence.InheritanceType;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;
@Entity(name = "T_TOPIC") ①

public class Topic implements Serializable ...{

@Id   ②-1

@GeneratedValue(strategy = GenerationType.TABLE) ②-2

@Column(name = "TOPIC_ID") ②-3

private int topicId;
@Column(name = "TOPIC_TITLE", length = 100) ③

private String topicTitle;
@Column(name = "TOPIC_TIME")

@Temporal(TemporalType.DATE) ④

private Date topicTime;
@Column(name = "TOPIC_VIEWS")

private int topicViews;
//省略get/setter方法

}
@Entity:將領域對象標註爲一個實體,表示須要保存到數據庫中,默認狀況下類名即爲表名,經過name屬性顯式指定表名,如①處的name = "T_TOPIC",表示Topic保存到T_TOPIC表中;

@Id :對應的屬性是表的主鍵,如②-1所示;

@GeneratedValue:主鍵的產生策略,經過strategy屬性指定。默認狀況下,JPA自動選擇一個最適合底層數據庫的主鍵生成策略,如SqlServer對應identity,MySql對應auto increment。在javax.persistence.GenerationType中定義瞭如下幾種可供選擇的策略:
1) IDENTITY:表自增鍵字段,Oracle不支持這種方式;

2) AUTO: JPA自動選擇合適的策略,是默認選項;

3) SEQUENCE:經過序列產生主鍵,經過@SequenceGenerator註解指定序列名,MySql不支持這種方式;

4) TABLE:經過表產生主鍵,框架藉由表模擬序列產生主鍵,使用該策略可使應用更易於數據庫移植。不一樣的JPA實現商生成的表名是不一樣的,如OpenJPA生成openjpa_sequence_table表Hibernate生成一個hibernate_sequences表,而TopLink則生成sequence表。這些表都具備一個序列名和對應值兩個字段,如SEQ_NAME和SEQ_COUNT。
@Column(name = "TOPIC_ID"):屬性對應的表字段。咱們並不須要指定表字段的類型,由於JPA會根據反射從實體屬性中獲取類型;若是是字符串類型,咱們能夠指定字段長度,以即可以自動生成DDL語句,如③處所示;

@Temporal(TemporalType.DATE):若是屬性是時間類型,由於數據表對時間類型有更嚴格的劃分,因此必須指定具體時間類型,如④所示。在javax.persistence.TemporalType枚舉中定義了3種時間類型: 
1) DATE :等於java.sql.Date

2) TIME :等於java.sql.Time

3) TIMESTAMP :等於java.sql.Timestamp 
繼承關係 
Topic和PollTopic是父子類,JPA 採用多種方法來支持實體繼承。在父類中必須聲明繼承實體的映射策略,如代碼清單2所示: 
代碼清單2:繼承實體的映射策略
       
       
       
       


@Entity(name = "T_TOPIC")

@Inheritance(strategy = InheritanceType.SINGLE_TABLE) ①

@DiscriminatorColumn(name = "TOPIC_TYPE", discriminatorType =   
DiscriminatorType.INTEGER, length = 1) ②

@DiscriminatorValue(value="1")③

public class Topic implements Serializable ...{



}
對於繼承的實體,在javax.persistence.InheritanceType定義了3種映射策略: 
SINGLE_TABLE:父子類都保存到同一個表中,經過字段值進行區分。這是咱們Topic實體所採用的策略,Topic和PollTopic都保存到同一張表中,經過TOPIC_TYPE字段進行區分,Topic在T_TOPIC表中對應TOPIC_TYPE=1的記錄,而PollTopic對應TOPIC_TYPE=2的記錄(稍後在PollTopic實體中指定);區別的字段經過@DiscriminatorColumn說明,如②所示,區分字段對應該實體的值經過@DiscriminatorValue指定,如③所示; 
JOINED:父子類相同的部分保存在同一個表中,不一樣的部分分開存放,經過錶鏈接獲取完整數據; 
TABLE_PER_CLASS:每個類對應本身的表,通常不推薦採用這種方式。
 
關聯關係 
咱們再繼續對PollTopic進行註解,進一步瞭解實體繼承的JPA映射定義: 
代碼清單3:PollTopic映射描述
       
       
       
       
package com.baobaotao.domain;



@Entity

@DiscriminatorValue(value="2") ①

public class PollTopic extends Topic ...{②繼承於Topic實體

private boolean multiple; ③

@Column(name = "MAX_CHOICES")

private int maxChoices;

@OneToMany(mappedBy="pollTopic",cascade=CascadeType.ALL) ④

private Set options = new HashSet ();

//省略get/setter方法

}
在①處,經過@DiscriminatorValue將區分字段TOPIC_TYPE的值爲2。因爲PollTopic實體繼承於Topic實體,其它的元數據信息直接從Topic得到。 
JPA規範規定任何屬性都默認映射到表中,因此雖然咱們沒有給③處的multiple屬性提供註解信息,但JPA將按照默認的規則對該字段進行映射:字段名和屬性名相同,類型相同。若是咱們不但願將某個屬性持久化到數據表中,則能夠經過@Transient註解顯式指定: 
@Transient 
private boolean tempProp1; 
在④處,咱們經過@OneToMany指定了一個一對多的關聯關係,一個PollTopic包括多個PollOption對象(咱們將在稍後的PollOption中經過ManyToOne描述PollOption和PollTopic的關係,以創建PollTopic和PollOption的雙向關聯關係)。

@OneToMany中經過mappedBy屬性指定「Many」方類引用「One」方類的屬性名,這裏mappedBy="pollTopic"表示PollOption實體擁有一個指定PollTopic的pollTopic屬性。 
下面,咱們來看一下Many方PollOption實體類的映射描述:
代碼清單4:PollOption映射描述
       
       
       
       
package com.baobaotao.domain;



@Entity(name="T_POLL_OPTION")

public class PollOption implements Serializable ...{

@Id

@GeneratedValue(strategy = GenerationType.TABLE)

@Column(name = "OPTION_ID")

private int optionId;
@Column(name = "OPTION_ITEM")

private String optionItem;
@ManyToOne  ①

@JoinColumn(name="TOPIC_ID", nullable=false) ②

private PollTopic pollTopic;

}
在①處經過@ManyToOne描述了PollOption和PollTopic的多對一關聯關係,並經過@JoinColumn指定關聯PollTopic實體所對應表的「外鍵」,如②所示。 
固然也能夠經過@OneToOne和@ManyToMany指定一對一和多以多的關係,方法差很少,再也不贅述。
Lob字段 
在JPA中Lob類型類型的持久化很簡單,僅須要經過特殊的Lob註解就能夠達到目的。下面,咱們對Post中的Lob屬性類型進行標註: 
代碼清單5 Post:標註Lob類型屬性
       
       
       
       
package com.baobaotao.domain;



import javax.persistence.Basic;

import javax.persistence.Lob;

@Entity(name = "T_POST")

public class Post implements Serializable ...{



@Lob ①-1

@Basic(fetch = FetchType.EAGER) ①-2

@Column(name = "POST_TEXT", columnDefinition = "LONGTEXT NOT NULL") ①-3

private String postText;
@Lob ②-1

@Basic(fetch = FetchType. LAZY) ②-2

@Column(name = "POST_ATTACH", columnDefinition = "BLOB") ②-3

private byte[] postAttach;



}
postText屬性對應T_POST表的POST_TEXT字段,該字段的類型是LONTTEXT,而且非空。JPA經過@Lob將屬性標註爲Lob類型,如①-1和②-1所示。經過@Basic指定Lob類型數據的獲取策略,FetchType.EAGER表示非延遲加載,而FetchType. LAZY表示延遲加載,如①-2和②-2所示。經過@Column的columnDefinition屬性指定數據表對應的Lob字段類型,如①-3和②-3所示。 
關於JPA註解的更多信息,你能夠經過這篇文章進行更加深刻的學習: [url]http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html[/url] 
 
4.使用XML元數據 
除了使用註解提供元數據信息外,JPA也容許咱們經過XML提供元數據信息。條條道路通羅馬,路路都是安康道,開發者安全能夠根據本身的習慣喜愛擇一而從。按照JPA的規範,若是你提供了XML元數據描述信息,它將覆蓋實體類中的註解元數據信息。XML元數據信息以orm.xml命名,放置在類路徑的META-INF目錄下。 
JPA儘可能讓XML和註解的元數據在描述的結構上相近,下降學習曲線和轉換難度,因此咱們在學習註解元數據後,學習XML元數據變得很是簡單。下面,咱們給出以上實體的XML描述版本,你能夠對照註解的描述進行比較學習: 
代碼清單6 XML元數據配置:orm.xml

[url]http://java.sun.com/xml/ns/persistence/orm[/url]"

xmlns:xsi=" [url]http://www.w3.org/2001/XMLSchema-instance[/url]"

xsi:schemaLocation=" [url]http://java.sun.com/xml/ns/persistence/orm[/url]    
[url]http://java.sun.com/xml/ns/persistence/orm_1_0.xsd[/url]"

version="1.0">

①實體對象所在的包

com.baobaotao.domain

②Topic實體配置





DATE ②PollTopic實體配置2 ②PollOption實體配置

  ②Post實體配置

從代碼清單6中,咱們能夠看出PollTopic並不須要經過特殊配置指定和Topic的繼承關係,這些信息將從實體類反射信息獲取。因此從嚴格意義上來講,元數據信息或XML和實體類結構信息共同構成的。
 
5.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實例的方法: 
EntityManagerFactory createContainerEntityManagerFactory(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的過程:
實體的狀態 
實體對象擁有如下4個狀態,這些狀態經過調用EntityManager接口方法發生遷移: 
新建態:新建立的實體對象,還沒有擁有持久化主鍵,沒有和一個持久化上下文關聯起來。

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

遊離態:擁有持久化主鍵,但還沒有和持久化上下文創建聯繫;

刪除態:擁有持久化主鍵,已經和持久化上下文創建聯繫,但已經被安排從數據庫中刪除。
EntityManager 的API 
下面是EntityManager的一些主要的接口方法: 
void persist(Object entity) 
經過調用EntityManager的persist()方法,新實體實例將轉換爲受控狀態。這意謂着當persist()方法所在的事務提交時,實體的數據將保存到數據庫中。若是實體已經被持久化,那麼調用persist()操做不會發生任何事情。若是對一個已經刪除的實體調用persist()操做,刪除態的實體又轉變爲受控態。若是對遊離狀的實體執行persist()操做,將拋出IllegalArgumentException。
在一個實體上調用persist()操做,將廣播到和實體關聯的實體上,執行相應的級聯持久化操做; 
void remove(Object entity)
經過調用remove()方法刪除一個受控的實體。若是實體聲明爲級聯刪除(cascade=REMOVE 或者cascade=ALL ),被關聯的實體也會被刪除。在一個新建狀態的實體上調用remove()操做,將被忽略。若是在遊離實體上調用remove()操做,將拋出IllegalArgumentException,相關的事務將回滾。若是在已經刪除的實體上執行remove()操做,也會被忽略; 
void flush()
將受控態的實體數據同步到數據庫中; 
T merge(T entity)
將一個遊離態的實體持久化到數據庫中,並轉換爲受控態的實體; 
T find(Class entityClass, Object primaryKey)
以主鍵查詢實體對象,entityClass是實體的類,primaryKey是主鍵值,如如下的代碼查詢Topic實體:
Topic t = em.find(Topic.class,1); 
Query createQuery(String qlString)
根據JPA的查詢語句建立一個查詢對象Query,以下面的代碼:
       
       
       
       
Query q= em.createQuery(""SELECT t FROM Topic t
WHERE t.topicTitle LIKE :topicTitle")"); 
Query createNativeQuery(String sqlString)
使用本地數據庫的SQL語句建立一個Query對象,Query經過getResultList()方法執行查詢後,返回一個List結果集,每一行數據對應一個Vector。 
使用本地數據庫的SQL語句建立一個Query對象,Query經過getResultList()方法執行查詢後,返回一個List結果集,每一行數據對應一個Vector。 
 
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():若是查詢語句是新增、刪除或更改的語句,經過該方法執行更新操做;
6.JPA的查詢語言
JPA的查詢語言是面向對象而非面向數據庫的,它以面向對象的天然語法構造查詢語句,能夠當作是Hibernate HQL的等價物。 
簡單的查詢 
你可使用如下語句返回全部Topic對象的記錄: 
SELECT t FROM Topic t 
t表示Topic的別名,在Topic t是Topic AS t的縮寫。 
若是須要按條件查詢Topic,咱們可使用: 
SELECT DISTINCT t FROM Topic t WHERE t.topicTitle = ?1 
經過WHERE指定查詢條件,?1表示用位置標識參數,爾後,咱們能夠經過Query的setParameter(1, "主題1")綁定參數。而DISTINCT表示過濾掉重複的數據。 
若是須要以命名綁定綁定數據,能夠改爲如下的方式:
SELECT DISTINCT t FROM Topic t WHERE t.topicTitle = :title 
這時,須要經過Query的setParameter("title", "主題1")綁定參數。 
關聯查詢:從One的一方關聯到Many的一方 
返回PollOptions對應的PollTopic對象,可使用如下語句: 
SELECT DISTINCT p FROM PollTopic p, IN(p.options) o WHERE o.optionItem LIKE ?1 
這個語法和SQL以及HQL都有很大的區別,它直接實體屬性鏈接關聯的實體,這裏咱們經過PollTopic的options屬性關聯到PollOption實體上,對應的SQL語句爲: 
       
       
       
       
SELECT DISTINCT t0.TOPIC_ID, t0.TOPIC_TYPE, t0.TOPIC_TITLE,
t0.TOPIC_TIME, t0.TOPIC_VIEWS, t0.MULTIPLE, t0.MAX_CHOICES FROM T_TOPIC t0,
T_POLL_OPTION t1 WHERE (((t1.OPTION_ITEM LIKE ?) AND (t0.TOPIC_TYPE = ?))
AND (t1.TOPIC_ID = t0.TOPIC_ID)) 
該查詢語句的另外兩種等價的寫法分別是: 
       
       
       
       
SELECT DISTINCT p FROM PollTopic p JOIN p.options o WHERE o.optionItem LIKE ?1
       
       
       
       
SELECT DISTINCT p FROM PollTopic p WHERE p.options.optionItem LIKE ?1 
關聯查詢:從Many的一方關聯到One的一方 
從Many一方關聯到One一方的查詢語句和前面所講的也很類似。如咱們但願查詢某一個調查主題下的所示調查項,則能夠編寫如下的查詢語句: 
       
       
       
       
SELECT p FROM PollOption p JOIN p.pollTopic t WHERE t.topicId = :topicId
對應的SQL語句爲:
       
       
       
       
SELECT t0.OPTION_ID, t0.OPTION_ITEM, t0.TOPIC_ID FROM T_POLL_OPTION t0,
TOPIC t1 WHERE ((t1.TOPIC_ID = ?)
AND ((t1.TOPIC_ID = t0.TOPIC_ID) AND (t1.TOPIC_TYPE = ?))) 
使用其它的關係操做符 
使用空值比較符,好比查詢附件不空的全部帖子對象: 
       
       
       
       
SELECT p FROM Post p WHERE p.postAttach IS NOT NULL 
範圍比較符包括BETWEEN..AND和>、>= 、<、<=、<>這些操做符。好比下面的語句查詢瀏覽次數在100到200之間的全部論壇主題: 
SELECT t FROM Topic t WHERE t.topicViews BETWEEN 100 AND 200 
 
集合關係操做符 
和其它實體是One-to-Many或Many-to-Many關係的實體,經過集合引用關聯的實體,咱們能夠經過集合關係操做符進行數據查詢。下面的語句返回全部沒有選項的調查論壇的主題: 
SELECT t FROM PollTopic t WHERE t.options IS EMPTY 
咱們還能夠經過判斷元素是否在集合中進行查詢: 
SELECT t FROM PollTopic t WHERE :option MEMBER OF t.options 
這裏參數必須綁定一個PollOption的對象,JPA會自動將其轉換爲主鍵比較的SQL語句。 
子查詢 
JPA能夠進行子查詢,並支持幾個常見的子查詢函數:EXISTS、ALL、ANY。以下面的語句查詢出擁有6個以上選項的調查主題: 
       
       
       
       
SELECT t FROM PollTopic t WHERE (SELECT COUNT(o) FROM t.options o) > 6
可用函數 
JPA查詢支持一些常見的函數,其中可用的字符串操做函數有: 
◆CONCAT(String, String):合併字段串;

◆LENGTH(String):求字段串的長度;

◆LOCATE(String, String [, start]):查詢字段串的函數,第一個參數爲須要查詢的字段串,看它在出如今第二個參數字符串的哪一個位置,start表示從哪一個位置開始查找,返回查找到的位置,沒有找到返回0。如LOCATE ('b1','a1b1c1',1)返回爲3;

◆SUBSTRING(String, start, length):子字段串函數;

◆TRIM([[LEADING|TRAILING|BOTH] char) FROM] (String):將字段串先後的特殊字符去除,能夠經過選擇決定具體的去除位置和字符;

◆LOWER(String):將字符串轉爲小寫;

◆UPPER(String):將字符串轉爲大寫。
數字操做函數有:
◆ABS(number):求絕對值函數;

◆MOD(int, int):求模的函數;

◆SQRT(double):求平方函數;

◆SIZE(Collection):求集合大小函數。 
更改語句 
能夠用EntityManager進行實體的更新操做,也能夠經過查詢語言執行數據表的字段更新,記錄刪除的操做:
下面的語句將某一個調查選項更新爲新的值: 
UPDATE PollOption p SET p.optionItem = :value WHERE p.optionId = :optionId 
咱們使用Query接口的executeUpdate()方法執行更新。下面的語句刪除一條記錄: 
DELETE FROM PollOption p WHERE p.optionId = :optionId 
排序和分組
咱們還能夠對查詢進行排序和分組。以下面的語句查詢出主題的發表時間大於某個時間值,返回的結果按瀏覽量降序排列:
       
       
       
       
SELECT t FROM Topic t WHERE t.topicTime > :time ORDER BY t.topicViews DESC
下面的語句計算出每一個調查主題對應的選項數目: 
SELECT COUNT(p),p.pollTopic.topicId FROM PollOption p GROUP BY p.pollTopic.topicId
這裏,咱們使用了計算數量的彙集函數COUNT(),其它幾個可用的彙集函數分別爲: 
◆AVG:計算平均值,返回類型爲double;

◆MAX:計算最大值;

◆MIN:計算最小值;

◆SUM:計算累加和;
咱們還能夠經過HAVING對彙集結果進行條件過濾:
       
       
       
       
SELECT COUNT(p),p.pollTopic.topicId
FROM PollOption p GROUP BY p.pollTopic.topicId HAVING
p.pollTopic.topicId IN(1,2,3) 
7.小結 
在不久的未來,Sun可能會將JPA做爲一個單獨的JSR對待,同時JPA還可能做爲Java SE的一部分。不過這些都不過重要,重要的是,咱們如今已經能夠在脫離容器的狀況下、在Java SE應用中使用JPA了。 
JPA已經做爲一項對象持久化的標準,不但能夠得到Java EE應用服務器的支持,還能夠直接在Java SE中使用。開發者將無需在現有多種ORM框架中艱難地選擇,按照Sun的預想,現有ORM框架頭頂的光環將漸漸暗淡,再也不具備以往的吸引力。
相關文章
相關標籤/搜索