轉載:http://blog.csdn.net/kevon_sun/article/details/42850387html
目錄git
WARNING! This is a translated version of the English Hibernate reference documentation. The translated version might not be up to date! However, the differences should only be very minor. Consult the English reference documentation if you are missing information or encounter a translation error. If you like to contribute to a particular translation, contact us on the Hibernate developer mailing list.正則表達式
Translator(s): RedSaga Translate Team 滿江紅翻譯團隊 <caoxg@yahoo.com>算法
本文檔的翻譯是在網絡上協做進行的,也會不斷根據Hibernate的升級進行更新。提供此文檔的目的是爲了減緩學習Hibernate的坡度,而非代替原文檔。咱們建議全部有能力的讀者都直接閱讀英文原文。若您對翻譯有異議,或發現翻譯錯誤,敬請不吝賜教,報告到以下地址:http://wiki.redsaga.com/confluence/display/HART/Homesql
表 1. Hibernate Annotation v3翻譯團隊數據庫
序號 | 標題 | 中文標題 | 翻譯 | 1審 | 2審 |
---|---|---|---|---|---|
-- | Contents | 目錄 | Liu Chang | ||
#1 | Setting up an annotations projec | 建立一個註解項目 | melthaw | Zheng Shuai | superq |
#2 | Entity Beans-Introduction | 實體Bean-簡介 | melthaw | Zheng Shuai | superq |
#3 | Entity Beans-Mapping with EJB3 Annotations | 實體Bean-用EJB3註解進行映射 | melthaw | Zheng Shuai | superq, Liu Chang, Sean Chan |
#4 | Entity Beans-Mapping Queries | 實體Bean-映射查詢 | melthaw | Zheng Shuai | superq, Liu Chang, Sean Chan |
#5 | Entity Beans-Hibernate Annotation Extensions | 實體Bean-Hibernate獨有的註解擴展 | Sean Chan | morning | melthaw |
#6 | Overriding metadata through XML | 經過XML覆寫元數據 | icess | melthaw | Sean Chan |
#7 | Hibernate Validator | Hibernate驗證器 | DigitalSonic | morning | melthaw |
#8 | Hibernate Lucene Integration | Hibernate與Lucene集成 | mochow | morning | melthaw |
#9 | Appendix:Glossary | 附錄:術語表 | mochow | Liu Chang | 曹曉鋼 |
關於咱們apache
從成立之初就致力於Java開放源代碼在中國的傳播與發展,與國內多個Java團體及出版社有深刻交流。堅持少說多作的原則,目前有兩個團隊,「OpenDoc團隊」與「翻譯團隊」,本翻譯文檔即爲翻譯團隊做品。OpenDoc團隊已經推出包括Hibernate、iBatis、Spring、WebWork的多份開放文檔,並於2005年5月在Hibernate開放文檔基礎上擴充成書,出版了原創書籍:《深刻淺出Hibernate》,本書400餘頁,適合各個層次的Hibernate用戶。(http://www.redsaga.com/hibernate_book.html)敬請支持。編程
在咱們翻譯Hibernate Annotation參考文檔的同時,還有一位熱心的朋友也在進行着一樣的工做,這位朋友就是icess(冰雨),由icess翻譯的中文版的地址: http://icess.my.china.com/hibernate/a/ref/index.htmapi
正如其餘的ORM工具,Hibernate一樣須要元數據來控制在不一樣數據表達形式之間的轉化. 在Hibernate 2.x裏,多數狀況下表示映射關係的元數據保存在XML文本文件中. 還有一種方式就是Xdoclet,它能夠在編譯時利用Javadoc中的源碼註釋信息來進行預處理. 如今新的JDK標準(JDK1.5以上)也支持相似的註解功能,但相比之下不少工具對此提供了更強大更好用的支持. 以IntelliJ IDEA和Eclipse爲例,這些IDE工具爲JDK 5.0註解功能提供了自動完成和語法高亮功能. 註解被直接編譯到字節碼裏,並 在運行時(對於Hibernate來說就是啓動的時候)經過反射讀取這些註解, 所以外部XML文件就再也不須要了.
EJB3規範最終承認了透明化ORM的成功範例以及市場對於這種技術的興趣. EJB3規範標準化了ORM的基礎API並且在任何ORM持久化機制中使用元數據. Hibernate EntityManager實現了EJB3持久化規範中定義的編程接口和生命週期規則. 在Hibernate Core的基礎上再結合 Hibernate Annotations就實現了一套完整(而且獨立)的EJB3持久化解決方案. 你能夠結合三者來使用,也能夠拋開EJB3編程接口和生命週期規則而獨立使用註解, 甚至只單獨使用Hibernate Core. 這些都取決於項目的商業和技術上的實際需求. Hibernate容許你直接使用native APIs,若是有須要, 甚至能夠直接操做JDBC和SQL.
注意本文檔基於Hibernate Annotations的預覽版(聽從EJB 3.0/JSR-220最終草案). 這個版本和新規範中定義的最終概念已經很是接近了.咱們的目標是提供一套完整的ORM註解, 包括EJB3的標準註解以及Hibernate3的擴展(後者是EJB3規範中沒有涉及到的). 最終經過註解你能夠完成任何可能的映射.詳情參考???.
EJB3最終草案修改了部分註解, http://www.hibernate.org/371.html提供了從上一個版本到最新版本的遷移指南.
首先從Hibernate官方網站下載並解壓Hibernate Annotations的發佈包。
這個版本(預覽版)要求使用Hibernate 3.2.0.CR2或更高版本。請不要和老版本的Hibernate 3.x混合起來使用。
這個版本在Hibernate core 3.2.0.CR2的基礎上工做良好。
首先肯定你已經安裝了JDK 5.0。固然就算使用低版本的JDK, Xdoclet也能夠提供(基於註解的)元數據所帶來的部分功能。 不過請注意本文檔只描述跟JDK5.0註解有關的內容,關於Xdoclet請參考相關文檔。
首先就是設置classpath(固然是在IDE中建立了一個新項目以後)。
將Hibernate3核心文件以及其依賴的第三方庫文件(請參考lib/README.txt文件)加入到你的classpath裏面。
將hibernate-annotations.jar 和lib/ejb3-persistence.jar加入到你的classpath裏面。
若是要使用 第 5 章 Hibernate與Lucene集成,還須要將lucene的jar文件加入你的classpath。
咱們推薦在一個包裝器(wrapper)類HibernateUtil 的靜態初始化代碼塊中啓動Hibernate。或許你在Hibernate文檔的其餘不少地方看到過這個類, 可是要在你的項目中使用註解,還須要對這個輔助(helper)類進行擴展。擴展以下:
package hello;
import org.hibernate.*;
import org.hibernate.cfg.*;
import test.*;
import test.animals.Dog;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().buildSessionFactory();
} catch (Throwable ex) {
// Log exception!
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession()
throws HibernateException {
return sessionFactory.openSession();
}
}
這裏比較有意思的是使用到了AnnotationConfiguration類。 在XML配置文件(一般是hibernate.cfg.xml)中則定義了包和通過註解的類。下面的xml和前面的聲明等價:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <mapping package="test.animals"/> <mapping class="test.Flight"/> <mapping class="test.Sky"/> <mapping class="test.Person"/> <mapping class="test.animals.Dog"/> <mapping resource="test/animals/orm.xml"/> </session-factory> </hibernate-configuration>
注意如今你能夠混合使用hbm.xml和註解。資源元素(resource element)能夠是hbm文件也能夠是EJB3 XML發佈描述符,此差異對於配置過程是透明的。
除了上面的方式,你還能夠經過編程的方式定義包括註解的類和包
sessionFactory = new AnnotationConfiguration() .addPackage("test.animals") //the fully qualified package name .addAnnotatedClass(Flight.class) .addAnnotatedClass(Sky.class) .addAnnotatedClass(Person.class) .addAnnotatedClass(Dog.class)
.buildSessionFactory();
你也可使用Hibernate Entity Manager來完成以上功能。Hibernate Entity Manager有本身的一套配置機制,詳情請參考相關文檔。
除了啓動方式和配置文件有所改變以外,結合註解來使用Hibernate API和之前沒有什麼區別, 在其餘方面你仍是能夠繼續保持之前的習慣和喜愛(hibernate.properties,hibernate.cfg.xml, programmatic APIs等等)。 甚至對於同一個SessionFactory,你均可以混合帶註解的持久類以及傳統的bm.cfg.xml聲明方式。 然而你不能屢次聲明同一個類(要麼經過註解要麼經過hbm.xml配置文件), 並且在一個映射實體的類繼承層次中,這兩個配置策略不能同時使用.
爲了簡化從hbm文件到註解的遷移過程, 配置機制將自動檢測在註解和hbm文件中重複的映射。 默認狀況下hbm文件中的聲明比類中的註解元數據具備更高的優先級。 這種優先級的設定是以類爲單位的。 你也能夠經過hibernate.mapping.precedence修改這種優先級。 默認的值是hbm, class, 若是改成class,hbm,當發生衝突的時候,類中的註解將比hbm文件具備更高的優先級。
如今EJB3實體Bean是純粹的POJO.實際上這表達了和Hibernate持久化實體對象一樣的概念. 它們的映射都經過JDK5.0註解來定義(EJB3規範中的XML描述語法至今尚未最終定下來). 註解分爲兩個部分,分別是邏輯映射註解和物理映射註解, 經過邏輯映射註解能夠描述對象模型,類之間的關係等等, 而物理映射註解則描述了物理的schema,表,列,索引等等. 下面咱們在代碼中將混合使用這兩種類型的註解.
EJB3註解的API定義在javax.persistence.*包裏面. 大部分和JDK5兼容的IDE(象Eclipse, IntelliJ IDEA 和Netbeans等等)都提供了註解接口和屬性的自動完成功能. (這些不須要IDE提供特別的EJB3支持模塊,由於EJB3註解是標準的JDK5註解)
請閱讀JBoss EJB 3.0指南或者直接閱讀Hibernate Annotations測試代碼以獲取更多的可運行實例.Hibernate Annotations提供的大部分單元測試代碼都演示了實際的例子,是一個獲取靈感的好地方.
每個持久化POJO類都是一個實體bean,這能夠經過在類的定義中使用@Entity註解來進行聲明:
@Entity public class Flight implements Serializable { Long id; @Id public Long getId() { return id; } public void setId(Long id) { this.id = id; } }
經過@Entity註解將一個類聲明爲一個實體bean(即一個持久化POJO類), @Id註解則聲明瞭該實體bean的標識屬性. 其餘的映射定義是隱式的.這種以隱式映射爲主體,以顯式映射爲例外的配置方式在新的EJ3規範中處於很是重要的位置, 和之前的版本相比有了質的飛躍. 在上面這段代碼中:Flight類映射到Flight表,並使用id列做爲主鍵列.
在對一個類進行註解時,你能夠選擇對它的的屬性或者方法進行註解,根據你的選擇,Hibernate的訪問類型分別爲 field或property. EJ3規範要求在須要訪問的元素上進行註解聲明,例如,若是訪問類型爲 property就要在getter方法上進行註解聲明, 若是訪問類型爲 field就要在字段上進行註解聲明.應該儘可能避免混合使用這兩種訪問類型. Hibernate根據@Id 或 @EmbeddedId的位置來判斷訪問類型.
@Table是類一級的註解, 經過@Table註解能夠爲實體bean映射指定表(table),目錄(catalog)和schema的名字. 若是沒有定義@Table,那麼系統自動使用默認值:實體的短類名(不附帶包名).
@Entity @Table(name="tbl_sky") public class Sky implements Serializable { ...
@Table元素包括了一個schema 和一個 catalog屬性,若是須要能夠指定相應的值. 結合使用@UniqueConstraint註解能夠定義表的惟一約束(unique constraint) (對於綁定到單列的惟一約束,請參考@Column註解)
@Table(name="tbl_sky",
uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}
)
上面這個例子中,在month和day這兩個字段上定義惟一約束. 注意columnNames數組中的值指的是邏輯列名.
Hibernate在NamingStrategy的實現中定義了邏輯列名. 默認的EJB3命名策略將物理字段名看成邏輯字段名來使用. 注意該字段名和它對應的屬性名可能不一樣(若是字段名是顯式指定的話). 除非你重寫了NamingStrategy,不然不用擔憂這些區別..你能夠在實體bean中使用@Version註解,經過這種方式可添加對樂觀鎖定的支持:
@Entity public class Flight implements Serializable { ... @Version @Column(name="OPTLOCK") public Integer getVersion() { ... } }
上面這個例子中,version屬性將映射到 OPTLOCK列, entity manager使用該字段來檢測更新衝突(防止更新丟失,請參考last-commit-wins策略).
根據EJB3規範,version列能夠是numeric類型(推薦方式)也能夠是timestamp類型. Hibernate支持任何自定義類型,只要該類型實現了UserVersionType.
Every non static non transient property (field or method) of an entity bean is considered persistent, unless you annotate it as @Transient. Not having an annotation for your property is equivalent to the appropriate @Basic annotation. The @Basic annotation allows you to declare the fetching strategy for a property:
實體bean中全部的非static非transient的屬性均可以被持久化, 除非你將其註解爲@Transient.全部沒有定義註解的屬性等價於在其上面添加了@Basic註解. 經過 @Basic註解能夠聲明屬性的獲取策略(fetch strategy):
public transient int counter; //transient property private String firstname; //persistent property @Transient String getLengthInMeter() { ... } //transient property String getName() {... } // persistent property @Basic int getLength() { ... } // persistent property @Basic(fetch = FetchType.LAZY) String getDetailedComment() { ... } // persistent property @Temporal(TemporalType.TIME) java.util.Date getDepartureTime() { ... } // persistent property @Enumerated(EnumType.STRING) Starred getNote() { ... } //enum persisted as String in database
上面這個例子中,counter是一個transient的字段, lengthInMeter的getter方法被註解爲@Transient, entity manager將忽略這些字段和屬性. 而name,length,firstname 這幾個屬性則是被定義爲可持久化和可獲取的.對於簡單屬性來講,默認的獲取方式是即時獲取(early fetch). 當一個實體Bean的實例被建立時,Hibernate會將這些屬性的值從數據庫中提取出來,保存到Bean的屬性裏. 與即時獲取相對應的是延遲獲取(lazy fetch).若是一個屬性的獲取方式是延遲獲取 (好比上面例子中的detailedComment屬性), Hibernate在建立一個實體Bean的實例時,不會即時將這個屬性的值從數據庫中讀出. 只有在該實體Bean的這個屬性第一次被調用時,Hibernate纔會去獲取對應的值. 一般你不須要對簡單屬性設置延遲獲取(lazy simple property),千萬不要和延遲關聯獲取(lazy association fetch)混淆了 (譯註:這裏指不要把lazy simple property和lazy association fetch混淆了).
爲了啓用屬性級的延遲獲取,你的類必須通過特殊處理(instrumented): 字節碼將被織入原始類中來實現延遲獲取功能, 詳情參考Hibernate參考文檔.若是不對類文件進行字節碼特殊處理, 那麼屬性級的延遲獲取將被忽略.
推薦的替代方案是使用EJB-QL或者Criteria查詢的投影(projection)功能.
Hibernate和EJB3都支持全部基本類型的屬性映射. 這些基本類型包括全部的Java基本類型,及其各自的wrapper類和serializable類. Hibernate Annotations還支持將內置的枚舉類型映射到一個順序列(保存了相應的序列值) 或一個字符串類型的列(保存相應的字符串).默認是保存枚舉的序列值, 可是你能夠經過@Enumerated註解來進行調整(見上面例子中的note屬性).
在覈心的Java API中並無定義時間精度(temporal precision). 所以處理時間類型數據時,你還須要定義將其存儲在數據庫中所預期的精度. 在數據庫中,表示時間類型的數據有DATE,TIME, 和 TIMESTAMP三種精度(即單純的日期,時間,或者二者兼備). 可以使用@Temporal註解來調整精度.
@Lob註解表示屬性將被持久化爲Blob或者Clob類型, 具體取決於屬性的類型, java.sql.Clob, Character[], char[] 和 java.lang.String這些類型的屬性都被持久化爲Clob類型, 而java.sql.Blob, Byte[], byte[] 和 serializable類型則被持久化爲Blob類型.
@Lob public String getFullText() { return fullText; } @Lob public byte[] getFullCode() { return fullCode; }
若是某個屬性實現了java.io.Serializable同時也不是基本類型, 而且沒有在該屬性上使用@Lob註解, 那麼Hibernate將使用自帶的serializable類型.
使用 @Column 註解可將屬性映射到列. 使用該註解來覆蓋默認值(關於默認值請參考EJB3規範). 在屬性級使用該註解的方式以下:
不進行註解
和 @Basic一塊兒使用
和 @Version一塊兒使用
和 @Lob一塊兒使用
和 @Temporal一塊兒使用
和 @org.hibernate.annotations.CollectionOfElements一塊兒使用 (只針對Hibernate )
@Entity public class Flight implements Serializable { ... @Column(updatable = false, name = "flight_name", nullable = false, length=50) public String getName() { ... }
在上面這個例子中,name屬性映射到flight_name列. 該字段不容許爲空,長度爲50,而且是不可更新的(也就是屬性值是不變的).
上面這些註解能夠被應用到正規屬性上例如@Id 或@Version屬性.
@Column( name="columnName"; (1) boolean unique() default false; (2) boolean nullable() default true; (3) boolean insertable() default true; (4) boolean updatable() default true; (5) String columnDefinition() default ""; (6) String table() default ""; (7) int length() default 255; (8) int precision() default 0; // decimal precision (9) int scale() default 0; // decimal scale
(1) | name 可選,列名(默認值是屬性名) |
(2) | unique 可選,是否在該列上設置惟一約束(默認值false) |
(3) | nullable 可選,是否設置該列的值能夠爲空(默認值false) |
(4) | insertable 可選,該列是否做爲生成的insert語句中的一個列(默認值true) |
(5) | updatable 可選,該列是否做爲生成的update語句中的一個列(默認值true) |
(6) | columnDefinition 可選: 爲這個特定列覆蓋SQL DDL片斷 (這可能致使沒法在不一樣數據庫間移植) |
(7) | table 可選,定義對應的表(默認爲主表) |
(8) | length 可選,列長度(默認值255) |
(8) | precision 可選,列十進制精度(decimal precision)(默認值0) |
(10) | scale 可選,若是列十進制數值範圍(decimal scale)可用,在此設置(默認值0) |
在實體中能夠定義一個嵌入式組件(embedded component), 甚至覆蓋該實體中原有的列映射. 組件類必須在類一級定義@Embeddable註解. 在特定的實體的關聯屬性上使用@Embedded和@AttributeOverride註解能夠覆蓋該屬性對應的嵌入式對象的列映射:
@Entity public class Person implements Serializable { // Persistent component using defaults Address homeAddress; @Embedded @AttributeOverrides( { @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ), @AttributeOverride(name="name", column = @Column(name="bornCountryName") ) } ) Country bornIn; ... }
@Embeddable public class Address implements Serializable { String city; Country nationality; //no overriding here }
@Embeddable public class Country implements Serializable { private String iso2; @Column(name="countryName") private String name; public String getIso2() { return iso2; } public void setIso2(String iso2) { this.iso2 = iso2; } public String getName() { return name; } public void setName(String name) { this.name = name; } ... }
嵌入式對象繼承其所屬實體中定義的訪問類型 (注意:這能夠經過使用Hibernate提供的@AccessType註解來覆蓋原有值)(請參考 Hibernate Annotation Extensions).
在上面的例子中,實體bean Person 有兩個組件屬性, 分別是homeAddress和bornIn. 咱們能夠看到homeAddress 屬性並無註解. 可是Hibernate自動檢測其對應的Address類中的@Embeddable註解, 並將其看做一個持久化組件.對於Country中已映射的屬性, 則使用@Embedded和@AttributeOverride 註解來覆蓋原來映射的列名. 正如你所看到的, Address對象中還內嵌了Country對象, 這裏和homeAddress同樣使用了Hibernate和EJB3自動檢測機制. 目前EJB3規範還不支持覆蓋多層嵌套(即嵌入式對象中還包括其餘嵌入式對象)的列映射. 不過Hibernate經過在表達式中使用"."符號表達式提供了對此特徵的支持.
@Embedded @AttributeOverrides( { @AttributeOverride(name="city", column = @Column(name="fld_city") ), @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ), @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") ) //nationality columns in homeAddress are overridden } ) Address homeAddress;
Hibernate註解支持不少EJB3規範中沒有明肯定義的特性. 例如,能夠在嵌入式對象上添加 @MappedSuperclass註解, 這樣能夠將其父類的屬性持久(詳情請查閱@MappedSuperclass).
Hibernate如今支持在嵌入式對象中使用關聯註解(如@*ToOne和@*ToMany). 而EJB3規範尚不支持這樣的用法。你可使用 @AssociationOverride註解來覆寫關聯列.
在同一個實體中使用兩個同類型的嵌入對象, 其默認列名是無效的:至少要對其中一個進行明確聲明. Hibernate在這方面走在了EJB3規範的前面, Hibernate提供了NamingStrategy, 在使用Hibernate時, 經過NamingStrategy你能夠對默認的機制進行擴展. DefaultComponentSafeNamingStrategy 在默認的EJB3NamingStrategy上進行了小小的提高, 容許在同一實體中使用兩個同類型的嵌入對象而無須額外的聲明.
使用@Id註解能夠將實體bean中的某個屬性定義爲標識符(identifier). 該屬性的值能夠經過應用自身進行設置, 也能夠經過Hiberante生成(推薦). 使用 @GeneratedValue註解能夠定義該標識符的生成策略:
和EJB3規範相比,Hibernate提供了更多的id生成器.詳情請查閱 Hibernate Annotation Extensions .
下面的例子展現了使用SEQ_STORE配置的sequence生成器
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") public Integer getId() { ... }
下面這個例子使用的是identity生成器
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Long getId() { ... }
AUTO生成器適用於可移植的應用(在多個DB間切換). 多個@Id能夠共享同一個identifier生成器,只要把generator屬性設成相同的值就能夠了. 經過@SequenceGenerator 和@TableGenerator,你能夠配置不一樣的identifier生成器. 每個identifier生成器都有本身的適用範圍,能夠是應用級(application level)和類一級(class level). 類一級的生成器在外部是不可見的, 並且類一級的生成器能夠覆蓋應用級的生成器. 應用級的生成器則定義在包一級(package level)(如package-info.java):
@javax.persistence.TableGenerator( name="EMP_GEN", table="GENERATOR_TABLE", pkColumnName = "key", valueColumnName = "hi" pkColumnValue="EMP", allocationSize=20 ) @javax.persistence.SequenceGenerator( name="SEQ_GEN", sequenceName="my_sequence" ) package org.hibernate.test.metadata;
若是在org.hibernate.test.metadata包下面的 package-info.java文件用於初始化EJB配置, 那麼該文件中定義的 EMP_GEN 和SEQ_GEN都是應用級的生成器. EMP_GEN定義了一個使用hilo算法 (max_lo爲20)的id生成器(該生成器將id的信息存在數據庫的某個表中.). id的hi值保存在GENERATOR_TABLE中. 在該表中 pkColumnName"key"等價於 pkColumnValue "EMP", 而valueColumnName "hi"中存儲的是下一個要使用的最大值.
SEQ_GEN則定義了一個sequence 生成器, 其對應的sequence名爲 my_sequence. 注意目前Hibernate Annotations還不支持sequence 生成器中的 initialValue和 allocationSize參數.
下面這個例子展現了定義在類範圍(class scope)的sequence生成器:
@Entity @javax.persistence.SequenceGenerator( name="SEQ_STORE", sequenceName="my_sequence" ) public class Store implements Serializable { private Long id; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") public Long getId() { return id; } }
在這個例子中,Store類使用名爲my_sequence的sequence,而且SEQ_STORE 生成器對於其餘類是不可見的. 注意在org.hibernate.test.metadata.id包下的測試代碼有更多演示Hibernate Annotations用法的例子..
下面是定義組合主鍵的幾種語法:
對於EJB2的開發人員來講 @IdClass是很常見的, 可是對於Hibernate的用戶來講就是一個嶄新的用法. 組合主鍵類對應了一個實體類中的多個字段或屬性, 並且主鍵類中用於定義主鍵的字段或屬性和 實體類中對應的字段或屬性在類型上必須一致.下面咱們看一個例子:
@Entity @IdClass(FootballerPk.class) public class Footballer { //part of the id key @Id public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } //part of the id key @Id public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getClub() { return club; } public void setClub(String club) { this.club = club; } //appropriate equals() and hashCode() implementation } @Embeddable public class FootballerPk implements Serializable { //same name and type as in Footballer public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } //same name and type as in Footballer public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } //appropriate equals() and hashCode() implementation }
如上, @IdClass指向對應的主鍵類.
Hibernate支持在組合標識符中定義關聯(就像使用普通的註解同樣),而EJB3規範並不支持此類用法.
@Entity @AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") ) public class TvMagazin { @EmbeddedId public TvMagazinPk id; @Temporal(TemporalType.TIME) Date time; } @Embeddable public class TvMagazinPk implements Serializable { @ManyToOne public Channel channel; public String name; @ManyToOne public Presenter presenter; }
EJB3支持三種類型的繼承映射:
你能夠用 @Inheritance註解來定義所選擇的策略. 這個註解須要在每一個類層次結構(class hierarchy) 最頂端的實體類上使用.
這種策略有不少缺點(例如:多態查詢和關聯),EJB3規範, Hibernate參考手冊, Hibernate in Action,以及其餘許多地方都對此進行了描述和解釋. Hibernate使用SQL UNION查詢來實現這種策略. 一般使用場合是在一個繼承層次結構的頂端:
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class Flight implements Serializable {
這種策略支持雙向的一對多關聯. 這裏不支持IDENTITY生成器策略,由於id必須在多個表間共享. 固然,一旦使用這種策略就意味着你不能使用 AUTO 生成器和IDENTITY生成器.
整個繼承層次結構中的父類和子類的全部屬性都映射到同一個表中, 他們的實例經過一個辨別符(discriminator)列來區分.:
@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn( name="planetype", discriminatorType=DiscriminatorType.STRING ) @DiscriminatorValue("Plane") public class Plane { ... } @Entity @DiscriminatorValue("A320") public class A320 extends Plane { ... }
在上面這個例子中,Plane是父類,在這個類裏面將繼承策略定義爲 InheritanceType.SINGLE_TABLE,並經過 @DiscriminatorColumn註解定義了辨別符列(還能夠定義辨別符的類型). 最後,對於繼承層次結構中的每一個類,@DiscriminatorValue註解指定了用來辨別該類的值. 辨別符列的名字默認爲 DTYPE,其默認值爲實體名(在@Entity.name中定義),其類型 爲DiscriminatorType.STRING. A320是子類,若是不想使用默認的辨別符,只須要指定相應的值便可. 其餘的如繼承策略,辨別標誌字段的類型都是自動設定的.
@Inheritance 和 @DiscriminatorColumn 註解只能用於實體層次結構的頂端.
當每一個子類映射到一個表時, @PrimaryKeyJoinColumn 和@PrimaryKeyJoinColumns 註解定義了每一個子類表關聯到父類表的主鍵:
@Entity @Inheritance(strategy=InheritanceType.JOINED) public class Boat implements Serializable { ... } @Entity public class Ferry extends Boat { ... } @Entity @PrimaryKeyJoinColumn(name="BOAT_ID") public class AmericaCupClass extends Boat { ... }
以上全部實體都使用了JOINED策略, Ferry表和Boat表使用同名的主鍵. 而AmericaCupClass表和Boat表使用了條件 Boat.id = AmericaCupClass.BOAT_ID進行關聯.
有時候經過一個(技術上或業務上)父類共享一些公共屬性是頗有用的, 同時還不用將該父類做爲映射的實體(也就是該實體沒有對應的表). 這個時候你須要使用@MappedSuperclass註解來進行映射.
@MappedSuperclass public class BaseEntity { @Basic @Temporal(TemporalType.TIMESTAMP) public Date getLastUpdate() { ... } public String getLastUpdater() { ... } ... } @Entity class Order extends BaseEntity { @Id public Integer getId() { ... } ... }
在數據庫中,上面這個例子中的繼承的層次結構最終以Order表的形式出現, 該表擁有id, lastUpdate 和 lastUpdater三個列.父類中的屬性映射將複製到其子類實體. 注意這種狀況下的父類再也不處在繼承層次結構的頂端.
你能夠經過 @AttributeOverride註解覆蓋實體父類中的定義的列. 這個註解只能在繼承層次結構的頂端使用.
@MappedSuperclass public class FlyingObject implements Serializable { public int getAltitude() { return altitude; } @Transient public int getMetricAltitude() { return metricAltitude; } @ManyToOne public PropulsionType getPropulsion() { return metricAltitude; } ... } @Entity @AttributeOverride( name="altitude", column = @Column(name="fld_altitude") ) @AssociationOverride( name="propulsion", joinColumns = @JoinColumn(name="fld_propulsion_fk") ) public class Plane extends FlyingObject { ... }
在上面這個例子中,altitude屬性的值最終將持久化到Plane 表的fld_altitude列.而名爲propulsion的關聯則保存在fld_propulsion_fk外間列.
你能夠爲@Entity和@MappedSuperclass註解的類 以及那些對象爲@Embeddable的屬性定義 @AttributeOverride和@AssociationOverride.
使用@OneToOne註解能夠創建實體bean之間的一對一的關聯. 一對一關聯有三種狀況: 一是關聯的實體都共享一樣的主鍵, 二是其中一個實體經過外鍵關聯到另外一個實體的主鍵 (注意要模擬一對一關聯必須在外鍵列上添加惟一約束). 三是經過關聯表來保存兩個實體之間的鏈接關係 (注意要模擬一對一關聯必須在每個外鍵上添加惟一約束).
首先,咱們經過共享主鍵來進行一對一關聯映射:
@Entity public class Body { @Id public Long getId() { return id; } @OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn public Heart getHeart() { return heart; } ... }
@Entity public class Heart { @Id public Long getId() { ...} }
上面的例子經過使用註解@PrimaryKeyJoinColumn定義了一對一關聯.
下面這個例子使用外鍵列進行實體的關聯.
@Entity public class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="passport_fk") public Passport getPassport() { ... } @Entity public class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ... }
上面這個例子中,Customer 經過Customer 表中名爲的passport_fk 外鍵列和 Passport關聯. @JoinColumn註解定義了聯接列(join column). 該註解和@Column註解有點相似, 可是多了一個名爲referencedColumnName的參數. 該參數定義了所關聯目標實體中的聯接列. 注意,當referencedColumnName關聯到非主鍵列的時候, 關聯的目標類必須實現Serializable, 還要注意的是所映射的屬性對應單個列(不然映射無效).
一對一關聯多是雙向的.在雙向關聯中, 有且僅有一端是做爲主體(owner)端存在的:主體端負責維護聯接列(即更新). 對於不須要維護這種關係的從表則經過mappedBy屬性進行聲明.mappedBy的值指向主體的關聯屬性. 在上面這個例子中,mappedBy的值爲 passport. 最後,沒必要也不能再在被關聯端(owned side)定義聯接列了,由於已經在主體端進行了聲明.
若是在主體沒有聲明@JoinColumn,系統自動進行處理: 在主表(owner table)中將建立聯接列, 列名爲:主體的關聯屬性名+下劃線+被關聯端的主鍵列名. 在上面這個例子中是passport_id, 由於Customer中關聯屬性名爲passport, Passport的主鍵是id.
The third possibility (using an association table) is very exotic.
第三種方式也許是最另類的(經過關聯表).
@Entity public class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "CustomerPassports", joinColumns = @JoinColumn(name="customer_fk"), inverseJoinColumns = @JoinColumn(name="passport_fk") ) public Passport getPassport() { ... } @Entity public class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ... }
Customer經過名爲 CustomerPassports的關聯表和 Passport關聯; 該關聯表擁有名爲passport_fk的外鍵列,該 外鍵指向Passport表,該信息定義爲inverseJoinColumn的屬性值, 而customer_fk外鍵列指向Customer表, 該信息定義爲 joinColumns的屬性值.
這種關聯多是雙向的.在雙向關聯中, 有且僅有一端是做爲主體端存在的:主體端負責維護聯接列(即更新). 對於不須要維護這種關係的從表則經過mappedBy屬性進行聲明. mappedBy的值指向主體的關聯屬性. 在上面這個例子中,mappedBy的值爲 passport. 最後,沒必要也不能再在被關聯端(owned side)定義聯接列了,由於已經在主體端進行了聲明.
你必須明肯定義關聯表名和關聯列名.
在實體屬性一級使用@ManyToOne註解來定義多對一關聯:
@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
其中@JoinColumn是可選的,關聯字段默認值和一對一 (one to one)關聯的狀況類似, 列名爲:主體的關聯屬性名+下劃線+被關聯端的主鍵列名. 在這個例子中是company_id, 由於關聯的屬性是company, Company的主鍵是id.
@ManyToOne註解有一個名爲targetEntity的參數, 該參數定義了目標實體名.一般不須要定義該參數, 由於在大部分狀況下默認值(表示關聯關係的屬性類型)就能夠很好的知足要求了. 不過下面這種狀況下這個參數就顯得有意義了:使用接口做爲返回值而不是常見的實體.
@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
public interface Company {
...
對於多對一也能夠經過關聯表的方式來映射。 經過@JoinTable註解可定義關聯表, 該關聯表包含了指回實體表的外鍵(經過@JoinTable.joinColumns) 以及指向目標實體表的外鍵(經過@JoinTable.inverseJoinColumns).
@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinTable(name="Flight_Company", joinColumns = @JoinColumn(name="FLIGHT_ID"), inverseJoinColumns = @JoinColumn(name="COMP_ID") )
public Company getCompany() {
return company;
}
...
}
你能夠對 Collection ,List (指有序列表, 而不是索引列表), Map和Set這幾種類型進行映射. EJB3規範定義了怎麼樣使用@javax.persistence.OrderBy 註解來對有序列表進行映射: 該註解接受的參數格式:用逗號隔開的(目標實體)屬性名及排序指令, 如firstname asc, age desc,若是該參數爲空,則默認以id對該集合進行排序. 若是某個集合在數據庫中對應一個關聯表(association table)的話,你不能在這個集合屬性上面使用@OrderBy註解. 對於這種狀況的處理方法,請參考Hibernate Annotation Extensions. EJB3 容許你利用目標實體的一個屬性做爲Map的key, 這個屬性能夠用@MapKey(name="myProperty")來聲明. 若是使用@MapKey註解的時候不提供屬性名, 系統默認使用目標實體的主鍵. map的key使用和屬性相同的列:不須要爲map key定義專用的列,由於map key實際上就表達了一個目標屬性。 注意一旦加載,key再也不和屬性保持同步, 也就是說,若是你改變了該屬性的值,在你的Java模型中的key不會自動更新 (請參考Hibernate Annotation Extensions). 不少人被<map>和@MapKey弄糊塗了。 其餘它們有兩點區別.@MapKey目前還有一些限制,詳情請查看論壇或者 咱們的JIRA缺陷系統。 注意一旦加載,key再也不和屬性保持同步, 也就是說,若是你改變了該屬性的值,在你的Java模型中的key不會自動更新. (Hibernate 3中Map支持的方式在當前的發佈版中還未獲得支持).
Hibernate將集合分如下幾類.
表 2.1. 集合語義
語義 | Java實現類 | 註解 |
---|---|---|
Bag 語義 | java.util.List, java.util.Collection | @org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany |
List 語義 | java.util.List | (@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany) 以及 @org.hibernate.annotations.IndexColumn |
Set 語義 | java.util.Set | @org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany |
Map 語義 | java.util.Map | (@org.hibernate.annotations.CollectionOfElements 或 @OneToMany 或 @ManyToMany) 以及 (空 或 @org.hibernate.annotations.MapKey/MapKeyManyToMany(支持真正的map), 或 @javax.persistence.MapKey |
EJB3規範不支持原始類型,核心類型,嵌入式對象的集合.可是Hibernate對此提供了支持 (詳情參考 Hibernate Annotation Extensions).
@Entity public class City { @OneToMany(mappedBy="city") @OrderBy("streetName") public List<Street> getStreets() { return streets; } ... } @Entity public class Street { public String getStreetName() { return streetName; } @ManyToOne public City getCity() { return city; } ... } @Entity public class Software { @OneToMany(mappedBy="software") @MapKey(name="codeName") public Map<String, Version> getVersions() { return versions; } ... } @Entity @Table(name="tbl_version") public class Version { public String getCodeName() {...} @ManyToOne public Software getSoftware() { ... } ... }
上面這個例子中,City 中包括了以streetName排序的Street的集合. 而Software中包括了以codeName做爲 key和以Version做爲值的Map.
除非集合爲generic類型,不然你須要指定targetEntity. 這個註解屬性接受的參數爲目標實體的class.
在屬性級使用 @OneToMany註解可定義一對多關聯.一對多關聯能夠是雙向關聯.
在EJB3規範中多對一這端幾乎老是雙向關聯中的主體(owner)端, 而一對多這端的關聯註解爲@OneToMany( mappedBy=... )
@Entity public class Troop { @OneToMany(mappedBy="troop") public Set<Soldier> getSoldiers() { ... } @Entity public class Soldier { @ManyToOne @JoinColumn(name="troop_fk") public Troop getTroop() { ... }
Troop 經過troop 屬性和Soldier創建了一對多的雙向關聯. 在mappedBy端沒必要也不能再定義任何物理映射
對於一對多的雙向映射,若是要一對多這一端維護關聯關係, 你須要刪除mappedBy元素並將多對一這端的 @JoinColumn的insertable和updatable設置爲false. 很明顯,這種方案不會獲得什麼明顯的優化,並且還會增長一些附加的UPDATE語句.
@Entity public class Troop { @OneToMany @JoinColumn(name="troop_fk") //we need to duplicate the physical information public Set<Soldier> getSoldiers() { ... } @Entity public class Soldier { @ManyToOne @JoinColumn(name="troop_fk", insertable=false, updatable=false) public Troop getTroop() { ... }
經過在被擁有的實體端(owned entity)增長一個外鍵列來實現一對多單向關聯是不多見的,也是不推薦的. 咱們強烈建議經過一個聯接表(join table)來實現這種關聯(下一節會對此進行解釋). 能夠經過@JoinColumn註解來描述這種單向關聯關係.
@Entity public class Customer implements Serializable { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="CUST_ID") public Set<Ticket> getTickets() { ... } @Entity public class Ticket implements Serializable { ... //no bidir }
Customer 經過 CUST_ID列和Ticket 創建了單向關聯關係.
經過聯接表處理單向一對多關聯是首選方式.這種關聯經過@JoinTable註解來進行描述.
@Entity public class Trainer { @OneToMany @JoinTable( name="TrainedMonkeys", joinColumns = @JoinColumn( name="trainer_id"), inverseJoinColumns = @JoinColumn( name="monkey_id") ) public Set<Monkey> getTrainedMonkeys() { ... } @Entity public class Monkey { ... //no bidir }
上面這個例子中,Trainer經過 TrainedMonkeys表和 Monkey 創建了單向關聯. 其中外鍵trainer_id關聯到Trainer (joinColumns), 而外鍵monkey_id關聯到 Monkey (inversejoinColumns).
經過聯接表來創建單向一對多關聯不須要描述任何物理映射. 表名由如下三個部分組成:主表(owner table)表名+下劃線+從表(the other side table)表名. 指向主表的外鍵名:主表表名+下劃線+主表主鍵列名 指向從表的外鍵名:主表所對應實體的屬性名+下劃線+從表主鍵列名 指向從表的外鍵定義爲惟一約束,用來表示一對多的關聯關係.
@Entity public class Trainer { @OneToMany public Set<Tiger> getTrainedTigers() { ... } @Entity public class Tiger { ... //no bidir }
上面這個例子中,Trainer和Tiger 經過聯接表 Trainer_Tiger創建單向關聯關係, 其中外鍵trainer_id關聯到Trainer (主表表名, _(下劃線), trainer id), 而外鍵trainedTigers_id關聯到Tiger (屬性名稱, _(下劃線), Tiger表的主鍵列名).
你能夠經過@ManyToMany註解可定義的多對多關聯. 同時,你也須要經過註解@JoinTable描述關聯表和關聯條件. 若是是雙向關聯,其中一段必須定義爲owner,另外一端必須定義爲inverse(在對關聯表進行更新操做時這一端將被忽略):
@Entity public class Employer implements Serializable { @ManyToMany( targetEntity=org.hibernate.test.metadata.manytomany.Employee.class, cascade={CascadeType.PERSIST, CascadeType.MERGE} ) @JoinTable( name="EMPLOYER_EMPLOYEE", joinColumns=@JoinColumn(name="EMPER_ID"), inverseJoinColumns=@JoinColumn(name="EMPEE_ID") ) public Collection getEmployees() { return employees; } ... }
@Entity public class Employee implements Serializable { @ManyToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "employees", targetEntity = Employer.class ) public Collection getEmployers() { return employers; } }
至此,咱們已經展現了不少跟關聯有關的聲明定義以及屬性細節. 下面咱們將深刻介紹@JoinTable註解,該註解定義了聯接表的表名, 聯接列數組(註解中定義數組的格式爲{ A, B, C }), 以及inverse聯接列數組. 後者是關聯表中關聯到Employee主鍵的列(the "other side").
正如前面所示,被關聯端沒必要也不能描述物理映射: 只須要一個簡單的mappedBy參數,該參數包含了主體端的屬性名,這樣就綁定雙方的關係.
和其餘許多註解同樣,在多對多關聯中不少值是自動生成. 當雙向多對多關聯中沒有定義任何物理映射時,Hibernate根據如下規則生成相應的值. 關聯表名:主表表名+_下劃線+從表表名, 關聯到主表的外鍵名:主表名+_下劃線+主表中的主鍵列名. 關聯到從表的外鍵名:主表中用於關聯的屬性名+_下劃線+從表的主鍵列名. 以上規則對於雙向一對多關聯一樣有效.
@Entity public class Store { @ManyToMany(cascade = CascadeType.PERSIST) public Set<City> getImplantedIn() { ... } } @Entity public class City { ... //no bidirectional relationship }
上面這個例子中,Store_Table做爲聯接表. Store_id列是聯接到Store表的外鍵. 而implantedIn_id列則聯接到City表.
當雙向多對多關聯中沒有定義任何物理映射時, Hibernate根據如下規則生成相應的值 關聯表名: :主表表名+_下劃線+從表表名, 關聯到主表的外鍵名:從表用於關聯的屬性名+_下劃線+主表中的主鍵列名. 關聯到從表的外鍵名:主表用於關聯的屬性名+_下劃線+從表的主鍵列名. 以上規則對於雙向一對多關聯一樣有效.
@Entity public class Store { @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) public Set<Customer> getCustomers() { ... } } @Entity public class Customer { @ManyToMany(mappedBy="customers") public Set<Store> getStores() { ... } }
在上面這個例子中,Store_Customer做爲聯接表. stores_id列是聯接到Store表的外鍵, 而customers_id列聯接到City表.
也許你已經注意到了cascade屬性接受的值爲CascadeType數組. 在EJB3中的cascade的概念和Hibernate中的傳播性持久化以及cascade操做很是相似, 可是在語義上有細微的區別,支持的cascade類型也有點區別:
關於cascading, create/merge的語義請參考EJB3規範的6.3章節.
組合主鍵使用一個可嵌入的類做爲主鍵表示,所以你須要使用@Id 和@Embeddable兩個註解. 還有一種方式是使用@EmbeddedId註解.注意所依賴的類必須實現 serializable以及實現equals()/hashCode()方法. 你也能夠如Mapping identifier properties一章中描述的辦法使用@IdClass註解.
@Entity public class RegionalArticle implements Serializable { @Id public RegionalArticlePk getPk() { ... } } @Embeddable public class RegionalArticlePk implements Serializable { ... }
或者
@Entity public class RegionalArticle implements Serializable { @EmbeddedId public RegionalArticlePk getPk() { ... } } public class RegionalArticlePk implements Serializable { ... }
@Embeddable 註解默認繼承了其所屬實體的訪問類型, 除非顯式使用了Hibernate的@AccessType註解(這個註解不是EJB3標準的一部分). 而@JoinColumns,即@JoinColumn數組, 定義了關聯的組合外鍵(若是不使用缺省值的話). 顯式指明referencedColumnNames是一個好的實踐方式, 不然,Hibernate認爲你使用的列順序和主鍵聲明的順序一致.
@Entity public class Parent implements Serializable { @Id public ParentPk id; public int age; @OneToMany(cascade=CascadeType.ALL) @JoinColumns ({ @JoinColumn(name="parentCivility", referencedColumnName = "isMale"), @JoinColumn(name="parentLastName", referencedColumnName = "lastName"), @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") }) public Set<Child> children; //unidirectional ... }
@Entity public class Child implements Serializable { @Id @GeneratedValue public Integer id; @ManyToOne @JoinColumns ({ @JoinColumn(name="parentCivility", referencedColumnName = "isMale"), @JoinColumn(name="parentLastName", referencedColumnName = "lastName"), @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") }) public Parent parent; //unidirectional }
@Embeddable public class ParentPk implements Serializable { String firstName; String lastName; ... }
注意上面的 referencedColumnName顯式使用方式.
使用類一級的 @SecondaryTable 或 @SecondaryTables 註解能夠實現單個實體到多個表的映射. 使用 @Column 或者 @JoinColumn 註解中的 table 參數可指定某個列所屬的特定表.
@Entity @Table(name="MainCat") @SecondaryTables({ @SecondaryTable(name="Cat1", pkJoinColumns={ @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id") ), @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})}) }) public class Cat implements Serializable { private Integer id; private String name; private String storyPart1; private String storyPart2; @Id @GeneratedValue public Integer getId() { return id; } public String getName() { return name; } @Column(table="Cat1") public String getStoryPart1() { return storyPart1; } @Column(table="Cat2") public String getStoryPart2() { return storyPart2; }
在上面這個例子中,name保存在MainCat表中, storyPart1保存在Cat1表中, storyPart2保存在Cat2表中. Cat1表經過外鍵cat_id和MainCat表關聯, Cat2表經過id列和MainCat表關聯 (和MainCat的id列同名). 對storyPart2列還定義了惟一約束.
在JBoss EJB 3指南和Hibernate Annotations單元測試代碼中還有更多的例子.
使用註解還能夠映射EJBQL/HQL查詢. @NamedQuery 和@NamedQueries是可以使用在類和包上的註解. 可是它們的定義在session factory/entity manager factory範圍中是均可見的. 命名式查詢經過它的名字和實際的查詢字符串來定義.
javax.persistence.NamedQueries( @javax.persistence.NamedQuery(name="plane.getAll", query="select p from Plane p") ) package org.hibernate.test.annotations.query; ... @Entity @NamedQuery(name="night.moreRecentThan", query="select n from Night n where n.date >= :date") public class Night { ... } public class MyDao { doStuff() { Query q = s.getNamedQuery("night.moreRecentThan"); q.setDate( "date", aMonthAgo ); List results = q.list(); ... } ... }
還能夠經過定義 QueryHint 數組的hints 屬性爲查詢提供一些hint信息.
下面是目前可使用的一些Hibernate hint:
表 2.2. Query hints
hint | description |
---|---|
org.hibernate.cacheable | 查詢是否與二級緩存交互(默認值爲false) |
org.hibernate.cacheRegion | 設置緩存區名稱 (默認爲otherwise) |
org.hibernate.timeout | 查詢超時設定 |
org.hibernate.fetchSize | 所獲取的結果集(resultset)大小 |
org.hibernate.flushMode | 本次查詢所用的刷新模式 |
org.hibernate.cacheMode | 本次查詢所用的緩存模式 |
org.hibernate.readOnly | 是否將本次查詢所加載的實體設爲只讀(默認爲false) |
org.hibernate.comment | 將查詢註釋添加入所生成的SQL |
你還能夠映射本地化查詢(也就是普通SQL查詢). 不過這須要你使用@SqlResultSetMapping註解來描述SQL的resultset的結構 (若是你打算定義多個結果集映射,但是使用@SqlResultSetMappings). @SqlResultSetMapping和@NamedQuery, @SqlResultSetMapping同樣,能夠定義在類和包一級. 可是@SqlResultSetMapping的做用域爲應用級. 下面咱們會看到,@NamedNativeQuery 註解中 resultSetMapping參數值爲@SqlResultSetMapping的名字. 結果集映射定義了經過本地化查詢返回值和實體的映射. 該實體中的每個字段都綁定到SQL結果集中的某個列上. 該實體的全部字段包括子類的全部字段以及 關聯實體的外鍵列都必須在SQL查詢中有對應的定義. 若是實體中的屬性和SQL查詢中的列名相同,這種狀況下能夠不進行定義字段映射.
@NamedNativeQuery(name="night&area", query="select night.id nid, night.night_duration, "
+ " night.night_date, area.id aid, night.area_id, area.name "
+ "from Night night, Area area where night.area_id = area.id", resultSetMapping="joinMapping")
@SqlResultSetMapping(name="joinMapping", entities={
@EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id"),
discriminatorColumn="disc"
}),
@EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
}
)
在上面這個例子中,名爲night&area的查詢 和joinMapping結果集映射對應. 該映射返回兩個實體,分別爲Night 和Area,其中每一個屬性都和一個列關聯, 列名經過查詢獲取.下面咱們看一個隱式聲明屬性和列映射關係的例子.
@Entity
@SqlResultSetMapping(name="implicit", entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class)) @NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultSetMapping="implicit")
public class SpaceShip {
private String name;
private String model;
private double speed;
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="model_txt")
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
}
在這個例子中,咱們只須要定義結果集映射中的實體成員. 屬性和列名之間的映射藉助實體中包含映射信息來完成. 在這個例子中,model屬性綁定到model_txt列. 若是和相關實體的關聯設計到組合主鍵, 那麼應該使用@FieldResult註解來定義每一個外鍵列. @FieldResult的名字由如下幾部分組成: 定義這種關係的屬性名字+"."+主鍵名或主鍵列或主鍵屬性.
@Entity
@SqlResultSetMapping(name="compositekey",
entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
fields = {
@FieldResult(name="name", column = "name"),
@FieldResult(name="model", column = "model"),
@FieldResult(name="speed", column = "speed"),
@FieldResult(name="captain.firstname", column = "firstn"), @FieldResult(name="captain.lastname", column = "lastn"),
@FieldResult(name="dimensions.length", column = "length"),
@FieldResult(name="dimensions.width", column = "width")
}),
columns = { @ColumnResult(name = "surface"),
@ColumnResult(name = "volume") } )
@NamedNativeQuery(name="compositekey",
query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width as surface from SpaceShip",
resultSetMapping="compositekey")
} )
public class SpaceShip {
private String name;
private String model;
private double speed;
private Captain captain;
private Dimensions dimensions;
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumns( {
@JoinColumn(name="fname", referencedColumnName = "firstname"),
@JoinColumn(name="lname", referencedColumnName = "lastname")
} )
public Captain getCaptain() {
return captain;
}
public void setCaptain(Captain captain) {
this.captain = captain;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public Dimensions getDimensions() {
return dimensions;
}
public void setDimensions(Dimensions dimensions) {
this.dimensions = dimensions;
}
}
@Entity
@IdClass(Identity.class)
public class Captain implements Serializable {
private String firstname;
private String lastname;
@Id
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Id
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
若是查詢返回的是單個實體,或者你打算使用系統默認的映射, 這種狀況下能夠不使用resultSetMapping 而是使用resultClass屬性:
@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultClass=SpaceShip.class)
public class SpaceShip {
某些本地查詢返回的是scalar值,例如報表查詢. 你能夠經過@ColumnResult將其映射到 @SqlResultsetMapping上. 甚至還能夠在同一個本地查詢的結果中混合實體和scalar類型(不過這種狀況比較少見).
@SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension")) @NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMapping="scalar")
本地查詢中還有另一個hint屬性: org.hibernate.callable. 這個屬性的布爾變量值代表這個查詢是不是一個存儲過程.
Hibernate 3.1 提供了多種附加的註解,這些註解能夠與EJB3的實體混合/匹配使用. 他們被設計成EJB3註解的天然擴展.
爲了強化EJB3的能力,Hibernate提供了與其自身特性相吻合的特殊註解. org.hibernate.annotations包已包含了全部的這些註解擴展.
你能夠在EJB3規範所能提供的能力以外,就Hibernate對實體所作的一些操做進行優化.
@org.hibernate.annotations.Entity 追加了可能須要的額外的元數據, 而這些元數據超出了標準@Entity 中所定義的元數據.
如下是一些附加的Hibernate註解擴展:
@org.hibernate.annotations.BatchSize 容許你定義批量獲取該實體的實例數量(如:@BatchSize(size=4)). 當加載一特定的實體時,Hibernate將加載在持久上下文中未經初始化的同類型實體,直至批量數量(上限).
@org.hibernate.annotations.Proxy 定義了實體的延遲屬性.Lazy(默認爲true)定義了類是否爲延遲(加載). proxyClassName是用來生成代理的接口(默認爲該類自己).
@org.hibernate.annotations.Where 定義了當獲取類實例時所用的SQL WHERE子句(該SQL WHERE子句爲可選).
@org.hibernate.annotations.Check 定義了在DDL語句中定義的合法性檢查約束(該約束爲可選).
@OnDelete(action=OnDeleteAction.CASCADE) 定義於被鏈接的子類(joined subclass):在刪除時使用SQL級連刪除,而非一般的Hibernate刪除機制.
@Table(name="tableName", indexes = { @Index(name="index1", columnNames={"column1", "column2"} ) } ) 在tableName表的列上建立定義好的索引. 該註解能夠被應用於關鍵表或者是其餘次要的表. @Tables 註解容許你在不一樣的表上應用索引. 此註解預期在使用 @javax.persistence.Table或 @javax.persistence.SecondaryTable的地方中出現.
@org.hibernate.annotations.Table 是對 @javax.persistence.Table的補充而不是它的替代品. 特別是當你打算改變表名的默認值的時候,你必須使用@javax.persistence.Table, 而不是@org.hibernate.annotations.Table.
@Entity @BatchSize(size=5) @org.hibernate.annotations.Entity( selectBeforeUpdate = true, dynamicInsert = true, dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL, polymorphism = PolymorphismType.EXPLICIT) @Where(clause="1=1") @org.hibernate.annotations.Table(name="Forest", indexes = { @Index(name="idx", columnNames = { "name", "length" } ) } ) public class Forest { ... }
@Entity @Inheritance( strategy=InheritanceType.JOINED ) public class Vegetable { ... } @Entity @OnDelete(action=OnDeleteAction.CASCADE) public class Carrot extends Vegetable { ... }
@org.hibernate.annotations.GenericGenerator 容許你定義一個Hibernate特定的id生成器.
@Id @GeneratedValue(generator="system-uuid") @GenericGenerator(name="system-uuid", strategy = "uuid") public String getId() { @Id @GeneratedValue(generator="hibseq") @GenericGenerator(name="hibseq", strategy = "seqhilo", parameters = { @Parameter(name="max_lo", value = "5"), @Parameter(name="sequence", value="heybabyhey") } ) public Integer getId() {
strategy能夠是Hibernate3生成器策略的簡稱, 或者是一個IdentifierGenerator實現的(帶包路徑的)全限定類名. 你能夠經過parameters屬性增長一些參數.
訪問類型是根據@Id或@EmbeddedId 在實體繼承層次中所處的位置推演而得的.子實體(Sub-entities), 內嵌對象和被映射的父類均繼承了根實體(root entity)的訪問類型.
在Hibernate中,你能夠把訪問類型覆蓋成:
使用定製的訪問類型策略
優化類級或屬性級的訪問類型
爲支持這種行爲,Hibernate引入了@AccessType註解.你能夠對如下元素定義訪問類型:
實體
父類
可內嵌的對象
屬性
被註解元素的訪問類型會被覆蓋,若覆蓋是在類一級上,則全部的屬性繼承訪問類型. 對於根實體,其訪問類型會被認爲是整個繼承層次中的缺省設置(可在類或屬性一級覆蓋).
若訪問類型被標以"property",則Hibernate會掃描getter方法的註解,若訪問類型被標以"field", 則掃描字段的註解.不然,掃描標爲@Id或@embeddedId的元素.
你能夠覆蓋某個屬性(property)的訪問類型,可是受註解的元素將不受影響: 例如一個具備field訪問類型的實體,(咱們)能夠將某個字段標註爲 @AccessType("property"), 則該字段的訪問類型隨之將成爲property,可是其餘字段上依然須要攜帶註解.
若父類或可內嵌的對象沒有被註解,則使用根實體的訪問類型(即便已經在非直系父類或可內嵌對象上定義了訪問類型). 此時俄羅斯套娃(Russian doll)原理就再也不適用.(譯註:俄羅斯套娃(матрёшка或 матрешка)是俄羅斯特產木製玩具, 通常由多個同樣圖案的空心木娃娃一個套一個組成,最多可達十多個,一般爲圓柱形,底部平坦能夠直立.)
@Entity
public class Person implements Serializable {
@Id @GeneratedValue //access type field
Integer id;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "iso2", column = @Column(name = "bornIso2")),
@AttributeOverride(name = "name", column = @Column(name = "bornCountryName"))
})
Country bornIn;
}
@Embeddable
@AccessType("property") //override access type for all properties in Country
public class Country implements Serializable {
private String iso2;
private String name;
public String getIso2() {
return iso2;
}
public void setIso2(String iso2) {
this.iso2 = iso2;
}
@Column(name = "countryName")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
有時候,你想讓數據庫,而非JVM,來替你完成一些計算,也可能想建立某種虛擬列. 你可使用SQL片斷(亦稱爲公式),而不是將屬性映射到(物理)列. 這種屬性是隻讀的(屬性值由公求得).
@Formula("obj_length * obj_height * obj_width") public long getObjectVolume()
SQL片斷能夠是任意複雜的,甚至可包含子查詢.
@org.hibernate.annotations.Type 覆蓋了Hibernate所用的默認類型:這一般不是必須的,由於類型能夠由Hibernate正確推得. 關於Hibernate類型的詳細信息,請參考Hibernate使用手冊.
@org.hibernate.annotations.TypeDef 和 @org.hibernate.annotations.TypeDefs容許你來聲明類型定義. 這些註解被置於類或包一級.注意,對session factory來講, 這些定義將是全局的(即便定義於類一級),而且類型定義必須先於任何使用.
@TypeDefs( { @TypeDef( name="caster", typeClass = CasterStringType.class, parameters = { @Parameter(name="cast", value="lower") } ) } ) package org.hibernate.test.annotations.entity; ... public class Forest { @Type(type="caster") public String getSmallText() { ... }
當使用組合的用戶自定義類型時,你必須本身表示列的定義. @Columns就是爲了此目的而引入的.
@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType") @Columns(columns = { @Column(name="r_amount"), @Column(name="r_currency") }) public MonetaryAmount getAmount() { return amount; } public class MonetaryAmount implements Serializable { private BigDecimal amount; private Currency currency; ... }
經過在列屬性(property)上使用@Index註解, 能夠在特定列上定義索引,columnNames屬性(attribute)將隨之被忽略.
@Column(secondaryTable="Cat1") @Index(name="story1index") public String getStoryPart1() { return storyPart1; }
在嵌入式對象內部,你能夠在那些指向該嵌入式對象所屬元素的屬性上定義該註解.
@Entity public class Person { @Embeddable public Address address; ... } @Embeddable public class Address { @Parent public Person owner; ... } person == person.address.owner
某些屬性能夠在對數據庫作插入或更新操做的時候生成. Hibernate可以處理這樣的屬性,並觸發一個後續的查詢來讀取這些屬性.
@Entity public class Antenna { @Id public Integer id; @Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false) public String longitude; @Generated(GenerationTime.INSERT) @Column(insertable = false) public String latitude; }
你能夠將屬性註解爲@Generated. 可是你要注意insertability和updatability不要和你選擇的生成策略衝突. 若是選擇了GenerationTime.INSERT,該屬性不能包含insertable列, 若是選擇了GenerationTime.ALWAYS,該屬性不能包含insertable和updatable列.
@Version屬性不能夠爲 @Generated(INSERT)(設計時), 只能是 NEVER或ALWAYS.
SINGLE_TABLE 是個功能強大的策略,但有時,特別對遺留系統而言, 是沒法加入一個額外的辨別符列. 由此,Hibernate引入了辨別符公式(discriminator formula)的概念:@DiscriminatorFormula是@DiscriminatorColumn的替代品, 它使用SQL片斷做爲辨別符解決方案的公式( 不須要有一個專門的字段).
@Entity @DiscriminatorForumla("case when forest_type is null then 0 else forest_type end") public class Forest { ... }
默認狀況下,當預期的被關聯元素不在數據庫中(關乎關聯列的錯誤id),導致Hiberante沒法解決關聯性問題時,Hibernate就會拋出異常. 這對遺留schema和歷經拙劣維護的schema而言,這或有許多不便. 此時,你可用 @NotFound 註解讓Hibernate略過這樣的元素而不是拋出異常. 該註解可用於 @OneToOne (有外鍵)、 @ManyToOne 、 @OneToMany 或 @ManyToMany 關聯.
@Entity public class Child { ... @ManyToOne @NotFound(action=NotFoundAction.IGNORE) public Parent getParent() { ... } ... }
有時候刪除某實體的時候須要觸發數據庫的級聯刪除.
@Entity public class Child { ... @ManyToOne @OnDelete(action=OnDeleteAction.CASCADE) public Parent getParent() { ... } ... }
上面這個例子中,Hibernate將生成一個數據庫級的級聯刪除約束.
EJB3爲延遲加載和獲取模式提供了fetch選項,而Hibernate 這方面提供了更豐富的選項集.爲了更好的調整延遲加載和獲取策略,Hibernate引入了 一些附加的註解:
@LazyToOne: 定義了 @ManyToOne 和 @OneToOne 關聯的延遲選項. LazyToOneOption 能夠是 PROXY (例如:基於代理的延遲加載), NO_PROXY (例如:基於字節碼加強的延遲加載 - 注意須要在構建期處理字節碼) 和 FALSE (非延遲加載的關聯)
@LazyCollection: 定義了 @ManyToMany和 @OneToMany 關聯的延遲選項. LazyCollectionOption 能夠是TRUE (集合具備延遲性,只有在訪問的時候才加載), EXTRA (集合具備延遲性,而且全部的操做都會盡可能避免加載集合, 對於一個巨大的集合特別有用,由於這樣的集合中的元素沒有必要所有加載)和 FALSE (非延遲加載的關聯)
@Fetch: 定義了加載關聯關係的獲取策略. FetchMode 能夠是 SELECT (在須要加載關聯的時候觸發select操做), SUBSELECT (只對集合有效,使用了子查詢策略,詳情參考Hibernate參考文檔) or JOIN (在加載主實體(owner entity)的時候使用SQL JOIN來加載關聯關係). JOIN 將覆寫任何延遲屬性 (經過JOIN策略加載的關聯將再也不具備延遲性).
The Hibernate annotations overrides the EJB3 fetching options.
Hibernate註解覆寫了EJB3提供的獲取(fetch)選項.
表 2.3. 延遲和獲取選項的等效註解
Annotations | Lazy | Fetch |
---|---|---|
@[One|Many]ToOne](fetch=FetchType.LAZY) | @LazyToOne(PROXY) | @Fetch(SELECT) |
@[One|Many]ToOne](fetch=FetchType.EAGER) | @LazyToOne(FALSE) | @Fetch(JOIN) |
@ManyTo[One|Many](fetch=FetchType.LAZY) | @LazyCollection(TRUE) | @Fetch(SELECT) |
@ManyTo[One|Many](fetch=FetchType.EAGER) | @LazyCollection(FALSE) | @Fetch(JOIN) |
如下是可能的設置方式
你也能夠利用@Sort註解定義一個排序比較器(sort comparator), 代表但願的比較器類型,無序、天然順序或自定義排序,三者擇一.若你想用你本身實現的comparator, 你還須要利用comparator屬性(attribute)指明實現類.
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="CUST_ID") @Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class) @Where(clause="1=1") @OnDelete(action=OnDeleteAction.CASCADE) public SortedSet<Ticket> getTickets() { return tickets; }
關於這些註解更詳細的信息,請參閱此前的描述.
比EJB3更勝一籌的是,Hibernate Annotations支持真正的 List和Array. 映射集合的方式和之前徹底同樣,只不過要新增@IndexColumn註解. 該註解容許你指明存放索引值的字段.你還能夠定義表明數據庫中首個元素的索引值(亦稱爲索引基數). 常見取值爲0或1.
@OneToMany(cascade = CascadeType.ALL) @IndexColumn(name = "drawer_position", base=1) public List<Drawer> getDrawers() { return drawers; }
Hibernate註解支持true Map映射, 若是沒有設置@javax.persistence.MapKey, hibernate將key元素或嵌入式對象直接映射到他們所屬的列. 要覆寫默認的列,可使用如下註解:@org.hibernate.annotations.MapKey適用的key爲基本類型或者嵌入式對象, @org.hibernate.annotations.MapKey適用的key爲實體.
Hibernate Annotations還支持核心類型集合(Integer, String, Enums, ......)、 可內嵌對象的集合,甚至基本類型數組.這就是所謂的元素集合.
元素集合可用@CollectionOfElements來註解(做爲@OneToMany的替代). 爲了定義集合表(譯註:即存放集合元素的表,與下面提到的主表對應),要在關聯屬性上使用@JoinTable註解, joinColumns定義了介乎實體主表與集合表之間的鏈接字段(inverseJoincolumn是無效的且其值應爲空). 對於核心類型的集合或基本類型數組,你能夠在關聯屬性上用@Column來覆蓋存放元素值的字段的定義. 你還能夠用@AttributeOverride來覆蓋存放可內嵌對象的字段的定義. 要訪問集合元素,須要將該註解的name屬性值設置爲"element"("element"用於核心類型,而"element.serial" 用於嵌入式對象的serial屬性).要訪問集合的index/key,則將該註解的name屬性值設置爲"key".
@Entity public class Boy { private Integer id; private Set<String> nickNames = new HashSet<String>(); private int[] favoriteNumbers; private Set<Toy> favoriteToys = new HashSet<Toy>(); private Set<Character> characters = new HashSet<Character>(); @Id @GeneratedValue public Integer getId() { return id; } @CollectionOfElements public Set<String> getNickNames() { return nickNames; } @CollectionOfElements @JoinTable( table=@Table(name="BoyFavoriteNumbers"), joinColumns = @JoinColumn(name="BoyId") ) @Column(name="favoriteNumber", nullable=false) @IndexColumn(name="nbr_index") public int[] getFavoriteNumbers() { return favoriteNumbers; } @CollectionOfElements @AttributeOverride( name="element.serial", column=@Column(name="serial_nbr") ) public Set<Toy> getFavoriteToys() { return favoriteToys; } @CollectionOfElements public Set<Character> getCharacters() { return characters; } ... } public enum Character { GENTLE, NORMAL, AGGRESSIVE, ATTENTIVE, VIOLENT, CRAFTY } @Embeddable public class Toy { public String name; public String serial; public Boy owner; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSerial() { return serial; } public void setSerial(String serial) { this.serial = serial; } @Parent public Boy getOwner() { return owner; } public void setOwner(Boy owner) { this.owner = owner; } public boolean equals(Object o) { if ( this == o ) return true; if ( o == null || getClass() != o.getClass() ) return false; final Toy toy = (Toy) o; if ( !name.equals( toy.name ) ) return false; if ( !serial.equals( toy.serial ) ) return false; return true; } public int hashCode() { int result; result = name.hashCode(); result = 29 * result + serial.hashCode(); return result; } }
在嵌入式對象的集合中,可使用 @Parent註解嵌入式對象的某屬性. 該屬性指向該嵌入式對象所屬的集合實體.
爲了優化數據庫訪問,你能夠激活所謂的Hibernate二級緩存.該緩存是能夠按每一個實體和集合進行配置的.
@org.hibernate.annotations.Cache定義了緩存策略及給定的二級緩存的範圍. 此註解適用於根實體(非子實體),還有集合.
@Entity @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public class Forest { ... }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="CUST_ID") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public SortedSet<Ticket> getTickets() { return tickets; }
@Cache( CacheConcurrencyStrategy usage(); (1) String region() default ""; (2) String include() default "all"; (3) )
(1) | usage: 給定緩存的併發策略(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL) |
(2) | region (可選的):緩存範圍(默認爲類的全限定類名或是集合的全限定角色名) |
(3) | include (可選的):值爲all時包括了全部的屬性(proterty), 爲non-lazy時僅含非延遲屬性(默認值爲all) |
Hibernate具備數據過濾器的概念,可在運行期應用於一個給定的session.過濾器須要事先定義好.
@org.hibernate.annotations.FilterDef 或 @FilterDefs 定義過濾器聲明,爲同名過濾器所用. 過濾器聲明帶有一個name()和一個parameters()數組,@ParamDef包含name和type, 你還能夠爲給定的@filterDef定義一個defaultCondition()參數, 當@Filter中沒有任何定義時,可以使用該參數定義缺省條件. @FilterDef (s)能夠在類或包一級進行定義.
如今咱們來定義應用於實體或集合加載時的SQL過濾器子句.咱們使用@Filter,並將其置於實體或集合元素上.
@Entity @FilterDef(name="minLength", parameters=@ParamDef( name="minLength", type="integer" ) ) @Filters( { @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"), @Filter(name="minLength", condition=":minLength <= length") } ) public class Forest { ... }
因爲Hibernate引入了 @org.hibernate.annotations.NamedQuery, @org.hibernate.annotations.NamedQueries, @org.hibernate.annotations.NamedNativeQuery 和@org.hibernate.annotations.NamedNativeQueries 命名式查詢, 所以Hibernate在命名式查詢上比EBJ3規範中所定義的命名式查詢提供了更多的特性. 他們在標準版中添加了可做爲替代品的一些屬性(attributes):
flushMode: 定義查詢的刷新模式(Always, Auto, Commit或Manual)
cacheable: 查詢該不應被緩存
cacheRegion: 若查詢已被緩存時所用緩存的範圍
fetchSize: 針對該查詢的JDBC statement單次獲取記錄的數目
timeout: 查詢超時
callable: 僅用於本地化查詢(native query),對於存儲過程設爲true
comment: 一旦激活註釋功能,咱們會在向數據庫交送查詢請求時看到註釋
cacheMode: 緩存交護模式(get, ignore,normal,或refresh)
readOnly: 無論是否從查詢獲取元素都是在只讀模式下
注意,EJB3已公開的最終草案中引入了@QueryHint的概念, 這多是定義hints更好的方法.
在EJB3中元數據的主要目標是使用註釋,可是EJB3規範也提供經過XML部署文件來覆寫或者替換元數據註釋. 在當前的發佈版本僅僅支持EJB3註釋的覆寫,若是你想使用Hibernate特有的一些實體註釋, 你有兩種選擇:一,只使用註釋;二,使用原來的hbm 映射文件.你固然仍是能夠同時使用註釋實體和hbm XML映射文件的實體.
在測試套件中有一些附加的XML文件的樣例.
XML部署文件結構被設計爲直接映射註釋結構,因此若是你知道註釋的結構,那麼使用XML語法是很簡單的.
你能夠定義一個或者多個XML文件來描述你的元數據,這些文件會被覆寫引擎合併(merged).
你可使用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 orm_1_0.xsd" version="1.0"> <persistence-unit-metadata> <xml-mapping-metadata-complete/> <persistence-unit-defaults> <schema>myschema</schema> <catalog>mycatalog</catalog> <cascade-persist/> </persistence-unit-defaults> </persistence-unit-metadata>
xml-mapping-metadata-complete 意味着全部的實體,mapped-superclasses和嵌套的元數據應該從XML文件中啓用(忽略註釋).
schema / catalog 將覆寫全部在元數據中默認定義的schema 和 catalog(包括XML和註釋).
cascade-persist 意味着全部註釋做爲一個 cascade type 都是PERSIST的. 咱們推薦你不要使用該特性.
你也能夠在一個給定的實體上定義或者覆寫元數據
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings (1) 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 orm_1_0.xsd" version="1.0"> <package>org.hibernate.test.annotations.reflection</package> (2) <entity class="Administration" access="PROPERTY" metadata-complete="true"> (3) <table name="tbl_admin"> (4) <unique-constraint> <column-name>firstname</column-name> <column-name>lastname</column-name> </unique-constraint> </table> <secondary-table name="admin2"> (5) <primary-key-join-column name="admin_id" referenced-column-name="id"/> <unique-constraint> <column-name>address</column-name> </unique-constraint> </secondary-table> <id-class class="SocialSecurityNumber"/> (6) <inheritance strategy="JOINED"/> (7) <sequence-generator name="seqhilo" sequence-name="seqhilo"/> (8) <table-generator name="table" table="tablehilo"/> (9) ... </entity> <entity class="PostalAdministration"> <primary-key-join-column name="id"/> (10) ... </entity> </entity-mappings>
(1) | entity-mappings:entity-mappings 是全部XML文件的根元素.你必須定義XML Schema, 該文件包含在hibernate-annotations.jar中,使用Hibernate Annotations 不須要訪問網絡. |
(2) | package (可選的): 做爲默認的package用於在一個給定的部署描述文件中全部沒有限定的類. |
(3) | entity: 描述一個實體. metadata-complete 定義對於該元素是否所有使用元數據(換句話來講就是,若是註釋出如今類級別應該考慮或者忽略). 一個實體不得不有一個 class 屬性來引用 元數據所應用的類. 經過name屬性你能夠覆寫實體的名字, 若是沒有定義而且@Entity.name出現了的話,那麼就使用該註釋(假如metadata complete 沒有被設置). 對於metadata complete (參考下面)元素, 你能夠定義一個 access(FIELD 或者 PROPERTY(默認值)), 對於非metadata complete 元素,使用註釋的access type. |
(4) | table: 你能夠聲明table 屬性(name, schema, catalog), 若是沒有定義, 將使用Java註釋. 就象例子中所示的那樣你能夠定義一個或者多個unique constraints |
(5) | secondary-table: 定義一個secondary-table,除了你能夠經過primary-key-join-column 元素定義 primary key / foreign key 列之外是和通常的table同樣的. 在非metadata complete下, annotation secondary tables 僅僅在沒有secondary-table 定義的狀況下使用, 不然 註釋將被忽略. |
(6) | id-class: 和@IdClass同樣定義一個id class. |
(7) | inheritance: 定義繼承策略(JOINED, TABLE_PER_CLASS, SINGLE_TABLE), 僅僅在根實體級別可使用. |
(8) | sequence-generator: 定義一個序列產生器. |
(9) | table-generator: 定義一個table generator |
(10) | primary-key-join-column: 當 JOINED 繼承策略使用時,爲sub entities定義一個 primary key join column. |
<?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 orm_1_0.xsd" version="1.0"> <package>org.hibernate.test.annotations.reflection</package> <entity class="Music" access="PROPERTY" metadata-complete="true"> <discriminator-value>Generic</discriminator-value> (1) <discriminator-column length="34"/> ... </entity> <entity class="PostalAdministration"> <primary-key-join-column name="id"/> <named-query name="adminById"> (2) <query>select m from Administration m where m.id = :id</query> <hint name="org.hibernate.timeout" value="200"/> </named-query> <named-native-query name="allAdmin" result-set-mapping="adminrs"> (3) <query>select *, count(taxpayer_id) as taxPayerNumber from Administration, TaxPayer where taxpayer_admin_id = admin_id group by ...</query> <hint name="org.hibernate.timeout" value="200"/> </named-native-query> <sql-result-set-mapping name="adminrs"> (4) <entity-result entity-class="Administration"> <field-result name="name" column="fld_name"/> </entity-result> <column-result name="taxPayerNumber"/> </sql-result-set-mapping> <attribute-override name="ground"> (5) <column name="fld_ground" unique="true" scale="2"/> </attribute-override> <association-override name="referer"> <join-column name="referer_id" referenced-column-name="id"/> </association-override> ... </entity> </entity-mappings>
(1) | discriminator-value / discriminator-column: 當SINGLE_TABLE繼承策略使用時,定義鑑別器值 和 保存該值的列. |
(2) | named-query: 定義命名查詢和一些相關的可能的線索. 該定義附加在註釋的定義中,若是兩個都定義了相同的名字,那麼XML將優先考慮. |
(3) | named-native-query: 定義一個命名本地查詢 和他的 sql result set 映射. 做爲另一種選擇,你能夠定義result-class. 這些定義附加在註釋的定義中.若是兩個定義了一樣的名字,XML文件優先考慮. |
(4) | sql-result-set-mapping: 描述了 result set mapping 的結構. 你能夠定義 實體和列映射. 這些定義附加在註釋的定義中,若是定義了一樣的名字,XML文件優先考慮. |
(5) | attribute-override / association-override: 定義一列或者join column overriding. 該overriding 附加在註釋的定義中. |
一些應用於 <embeddable> 和 <mapped-superclass>.
你固然能夠定義XML來覆寫屬性. 若是metadata complete 給定義了,那麼附加的屬性(如: 在Java 級別的)將被忽略. 另外,一旦你開始覆寫一個屬性,在該屬性上的全部註釋都會被忽略.全部屬性級別的元數據應用於entity/attributes, mapped-superclass/attributes 或 embeddable/attributes.
<attributes> <id name="id"> <column name="fld_id"/> <generated-value generator="generator" strategy="SEQUENCE"/> <temporal>DATE</temporal> <sequence-generator name="generator" sequence-name="seq"/> </id> <version name="version"/> <embedded name="embeddedObject"> <attribute-override name"subproperty"> <column name="my_column"/> </attribute-override> </embedded> <basic name="status" optional="false"> <enumerated>STRING</enumerated> </basic> <basic name="serial" optional="true"> <column name="serialbytes"/> <lob/> </basic> <basic name="terminusTime" fetch="LAZY"> <temporal>TIMESTAMP</temporal> </basic> </attributes>
經過 id, embedded-id, version, embedded 和 basic你能夠覆寫一個屬性, 這些元素中的每個元素都有相應的subelements:lob, temporal, enumerated, column.
你能夠定義XML覆寫關聯註釋. 全部的關聯級別的元數據做用於 entity/attributes, mapped-superclass/attributes 或 embeddable/attributes.
<attributes> <one-to-many name="players" fetch="EAGER"> <map-key name="name"/> <join-column name="driver"/> <join-column name="number"/> </one-to-many> <many-to-many name="roads" target-entity="Administration"> <order-by>maxSpeed</order-by> <join-table name="bus_road"> <join-column name="driver"/> <join-column name="number"/> <inverse-join-column name="road_id"/> <unique-constraint> <column-name>driver</column-name> <column-name>number</column-name> </unique-constraint> </join-table> </many-to-many> <many-to-many name="allTimeDrivers" mapped-by="drivenBuses"> </attributes>
經過one-to-many, one-to-one, many-to-one, 和 many-to-many. 你能夠重寫一個關聯關係.這些元素中的每個都有相應的subelements. join-table (能夠有 join-column和 inverse-join-column), join-column, map-key, 和 order-by. mapped-by 和 target-entity 當他們有意義的時候能夠定義屬性. 再一次強調 該結構映射於註釋的結構.在描述註釋的一章中 你能夠找到全部的語義信息.
註解是一種爲領域模型(domain model)指定不變約束的簡潔而幽雅的方法。例如,你能 表示一個屬性永遠不爲null,一個賬戶餘額必定是正值,等等。這些域模型約束經過爲bean中的屬性添加 註解來加以聲明。隨後一個驗證器(validator)會讀取並檢查這些約束。驗證機制能夠執行於應用程序中的 不一樣層(表現層、數據訪問層),而沒必要複述任何(前述)這些規則。Hibernate驗證器正爲這一目的而設計的。
Hibernate驗證器工做在兩個層次上。第一層,它能檢查內存中一個類的實例是否違反約束。 第二層,它能將約束應用於Hibernate元模型上,並將它們融入生成的數據庫schema中。
每一個約束註解(constraint annotation)和一個驗證器實現關聯,該驗證器負責檢查位於實體實例上的約束。 一個驗證器也能(可選地)將約束應用於Hibernate元模型上,讓Hibernate生成表示這一約束的DDL。使用合適的事件監聽器,你能 讓Hibernate在插入和更新時執行檢查操做。Hibernate驗證器並不侷限於同Hibernate一塊兒使用。 你能在你應用程序的任何地方方便地使用它。
在運行時檢查實例時,Hibernate驗證器返回違反約束的信息, 這些信息以一個InvalidValue數組的形式返回。 除了衆多其餘信息外,InvalidValue包含了一個錯誤描述消 息,該信息能夠內嵌與註解相捆綁的參數值(例如長度限制),以及能被提取至ResourceBundle的消息字串。
Hibernate驗證器有些內建約束,這些約束覆蓋了大多數的基本數據檢查。隨後咱們會看到, 你沒必要受制於這些內置約束,由於一分鐘內就能夠寫出你本身的約束。
表 4.1. 內建約束
註解 | 應用目標 | 運行時檢查 | Hibernate元數據影響 |
---|---|---|---|
@Length(min=, max=) | 屬性(String) | 檢查字符串長度是否符合範圍 | 列長度會被設到最大值 |
@Max(value=) | 屬性 (以numeric或者string類型來表示一個數字) | 檢查值是否小於或等於最大值 | 對列增長一個檢查約束 |
@Min(value=) | 屬性(以numeric或者string類型來表示一個數字) | 檢查值是否大於或等於最小值 | 對列增長一個檢查約束 |
@NotNull | 屬性 | 檢查值是否非空(not null) | 列不爲空 |
@Past | 屬性(date或calendar) | 檢查日期是不是過去時 | 對列增長一個檢查約束 |
@Future | 屬性 (date 或 calendar) | 檢查日期是不是未來時 | 無 |
@Pattern(regex="regexp", flag=) | 屬性 (string) | 檢查屬性是否與給定匹配標誌的正則表達式相匹配(見 java.util.regex.Pattern ) | 無 |
@Range(min=, max=) | 屬性(以numeric或者string類型來表示一個數字) | 檢查值是否在最小和最大值之間(包括臨界值) | 對列增長一個檢查約束 |
@Size(min=, max=) | 屬性 (array, collection, map) | 檢查元素大小是否在最小和最大值之間(包括臨界值) | 無 |
@AssertFalse | 屬性 | 檢查方法的演算結果是否爲false(對以代碼方式而不是註解表示的約束頗有用) | 無 |
@AssertTrue | 屬性 | 檢查方法的演算結果是否爲true(對以代碼方式而不是註解表示的約束頗有用) | 無 |
@Valid | 屬性 (object) | 對關聯對象遞歸的進行驗證。若是對象是集合或數組,就遞歸地驗證其元素。若是對象是Map,則遞歸驗證其值元素。 | 無 |
屬性(String) | 檢查字符串是否符合有效的email地址規範。 | 無 |
Hibernate驗證器提供了一組默認的錯誤提示信息,它們被翻譯成多種語言(若是你的語言不在其中,請給 咱們寄一個補丁)。你能夠在org.hibernate.validator.resources.DefaultValidatorMessages.properties 以外建立ValidatorMessages.properties或ValidatorMessages_loc.properties 文件並改變相應的鍵值,籍此覆蓋那些(默認)信息。你甚至能夠在寫本身的驗證器 註解時添加你本身的附加消息集。
或者你能夠以編程方式檢查bean的驗證規則並提供相應的ResourceBundle。
擴展內建約束集是極其方便的。任何約束都包括兩部分:約束描述符(註解) 和約束驗證器(實現類)。下面是一個簡單的用戶定義描述符:
@ValidatorClass(CapitalizedValidator.class) @Target(METHOD) @Retention(RUNTIME) @Documented public @interface Capitalized { CapitalizeType type() default Capitalize.FIRST; String message() default "has incorrect capitalization"; }
type參數描述屬性應該如何被大寫。這是一個徹底依賴於註解業務(邏輯)的用戶 參數。
message是用於描述約束違規的默認字符串,它是強制要求的。你能夠採起硬編碼的方式, 或者經過Java ResourceBundle機制將message的部分/所有內容提取至外部文件。一旦發現message中{parameter}字符串, 就會在{parameter}這個位置注入相應的參數值(在咱們的例子裏Capitalization is not {type}會生成 Capitalization is not FIRST), 能夠將message對應的整個字符串提取至外部文件ValidatorMessages.properties,這也是一種良好實踐。 見Error messages。
@ValidatorClass(CapitalizedValidator.class) @Target(METHOD) @Retention(RUNTIME) @Documented public @interface Capitalized { CapitalizeType type() default Capitalize.FIRST; String message() default "{validator.capitalized}"; } ... #in ValidatorMessages.properties validator.capitalized=Capitalization is not {type}
如你所見{}符號是遞歸的。
爲了將一個描述符鏈接到它的驗證器實現,咱們使用@ValidatorClass 元註解。驗證器類參數必須指定一個實現了Validator<ConstraintAnnotation> 的類。
咱們如今要實現驗證器(也就是實現規則檢查)。一個驗證器實現能檢查一個屬性的值 (實現PropertyConstraint),而且/或者能夠修改hibernate映射元數據 (實現PersistentClassConstraint),籍此表示數據庫級的約束。
public class CapitalizedValidator implements Validator<Capitalized>, PropertyConstraint { private CapitalizeType type; //part of the Validator<Annotation> contract, //allows to get and use the annotation values public void initialize(Capitalized parameters) { type = parameters.type(); } //part of the property constraint contract public boolean isValid(Object value) { if (value==null) return true; if ( !(value instanceof String) ) return false; String string = (String) value; if (type == CapitalizeType.ALL) { return string.equals( string.toUpperCase() ); } else { String first = string.substring(0,1); return first.equals( first.toUpperCase(); } } }
若是違反約束,isValid()方法將返回false。更多例子請參考內建驗證器實現。
至此咱們只看到屬性級的驗證,你還能夠寫一個Bean級別的驗證註解。Bean自身會被傳遞給驗證器, 而不是bean的屬性實例。只要對bean自身進行註解便可激活驗證檢查。在單元測試套件中還能夠找到一個小例子。
既然你如今已經熟悉註解了,那麼對語法也應該很清楚了。
public class Address { private String line1; private String line2; private String zip; private String state; private String country; private long id; // a not null string of 20 characters maximum @Length(max=20) @NotNull public String getCountry() { return country; } // a non null string @NotNull public String getLine1() { return line1; } //no constraint public String getLine2() { return line2; } // a not null string of 3 characters maximum @Length(max=3) @NotNull public String getState() { return state; } // a not null numeric string of 5 characters maximum // if the string is longer, the message will //be searched in the resource bundle at key 'long' @Length(max=5, message="{long}") @Pattern(regex="[0-9]+") @NotNull public String getZip() { return zip; } // should always be true @AssertTrue public boolean isValid() { return true; } // a numeric between 1 and 2000 @Id @Min(1) @Range(max=2000) public long getId() { return id; } }
上面的例子只展現了公共屬性驗證,你還能夠對任何可見度的字段(field)進行註解。
@MyBeanConstraint(max=45) public class Dog { @AssertTrue private boolean isMale; @NotNull protected String getName() { ... }; ... }
你能夠對接口進行註解。Hibernate驗證器會檢查給定bean所擴展或實現的全部父類和接口, 籍以讀取相應的驗證器註解(信息)。
public interface Named { @NotNull String getName(); ... } public class Dog implements Named { @AssertTrue private boolean isMale; public String getName() { ... }; }
在驗證Dog bean時會檢查name屬性的有效性(不爲null)。
Hibernate驗證器旨在實現多層數據驗證,咱們在一處表示約束(帶註解的域模型),而後將其運用於 應用程序的不一樣層。
無須額外手續,Hibernate Annotations會自動將你爲實體定義的約束翻譯爲映射元數據。例如,若是你的實體 的一個屬性註解爲@NotNull,在Hibernate生成的DDL schema中這列會被定義爲 not null。
Hibernate驗證器有兩個內建Hibernate事件監聽器。當一個PreInsertEvent 或PreUpdateEvent發生時,監聽器會驗證該實體實例的全部約束,若有違反會拋出一個異常。 基本上,在Hibernate執行任何插入和更新前對象會被檢查。這是激活驗證過程的最便捷最簡單的方法。當遇到約束 違規時,事件會引起一個運行時InvalidStateException,該異常包含一個描述每一個錯誤的 InvalidValue數組。
<hibernate-configuration> ... <event type="pre-update"> <listener class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/> </event> <event type="pre-insert"> <listener class="org.hibernate.validator.event.ValidatePreInsertEventListener"/> </event> </hibernate-configuration>
Hibernate驗證器能應用於你應用程序代碼中的任何地方。
ClassValidator personValidator = new ClassValidator( Person.class ); ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) ); InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);
頭兩行爲執行類檢查而準備Hibernate驗證器。第一行依賴於嵌入在Hibernate驗證器內的錯誤 消息(見Error messages),第二行爲這些消息準備資源包。這些代碼只執行一次, 並將驗證器進行緩存處理,這種方式是一種良好實踐。
第三行真正驗證了Address實例並返回一個InvalidValue數組。 你的應用程序邏輯隨後能夠對錯誤作出響應。
除了針對整個bean你還能夠對某個特定屬性進行檢查。這對於一個屬性一個屬性的用戶交互情形或許是有用的。
ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) ); //only get city property invalid values InvalidValue[] validationMessages = addressValidator.getInvalidValues(address, "city"); //only get potential city property invalid values InvalidValue[] validationMessages = addressValidator.getPotentialInvalidValues("city", "Paris")
做爲一個驗證信息的載體,hibernate提供了一個InvalidValue數組。 每一個InvalidValue有一組,這些方法分別描述相應的個體問題。
getBeanClass()獲取失敗的bean類型。
getBean()獲取驗證失敗的實例(若是有的話,當使用 getPotentianInvalidValues()時則不會取到)
getValue()獲取驗證失敗的值
getMessage()獲取合適的國際化錯誤消息
getRootBean()獲取產生問題的根bean實例(在與@Valid連用 時頗有用),如用getPotentianInvalidValues()則返回null。
getPropertyPath()獲取「問題」屬性從根bean開始的帶點的路徑
Lucene是一個高性能的java搜索引擎庫,能夠從 Apache軟件基金組織獲取。 Hibernate Annotations包括一個註解包,它容許把任何域模型對象標記爲可索引的, 而且對任何經由Hibernate進行持續化的實例,Hibernate 都會爲之維護一個對應的Lucene索引。
首先,必須將一個持久類聲明爲 @Indexed:
@Entity @Indexed(index="indexes/essays") public class Essay { ... }
屬性index是告訴Hibernate, Lucene索引信息所在的位置(你文件系統的某個目錄)。 若是你想爲全部的Lucene索引定義一個根目錄,你能夠在配置文件中用屬性hibernate.lucene.index_dir進行配置。
Lucene索引包括四種字段:keyword 字段,text 字段,unstored字段和unindexed字段。 Hibernate註解提供了將實體屬性標記爲前三種被索引字段的註解。
@Entity @Indexed(index="indexes/essays") public class Essay { ... @Id @Keyword(id=true) public Long getId() { return id; } @Text(name="Abstract") public String getSummary() { return summary; } @Lob @Unstored public String getText() { return text; } }
這些註解定義了一個帶有三個字段的索引: Id, Abstract 和 Text.
注意:你必須在你的實體類的標誌屬性上指定 @Keyword(id=true) .
用於對元素創建索引的分析器類是能夠經過hibernate.lucene.analyzer屬性進行配置的。 若是沒有定義,則把 org.apache.lucene.analysis.standard.StandardAnalyzer做爲缺省。
咱們激活用於幀聽三類Hibernate事件的 LuceneEventListener, 這些事件會在變動被提交至數據庫後產生。
<hibernate-configuration> ... <event type="post-commit-update" <listener class="org.hibernate.lucene.event.LuceneEventListener"/> </event> <event type="post-commit-insert" <listener class="org.hibernate.lucene.event.LuceneEventListener"/> </event> <event type="post-commit-delete" <listener class="org.hibernate.lucene.event.LuceneEventListener"/> </event> </hibernate-configuration>