<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    love fish大鵬一曰同風(fēng)起,扶搖直上九萬里

    常用鏈接

    統(tǒng)計(jì)

    積分與排名

    friends

    link

    最新評論

    JPA重整ORM山河(l轉(zhuǎn))

    1.JPA概述 
        JPA(Java Persistence API)作為Java EE 5.0平臺標(biāo)準(zhǔn)的ORM規(guī)范,將得到所有Java EE服務(wù)器的支持。Sun這次吸取了之前EJB規(guī)范慘痛失敗的經(jīng)歷,在充分吸收現(xiàn)有ORM框架的基礎(chǔ)上,得到了一個(gè)易于使用、伸縮性強(qiáng)的ORM規(guī)范。從目前的開發(fā)社區(qū)的反應(yīng)上看,JPA受到了極大的支持和贊揚(yáng),JPA作為ORM領(lǐng)域標(biāo)準(zhǔn)化整合者的目標(biāo)應(yīng)該不難實(shí)現(xiàn)。 
        JPA通過JDK 5.0注解或XML描述對象-關(guān)系表的映射關(guān)系,并將運(yùn)行期的實(shí)體對象持久化到數(shù)據(jù)庫中,圖 1很好地描述了JPA的結(jié)構(gòu):


        Sun引入新的JPA ORM規(guī)范出于兩個(gè)原因:其一,簡化現(xiàn)有Java EE和Java SE應(yīng)用的對象持久化的開發(fā)工作;其二,Sun希望整合對ORM技術(shù),實(shí)現(xiàn)天下歸一。 
        JPA由EJB 3.0軟件專家組開發(fā),作為JSR-220實(shí)現(xiàn)的一部分。但它不囿于EJB 3.0,你可以在Web應(yīng)用、甚至桌面應(yīng)用中使用。JPA的宗旨是為POJO提供持久化標(biāo)準(zhǔn)規(guī)范,由此可見,經(jīng)過這幾年的實(shí)踐探索,能夠脫離容器獨(dú)立運(yùn)行,方便開發(fā)和測試的理念已經(jīng)深入人心了。目前Hibernate 3.2、TopLink 10.1.3以及OpenJpa都提供了JPA的實(shí)現(xiàn)。 
        JPA的總體思想和現(xiàn)有Hibernate、TopLink,JDO等ORM框架大體一致??偟膩碚f,JPA包括以下3方面的技術(shù):
    ?     ORM映射元數(shù)據(jù),JPA支持XML和JDK 5.0注解兩種元數(shù)據(jù)的形式,元數(shù)據(jù)描述對象和表之間的映射關(guān)系,框架據(jù)此將實(shí)體對象持久化到數(shù)據(jù)庫表中;
    ?     JPA 的API,用來操作實(shí)體對象,執(zhí)行CRUD操作,框架在后臺替我們完成所有的事情,開發(fā)者從繁瑣的JDBC和SQL代碼中解脫出來。
    ?     查詢語言,這是持久化操作中很重要的一個(gè)方面,通過面向?qū)ο蠖敲嫦驍?shù)據(jù)庫的查詢語言查詢數(shù)據(jù),避免程序的SQL語句緊密耦合。 

        2.實(shí)體對象 
        訪問數(shù)據(jù)庫前,我們總是要設(shè)計(jì)在應(yīng)用層承載數(shù)據(jù)的領(lǐng)域?qū)ο螅―omain Object),ORM框架將它們持久化到數(shù)據(jù)庫表中。為了方便后面的講解,我們用論壇應(yīng)用為例,建立以下的領(lǐng)域?qū)ο螅?


        Topic是論壇的主題,而PollTopic是調(diào)查性質(zhì)的論壇主題,它擴(kuò)展于Topic,一個(gè)調(diào)查主題擁有多個(gè)選項(xiàng)PollOption。這三個(gè)領(lǐng)域?qū)ο蠛芎玫卣宫F(xiàn)了領(lǐng)域?qū)ο笾g繼承和關(guān)聯(lián)這兩大核心的關(guān)系。這3個(gè)領(lǐng)域?qū)ο髮⒈挥成涞綌?shù)據(jù)庫的兩張表中:

        其中,Topic及其子類PollTopic將映射到同一張t_topic表中,并用topic_type字段區(qū)分兩者。而PollOption映射到t_polloption中。
    具有ORM元數(shù)據(jù)的領(lǐng)域?qū)ο蠓Q為實(shí)體(Entity),按JPA的規(guī)范,實(shí)體具備以下的條件:
    ? 必須使用javax.persistence.Entity注解或者在XML映射文件中有對應(yīng)的<entity>元素;
    ? 必須具有一個(gè)不帶參的構(gòu)造函數(shù),類不能聲明為final,方法和需要持久化的屬性也不能聲明為final;
    ? 如果游離狀的實(shí)體對象需要以值的方式進(jìn)行傳遞,如通Session bean的遠(yuǎn)程業(yè)務(wù)接口傳遞,則必須實(shí)現(xiàn)Serializable接口;
    ? 需要持久化的屬性,其訪問修飾符不能是public,它們必須通過實(shí)體類方法進(jìn)行訪問。
    3.使用注解元數(shù)據(jù) 
            基本注解 
        首先,我們對Topic領(lǐng)域?qū)ο筮M(jìn)行注解,使其成為一個(gè)合格的實(shí)體類: 
        代碼清單 1 Topic實(shí)體類的注解
    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:將領(lǐng)域?qū)ο髽?biāo)注為一個(gè)實(shí)體,表示需要保存到數(shù)據(jù)庫中,默認(rèn)情況下類名即為表名,通過name屬性顯式指定表名,如①處的name = "T_TOPIC",表示Topic保存到T_TOPIC表中;
    ? @Id :對應(yīng)的屬性是表的主鍵,如②-1所示;
    ? @GeneratedValue:主鍵的產(chǎn)生策略,通過strategy屬性指定。默認(rèn)情況下,JPA自動選擇一個(gè)最適合底層數(shù)據(jù)庫的主鍵生成策略,如SqlServer對應(yīng)identity,MySql對應(yīng)auto increment。在javax.persistence.GenerationType中定義了以下幾種可供選擇的策略:
    ? 1) IDENTITY:表自增鍵字段,Oracle不支持這種方式;
    ? 2) AUTO: JPA自動選擇合適的策略,是默認(rèn)選項(xiàng);
    ? 3) SEQUENCE:通過序列產(chǎn)生主鍵,通過@SequenceGenerator注解指定序列名,MySql不支持這種方式;
    ? 4) TABLE:通過表產(chǎn)生主鍵,框架借由表模擬序列產(chǎn)生主鍵,使用該策略可以使應(yīng)用更易于數(shù)據(jù)庫移植。不同的JPA實(shí)現(xiàn)商生成的表名是不同的,如OpenJPA生成openjpa_sequence_table表Hibernate生成一個(gè)hibernate_sequences表,而TopLink則生成sequence表。這些表都具有一個(gè)序列名和對應(yīng)值兩個(gè)字段,如SEQ_NAME和SEQ_COUNT。
    ? @Column(name = "TOPIC_ID"):屬性對應(yīng)的表字段。我們并不需要指定表字段的類型,因?yàn)镴PA會根據(jù)反射從實(shí)體屬性中獲取類型;如果是字符串類型,我們可以指定字段長度,以便可以自動生成DDL語句,如③處所示;
    ? @Temporal(TemporalType.DATE):如果屬性是時(shí)間類型,因?yàn)閿?shù)據(jù)表對時(shí)間類型有更嚴(yán)格的劃分,所以必須指定具體時(shí)間類型,如④所示。在javax.persistence.TemporalType枚舉中定義了3種時(shí)間類型:
    ? 1) DATE :等于java.sql.Date
    ? 2) TIME :等于java.sql.Time
    ? 3) TIMESTAMP :等于java.sql.Timestamp

    ? ? 繼承關(guān)系
    ? Topic和PollTopic是父子類,JPA 采用多種方法來支持實(shí)體繼承。在父類中必須聲明繼承實(shí)體的映射策略,如代碼清單 2所示:
    ? 代碼清單 2:繼承實(shí)體的映射策略
    @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 { }
    ?  對于繼承的實(shí)體,在javax.persistence.InheritanceType定義了3種映射策略,:
    ? SINGLE_TABLE:父子類都保存到同一個(gè)表中,通過字段值進(jìn)行區(qū)分。這是我們Topic實(shí)體所采用的策略,Topic和PollTopic都保存到同一張表中,通過TOPIC_TYPE字段進(jìn)行區(qū)分,Topic在T_TOPIC表中對應(yīng)TOPIC_TYPE=1的記錄,而PollTopic對應(yīng)TOPIC_TYPE=2的記錄(稍后在PollTopic實(shí)體中指定);區(qū)別的字段通過@DiscriminatorColumn說明,如②所示,區(qū)分字段對應(yīng)該實(shí)體的值通過@DiscriminatorValue指定,如③所示;
    ? JOINED:父子類相同的部分保存在同一個(gè)表中,不同的部分分開存放,通過表連接獲取完整數(shù)據(jù);
    ? TABLE_PER_CLASS:每一個(gè)類對應(yīng)自己的表,一般不推薦采用這種方式。

    ? ? 關(guān)聯(lián)關(guān)系
    ? 我們再繼續(xù)對PollTopic進(jìn)行注解,進(jìn)一步了解實(shí)體繼承的JPA映射定義:
    ? 代碼清單 3 PollTopic映射描述
    package com.baobaotao.domain; @Entity @DiscriminatorValue(value="2") ① public class PollTopic extends Topic {②繼承于Topic實(shí)體 private boolean multiple; ③ @Column(name = "MAX_CHOICES") private int maxChoices; @OneToMany(mappedBy="pollTopic",cascade=CascadeType.ALL) ④ private Set<PollOption> options = new HashSet<PollOption>(); //省略get/setter方法 }
    ? 在①處,通過@DiscriminatorValue將區(qū)分字段TOPIC_TYPE的值為2。由于PollTopic實(shí)體繼承于Topic實(shí)體,其它的元數(shù)據(jù)信息直接從Topic獲得。
    ? JPA規(guī)范規(guī)定任何屬性都默認(rèn)映射到表中,所以雖然我們沒有給③處的multiple屬性提供注解信息,但JPA將按照默認(rèn)的規(guī)則對該字段進(jìn)行映射:字段名和屬性名相同,類型相同。如果我們不希望將某個(gè)屬性持久化到數(shù)據(jù)表中,則可以通過@Transient注解顯式指定:
    ? ? @Transient
    ? ? private boolean tempProp1;
    ? 在④處,我們通過@OneToMany指定了一個(gè)一對多的關(guān)聯(lián)關(guān)系,一個(gè)PollTopic包括多個(gè)PollOption對象(我們將在稍后的PollOption中通過ManyToOne描述PollOption和PollTopic的關(guān)系,以建立PollTopic和PollOption的雙向關(guān)聯(lián)關(guān)系)。
    ? @OneToMany中通過mappedBy屬性指定“Many”方類引用“One”方類的屬性名,這里mappedBy="pollTopic"表示PollOption實(shí)體擁有一個(gè)指定PollTopic的pollTopic屬性。
    ? 下面,我們來看一下Many方PollOption實(shí)體類的映射描述:
    ? 代碼清單 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的多對一關(guān)聯(lián)關(guān)系,并通過@JoinColumn指定關(guān)聯(lián)PollTopic實(shí)體所對應(yīng)表的“外鍵”,如②所示。
    ? 當(dāng)然也可以通過@OneToOne和@ManyToMany指定一對一和多以多的關(guān)系,方法差不多,不再贅述。
    Lob字段 
        在JPA中Lob類型類型的持久化很簡單,僅需要通過特殊的Lob注解就可以達(dá)到目的。下面,我們對Post中的Lob屬性類型進(jìn)行標(biāo)注: 
        代碼清單 5 Post:標(biāo)注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屬性對應(yīng)T_POST表的POST_TEXT字段,該字段的類型是LONTTEXT,并且非空。JPA通過@Lob將屬性標(biāo)注為Lob類型,如①-1和②-1所示。通過@Basic指定Lob類型數(shù)據(jù)的獲取策略,F(xiàn)etchType.EAGER表示非延遲加載,而FetchType. LAZY表示延遲加載,如①-2和②-2所示。通過@Column的columnDefinition屬性指定數(shù)據(jù)表對應(yīng)的Lob字段類型,如①-3和②-3所示。 
        關(guān)于JPA注解的更多信息,你可以通過這篇文章進(jìn)行更加深入的學(xué)習(xí):    http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html 

        4.使用XML元數(shù)據(jù) 
        除了使用注解提供元數(shù)據(jù)信息外,JPA也允許我們通過XML提供元數(shù)據(jù)信息。條條道路通羅馬,路路都是安康道,開發(fā)者安全可以根據(jù)自己的習(xí)慣喜好擇一而從。按照J(rèn)PA的規(guī)范,如果你提供了XML元數(shù)據(jù)描述信息,它將覆蓋實(shí)體類中的注解元數(shù)據(jù)信息。XML元數(shù)據(jù)信息以orm.xml命名,放置在類路徑的META-INF目錄下。 
        JPA盡量讓XML和注解的元數(shù)據(jù)在描述的結(jié)構(gòu)上相近,降低學(xué)習(xí)曲線和轉(zhuǎn)換難度,所以我們在學(xué)習(xí)注解元數(shù)據(jù)后,學(xué)習(xí)XML元數(shù)據(jù)變得非常簡單。下面,我們給出以上實(shí)體的XML描述版本,你可以對照注解的描述進(jìn)行比較學(xué)習(xí): 
        代碼清單 6 XML元數(shù)據(jù)配置:orm.xml
    <?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
    http://java.sun.com/xml/ns/persistence/orm_1_0.xsd
    " version="1.0"> ①實(shí)體對象所在的包 <package>com.baobaotao.domain</package> <entity class="Topic"> ②Topic實(shí)體配置 <table name="T_TOPIC" /> <attributes> <id name="topicId"> <column name="TOPIC_ID"/> <generated-value strategy="TABLE" /> </id> <basic name="topicTitle"> <column name="TOPIC_TITLE" length="30" /> </basic> <basic name="topicTime"> <column name="TOPIC_TIME" /> <temporal>DATE</temporal> </basic> <basic name="topicViews"> <column name="TOPIC_VIEWS" /> </basic> </attributes> </entity> <entity class="PollTopic"> ②PollTopic實(shí)體配置 <discriminator-value>2</discriminator-value> <attributes> <basic name="maxChoices"> <column name="MAX_CHOICES" /> </basic> <one-to-many name="options" mapped-by="pollTopic"> <cascade> <cascade-all/> </cascade> </one-to-many> </attributes> </entity> <entity class="PollOption"> ②PollOption實(shí)體配置 <table name="T_POLL_OPTION" /> <attributes> <id name="optionId"> <column name="OPTION_ID" /> <generated-value strategy="TABLE" /> </id> <basic name="optionItem"> <column name="OPTION_ITEM"/> </basic> <many-to-one name="pollTopic" > <join-column name="TOPIC_ID" nullable="false"/> </many-to-one> </attributes> </entity> <entity class="Post"> ②Post實(shí)體配置 <table name="T_POST" /> <attributes> <id name="postId"> <column name="POST_ID" /> <generated-value strategy="TABLE" /> </id> <basic name="postText" fetch="EAGER"> <column name="POST_TEXT" column-definition="LONGTEXT NOT NULL"/> <lob/> </basic> <basic name="postAttach" fetch="LAZY"> <column name="POST_ATTACH" column-definition="BLOB"/> <lob/> </basic> </attributes> </entity> </entity-mappings>
        從代碼清單 6中,我們可以看出PollTopic并不需要通過特殊配置指定和Topic的繼承關(guān)系,這些信息將從實(shí)體類反射信息獲取。所以從嚴(yán)格意義上來說,元數(shù)據(jù)信息或XML和實(shí)體類結(jié)構(gòu)信息共同構(gòu)成的。
    5.JPA的編程結(jié)構(gòu)及重要的API 
        JavaEE 5.0中所定義的JPA接口個(gè)數(shù)并不多,它們位于javax.persistence和javax.persistence.spi兩個(gè)包中。javax.persistence包中大部分API都是注解類,除此之外還包括EntityManager、Query等持久化操作接口。而javax.persistence.spi包中的4個(gè)API,是JPA的服務(wù)層接口。下面,我們就來認(rèn)識一下這些重要的接口。 
        EntityManager的類型 
        實(shí)體對象由實(shí)體管理器進(jìn)行管理,JPA使用javax.persistence.EntityManager代表實(shí)體管理器。實(shí)體管理器和持久化上下文關(guān)聯(lián),持久化上下文是一系列實(shí)體的管理環(huán)境,我們通過EntityManager和持久化上下文進(jìn)行交互。 
        有兩種類型的實(shí)體管理器:
    ?     容器型:容器型的實(shí)體管理器由容器負(fù)責(zé)實(shí)體管理器之間的協(xié)作,在一個(gè)JTA事務(wù)中,一個(gè)實(shí)體管理器的持久化上下文的狀態(tài)會自動廣播到所有使用EntityManager的應(yīng)用程序組件中。Java EE應(yīng)用服務(wù)器提供的就是管理型的實(shí)體管理器;
    ?     應(yīng)用程序型:實(shí)體管理器的生命周期由應(yīng)用程序控制,應(yīng)用程序通過javax.persistence.EntityManagerFactory的createEntityManager創(chuàng)建EntityManager實(shí)例。 
        EntityManager的創(chuàng)建過程 
            javax.persistence.spi.PersistenceProvider接口由JPA的實(shí)現(xiàn)者提供,該接口由啟動者調(diào)用,以便創(chuàng)建一個(gè)EntityManagerFactory實(shí)例。它定義了創(chuàng)建一個(gè)EntityManagerFactory實(shí)例的方法: 
            EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) 
            javax.persistence.spi.PersistenceUnitInfo入?yún)⑻峁┝藙?chuàng)建實(shí)體管理器所需要的所有信息,這些信息根據(jù)JPA的規(guī)范,必須放置在META-INF/persistence.xml文件中。 
            PersistenceUnitInfo接口擁有了一個(gè)void addTransformer(ClassTransformer transformer)方法,通過該方式可以添加一個(gè)javax.persistence.spi.ClassTransformer,并通過PersistenceProvider開放給容器,以便容器在實(shí)體類文件加載到JVM之前進(jìn)行代碼的增強(qiáng),使元數(shù)據(jù)生效。JPA廠商負(fù)責(zé)提供ClassTransformer接口的實(shí)現(xiàn)。 
        圖 4描述了創(chuàng)建EntityManager的過程:


        實(shí)體的狀態(tài) 
        實(shí)體對象擁有以下4個(gè)狀態(tài),這些狀態(tài)通過調(diào)用EntityManager接口方法發(fā)生遷移:
    ? 新建態(tài):新創(chuàng)建的實(shí)體對象,尚未擁有持久化主鍵,沒有和一個(gè)持久化上下文關(guān)聯(lián)起來。
    ? 受控態(tài):已經(jīng)擁有持久化主鍵并和持久化上下文建立了聯(lián)系;
    ? 游離態(tài):擁有持久化主鍵,但尚未和持久化上下文建立聯(lián)系;
    ? 刪除態(tài):擁有持久化主鍵,已經(jīng)和持久化上下文建立聯(lián)系,但已經(jīng)被安排從數(shù)據(jù)庫中刪除。 
        EntityManager 的API 
        下面是EntityManager的一些主要的接口方法:
    ? void persist(Object entity) 
        通過調(diào)用EntityManager的persist()方法,新實(shí)體實(shí)例將轉(zhuǎn)換為受控狀態(tài)。這意謂著當(dāng)persist()方法所在的事務(wù)提交時(shí),實(shí)體的數(shù)據(jù)將保存到數(shù)據(jù)庫中。如果實(shí)體已經(jīng)被持久化,那么調(diào)用persist()操作不會發(fā)生任何事情。如果對一個(gè)已經(jīng)刪除的實(shí)體調(diào)用persist()操作,刪除態(tài)的實(shí)體又轉(zhuǎn)變?yōu)槭芸貞B(tài)。如果對游離狀的實(shí)體執(zhí)行persist()操作,將拋出IllegalArgumentException。
    在一個(gè)實(shí)體 上調(diào)用persist()操作,將廣播到和實(shí)體關(guān)聯(lián)的實(shí)體上,執(zhí)行相應(yīng)的級聯(lián)持久化操作;

    ? void remove(Object entity)
    通過調(diào)用remove()方法刪除一個(gè)受控的實(shí)體。如果實(shí)體聲明為級聯(lián)刪除(cascade=REMOVE 或者cascade=ALL ),被關(guān)聯(lián)的實(shí)體也會被刪除。在一個(gè)新建狀態(tài)的實(shí)體上調(diào)用remove()操作,將被忽略。如果在游離實(shí)體上調(diào)用remove()操作,將拋出IllegalArgumentException,相關(guān)的事務(wù)將回滾。如果在已經(jīng)刪除的實(shí)體上執(zhí)行remove()操作,也會被忽略;
    ? void flush()
    將受控態(tài)的實(shí)體數(shù)據(jù)同步到數(shù)據(jù)庫中;
    ? <T> T merge(T entity)
    將一個(gè)游離態(tài)的實(shí)體持久化到數(shù)據(jù)庫中,并轉(zhuǎn)換為受控態(tài)的實(shí)體;
    ? <T> T find(Class<T> entityClass, Object primaryKey)
    以主鍵查詢實(shí)體對象,entityClass是實(shí)體的類,primaryKey是主鍵值,如以下的代碼查詢Topic實(shí)體:
    Topic t = em.find(Topic.class,1);
    ? Query createQuery(String qlString)
    根據(jù)JPA的查詢語句創(chuàng)建一個(gè)查詢對象Query,如下面的代碼:
    Query q= em.createQuery(""SELECT t FROM Topic t WHERE t.topicTitle LIKE :topicTitle")");
    ? Query createNativeQuery(String sqlString)
    使用本地?cái)?shù)據(jù)庫的SQL語句創(chuàng)建一個(gè)Query對象,Query通過getResultList()方法執(zhí)行查詢后,返回一個(gè)List結(jié)果集,每一行數(shù)據(jù)對應(yīng)一個(gè)Vector。 
        Query 
        JPA使用javax.persistence.Query接口代表一個(gè)查詢實(shí)例,Query實(shí)例由EntityManager通過指定查詢語句構(gòu)建。該接口擁有眾多執(zhí)行數(shù)據(jù)查詢的接口方法:
    ? Object getSingleResult():執(zhí)行SELECT查詢語句,并返回一個(gè)結(jié)果;
    ? List getResultList() :執(zhí)行SELECT查詢語句,并返回多個(gè)結(jié)果;
    ? Query setParameter(int position, Object value):通過參數(shù)位置號綁定查詢語句中的參數(shù),如果查詢語句使用了命令參數(shù),則可以使用Query setParameter(String name, Object value)方法綁定命名參數(shù);
    ? Query setMaxResults(int maxResult):設(shè)置返回的最大結(jié)果數(shù);
    ? int executeUpdate():如果查詢語句是新增、刪除或更改的語句,通過該方法執(zhí)行更新操作;
    6.JPA的查詢語言
        JPA的查詢語言是面向?qū)ο蠖敲嫦驍?shù)據(jù)庫的,它以面向?qū)ο蟮淖匀徽Z法構(gòu)造查詢語句,可以看成是Hibernate HQL的等價(jià)物。 
        簡單的查詢 
        你可以使用以下語句返回所有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表示用位置標(biāo)識參數(shù),爾后,我們可以通過Query的setParameter(1, "主題1")綁定參數(shù)。而DISTINCT表示過濾掉重復(fù)的數(shù)據(jù)。 
        如果需要以命名綁定綁定數(shù)據(jù),可以改成以下的方式: 
        SELECT DISTINCT t FROM Topic t WHERE t.topicTitle = :title 
        這時(shí),需要通過Query的setParameter("title", "主題1")綁定參數(shù)。 

        關(guān)聯(lián)查詢:從One的一方關(guān)聯(lián)到Many的一方 
        返回PollOptions對應(yīng)的PollTopic對象,可以使用以下語句: 
        SELECT DISTINCT p FROM PollTopic p, IN(p.options) o WHERE o.optionItem LIKE ?1 
        這個(gè)語法和SQL以及HQL都有很大的區(qū)別,它直接實(shí)體屬性連接關(guān)聯(lián)的實(shí)體,這里我們通過PollTopic的options屬性關(guān)聯(lián)到PollOption實(shí)體上,對應(yīng)的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)) 
        該查詢語句的另外兩種等價(jià)的寫法分別是: 
        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 

        關(guān)聯(lián)查詢:從Many的一方關(guān)聯(lián)到One的一方 
        從Many一方關(guān)聯(lián)到One一方的查詢語句和前面所講的也很相似。如我們希望查詢某一個(gè)調(diào)查主題下的所示調(diào)查項(xiàng),則可以編寫以下的查詢語句: 
        SELECT p FROM PollOption p JOIN p.pollTopic t WHERE t.topicId = :topicId 
        對應(yīng)的SQL語句為: 
        SELECT t0.OPTION_ID, t0.OPTION_ITEM, t0.TOPIC_ID FROM T_POLL_OPTION t0, T_TOPIC t1 WHERE ((t1.TOPIC_ID = ?) AND ((t1.TOPIC_ID = t0.TOPIC_ID) AND (t1.TOPIC_TYPE = ?))) 

        使用其它的關(guān)系操作符 
        使用空值比較符,比如查詢附件不空的所有帖子對象: 
        SELECT p FROM Post p WHERE p.postAttach IS NOT NULL 
        范圍比較符包括BETWEEN..AND和>、>= 、<、<=、<>這些操作符。比如下面的語句查詢?yōu)g覽次數(shù)在100到200之間的所有論壇主題: 
        SELECT t FROM Topic t WHERE t.topicViews BETWEEN 100 AND 200 

        集合關(guān)系操作符 
        和其它實(shí)體是One-to-Many或Many-to-Many關(guān)系的實(shí)體,通過集合引用關(guān)聯(lián)的實(shí)體,我們可以通過集合關(guān)系操作符進(jìn)行數(shù)據(jù)查詢。下面的語句返回所有沒有選項(xiàng)的調(diào)查論壇的主題: 
        SELECT t FROM PollTopic t WHERE t.options IS EMPTY 
        我們還可以通過判斷元素是否在集合中進(jìn)行查詢: 
        SELECT t FROM PollTopic t WHERE :option MEMBER OF t.options 
        這里參數(shù)必須綁定一個(gè)PollOption的對象,JPA會自動將其轉(zhuǎn)換為主鍵比較的SQL語句。 

        子查詢 
        JPA可以進(jìn)行子查詢,并支持幾個(gè)常見的子查詢函數(shù):EXISTS、ALL、ANY。如下面的語句查詢出擁有6個(gè)以上選項(xiàng)的調(diào)查主題: 
        SELECT t FROM PollTopic t WHERE (SELECT COUNT(o) FROM t.options o) > 6 
        
        可用函數(shù) 
        JPA查詢支持一些常見的函數(shù),其中可用的字符串操作函數(shù)有:
    ? CONCAT(String, String):合并字段串;
    ? LENGTH(String):求字段串的長度;
    ? LOCATE(String, String [, start]):查詢字段串的函數(shù),第一個(gè)參數(shù)為需要查詢的字段串,看它在出現(xiàn)在第二個(gè)參數(shù)字符串的哪個(gè)位置,start表示從哪個(gè)位置開始查找,返回查找到的位置,沒有找到返回0。如LOCATE ('b1','a1b1c1',1)返回為3;
    ? SUBSTRING(String, start, length):子字段串函數(shù);
    ? TRIM([[LEADING|TRAILING|BOTH] char) FROM] (String):將字段串前后的特殊字符去除,可以通過選擇決定具體的去除位置和字符;
    ? LOWER(String):將字符串轉(zhuǎn)為小寫;
    ? UPPER(String):將字符串轉(zhuǎn)為大寫。
    數(shù)字操作函數(shù)有:
    ? ABS(number):求絕對值函數(shù);
    ? MOD(int, int):求模的函數(shù);
    ? SQRT(double):求平方函數(shù);
    ? SIZE(Collection):求集合大小函數(shù)。 

        更改語句 
        可以用EntityManager進(jìn)行實(shí)體的更新操作,也可以通過查詢語言執(zhí)行數(shù)據(jù)表的字段更新,記錄刪除的操作: 
        下面的語句將某一個(gè)調(diào)查選項(xiàng)更新為新的值: 
        UPDATE PollOption p SET p.optionItem = :value WHERE p.optionId = :optionId 
        我們使用Query接口的executeUpdate()方法執(zhí)行更新。下面的語句刪除一條記錄: 
        DELETE FROM PollOption p WHERE p.optionId = :optionId 

        排序和分組 
        我們還可以對查詢進(jìn)行排序和分組。如下面的語句查詢出主題的發(fā)表時(shí)間大于某個(gè)時(shí)間值,返回的結(jié)果按瀏覽量降序排列:
    SELECT t FROM Topic t WHERE t.topicTime > :time ORDER BY t.topicViews DESC 
        下面的語句計(jì)算出每個(gè)調(diào)查主題對應(yīng)的選項(xiàng)數(shù)目: 
        SELECT COUNT(p),p.pollTopic.topicId FROM PollOption p GROUP BY p.pollTopic.topicId
    這里,我們使用了計(jì)算數(shù)量的聚集函數(shù)COUNT(),其它幾個(gè)可用的聚集函數(shù)分別為:
    ? AVG:計(jì)算平均值,返回類型為double;
    ? MAX:計(jì)算最大值;
    ? MIN:計(jì)算最小值;
    ? SUM:計(jì)算累加和;
    我們還可以通過HAVING對聚集結(jié)果進(jìn)行條件過濾:
    SELECT COUNT(p),p.pollTopic.topicId FROM PollOption p GROUP BY p.pollTopic.topicId HAVING p.pollTopic.topicId IN(1,2,3) 

        7.小結(jié) 
        在不久的將來,Sun可能會將JPA作為一個(gè)單獨(dú)的JSR對待,同時(shí)JPA還可能作為Java SE的一部分。不過這些都不太重要,重要的是,我們現(xiàn)在已經(jīng)可以在脫離容器的情況下、在Java SE應(yīng)用中使用JPA了。 
        JPA已經(jīng)作為一項(xiàng)對象持久化的標(biāo)準(zhǔn),不但可以獲得Java EE應(yīng)用服務(wù)器的支持,來可以直接在Java SE中使用。開發(fā)者將無需在現(xiàn)有多種ORM框架中艱難地選擇,按照Sun的預(yù)想,現(xiàn)有ORM框架頭頂?shù)墓猸h(huán)將漸漸暗淡,不再具有以往的吸引力。

    posted on 2007-05-23 17:32 liaojiyong 閱讀(4147) 評論(0)  編輯  收藏 所屬分類: JPA


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲熟妇无码AV| 97久久精品亚洲中文字幕无码| 国产99在线|亚洲| 精品国产免费人成电影在线观看| 国产亚洲免费的视频看| 成人性生交大片免费看中文| 中文亚洲AV片不卡在线观看| 91视频免费观看| 亚洲AV无码一区二区三区系列| 久久国产精品成人免费| 久久久久亚洲Av无码专| 精品久久8x国产免费观看| 亚洲区精品久久一区二区三区| 91免费精品国自产拍在线不卡| 亚洲一区动漫卡通在线播放| 一个人免费观看www视频在线| 亚洲国产区男人本色| 亚洲无码日韩精品第一页| 久久久久久久国产免费看| 亚洲综合久久综合激情久久| 四虎精品视频在线永久免费观看| 67194在线午夜亚洲| 日本免费的一级v一片| 99久久精品毛片免费播放| 亚洲精品成人av在线| 大地资源免费更新在线播放| 国产亚洲精品第一综合| 亚洲国产三级在线观看| **一级一级毛片免费观看| 亚洲AV成人无码网天堂| 亚洲热线99精品视频| 97热久久免费频精品99 | 亚洲香蕉免费有线视频| 日本XXX黄区免费看| 思思久久99热免费精品6 | 亚洲另类视频在线观看| 国产色婷婷精品免费视频| 青青操在线免费观看| 亚洲国产av一区二区三区丶| 日韩精品成人亚洲专区| 四虎国产精品永久免费网址|