Hibernate的類(lèi)型分類(lèi)
Hibernate 有哪些類(lèi)型呢?如果不清楚那么你看過(guò)本文,相信你對(duì)Hibernate類(lèi)型一定會(huì)明白很多。
1. 實(shí)體(Entities)和值(values)
為了理解很多與持久化服務(wù)相關(guān)的Java語(yǔ)言級(jí)對(duì)象的行為,我們需要把它們分為兩類(lèi):
實(shí)體entity 獨(dú)立于任何持有實(shí)體引用的對(duì)象。與通常的Java模型相比,不再被引用的對(duì)象會(huì)被當(dāng)作垃圾收集掉。實(shí)體必須被顯式的保存和刪除(除非保存和刪除是從父實(shí)體向子實(shí)體引發(fā)的級(jí)聯(lián))。這和ODMG模型中關(guān)于對(duì)象通過(guò)可觸及保持持久性有一些不同——比較起來(lái)更加接近應(yīng)用程序?qū)ο笸ǔT谝粋€(gè)大系統(tǒng)中的使用方法。實(shí)體支持循環(huán)引用和交叉引用,它們也可以加上版本信息。
一個(gè)實(shí)體的持久狀態(tài)包含指向其他實(shí)體和值類(lèi)型實(shí)例的引用。值可以是原始類(lèi)型,集合(不是集合中的對(duì)象),組件或者特定的不可變對(duì)象。與實(shí)體不同,值(特別是集合和組件)是通過(guò)可觸及性來(lái)進(jìn)行持久化和刪除的。因?yàn)橹祵?duì)象(和原始類(lèi)型數(shù)據(jù))是隨著包含他們的實(shí)體而被持久化和刪除的,他們不能被獨(dú)立的加上版本信息。值沒(méi)有獨(dú)立的標(biāo)識(shí),所以他們不能被兩個(gè)實(shí)體或者集合共享。
直到現(xiàn)在,我們都一直使用術(shù)語(yǔ)“持久類(lèi)”(persistent class)來(lái)代表實(shí)體。我們?nèi)匀粫?huì)這么做。 然而嚴(yán)格說(shuō)來(lái),不是所有的用戶自定義的,帶有持久化狀態(tài)的類(lèi)都是實(shí)體。組件就是用戶自定義類(lèi),卻是值語(yǔ)義的。java.lang.String類(lèi)型的java屬性也是值語(yǔ)義的。給了這個(gè)定義以后,我們可以說(shuō)所有JDK提供的類(lèi)型(類(lèi))都是值類(lèi)型的語(yǔ)義,而用于自定義類(lèi)型可能被映射為實(shí)體類(lèi)型或值類(lèi)型語(yǔ)義。采用哪種類(lèi)型的語(yǔ)義取決于開(kāi)發(fā)人員。在領(lǐng)域模型中,尋找實(shí)體類(lèi)的一個(gè)好線索是共享引用指向這個(gè)類(lèi)的單一實(shí)例,而組合或聚合通常被轉(zhuǎn)化為值類(lèi)型。
我們會(huì)在本文檔中重復(fù)碰到這兩個(gè)概念。
挑戰(zhàn)在于將java類(lèi)型系統(tǒng)(和開(kāi)發(fā)者定義的實(shí)體和值類(lèi)型)映射到 SQL/數(shù)據(jù)庫(kù)類(lèi)型系統(tǒng)。Hibernate提供了連接兩個(gè)系統(tǒng)之間的橋梁:對(duì)于實(shí)體類(lèi)型,我們使用
所有的Hibernate內(nèi)建類(lèi)型,除了collections以外,都支持空(null)語(yǔ)義。
2. 基本值Hibernate類(lèi)型
內(nèi)建的 基本映射類(lèi)型可以大致分為integer, long, short, float, double, character, byte, boolean, yes_no, true_false 這些類(lèi)型都對(duì)應(yīng)Java的原始類(lèi)型或者其封裝類(lèi),來(lái)符合(特定廠商的)SQL 字段類(lèi)型。boolean, yes_no 和 true_false都是Java 中boolean 或者java.lang.Boolean的另外說(shuō)法。
string 從java.lang.String 到 VARCHAR (或者 Oracle的 VARCHAR2)的映射。
date, time, timestamp 從java.util.Date和其子類(lèi)到SQL類(lèi)型DATE, TIME 和TIMESTAMP (或等價(jià)類(lèi)型)的映射。
calendar, calendar_date 從java.util.Calendar 到SQL 類(lèi)型TIMESTAMP和 DATE(或等價(jià)類(lèi)型)的映射。
big_decimal, big_integer 從java.math.BigDecimal和java.math.BigInteger到NUMERIC (或者 Oracle 的NUMBER類(lèi)型)的映射。
locale, timezone, currency 從java.util.Locale, java.util.TimeZone 和java.util.Currency 到VARCHAR (或者 Oracle 的VARCHAR2類(lèi)型)的映射. Locale和 Currency 的實(shí)例被映射為它們的ISO代碼。TimeZone的實(shí)例被影射為它的ID。
class 從java.lang.Class 到 VARCHAR (或者 Oracle 的VARCHAR2類(lèi)型)的映射。Class被映射為它的全限定名。
binary 把字節(jié)數(shù)組(byte arrays)映射為對(duì)應(yīng)的 SQL二進(jìn)制類(lèi)型。
text 把長(zhǎng)Java字符串映射為SQL的CLOB或者TEXT類(lèi)型。
serializable 把可序列化的Java類(lèi)型映射到對(duì)應(yīng)的SQL二進(jìn)制類(lèi)型。你也可以為一個(gè)并非默認(rèn)為基本類(lèi)型的可序列化Java類(lèi)或者接口指定Hibernate類(lèi)型serializable。
clob, blob JDBC 類(lèi) java.sql.Clob 和 java.sql.Blob的映射。某些程序可能不適合使用這個(gè)類(lèi)型,因?yàn)閎lob和clob對(duì)象可能在一個(gè)事務(wù)之外是無(wú)法重用的。(而且, 驅(qū)動(dòng)程序?qū)@種類(lèi)型的支持充滿著補(bǔ)丁和前后矛盾。)
imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary 一般來(lái)說(shuō),映射類(lèi)型被假定為是可變的Java類(lèi)型,只有對(duì)不可變Java類(lèi)型,Hibernate會(huì)采取特定的優(yōu)化措施,應(yīng)用程序會(huì)把這些對(duì)象作為不可變對(duì)象處理。比如,你不應(yīng)該對(duì)作為imm_timestamp映射的Date執(zhí)行Date.setTime()。要改變屬性的值,并且保存這一改變,應(yīng)用程序必須對(duì)這一屬性重新設(shè)置一個(gè)新的(不一樣的)對(duì)象。
實(shí)體及其集合的***標(biāo)識(shí)可以是除了binary、 blob 和 clob之外的任何基礎(chǔ)類(lèi)型。(聯(lián)合標(biāo)識(shí)也是允許的,后面會(huì)說(shuō)到。)
在org.hibernate.Hibernate中,定義了基礎(chǔ)類(lèi)型對(duì)應(yīng)的Type常量。比如,Hibernate.STRING代表string 類(lèi)型。
3. 自定義值Hibernate類(lèi)型
開(kāi)發(fā)者創(chuàng)建屬于他們自己的值類(lèi)型也是很容易的。比如說(shuō),你可能希望持久化java.lang.BigInteger類(lèi)型的屬性,持久化成為VARCHAR字段。Hibernate沒(méi)有內(nèi)置這樣一種類(lèi)型。自定義類(lèi)型能夠映射一個(gè)屬性(或集合元素)到不止一個(gè)數(shù)據(jù)庫(kù)表字段。比如說(shuō),你可能有這樣的Java屬性:getName()/setName(),這是java.lang.String類(lèi)型的,對(duì)應(yīng)的持久化到三個(gè)字段:FIRST_NAME, INITIAL, SURNAME。
要實(shí)現(xiàn)一個(gè)自定義類(lèi)型,可以實(shí)現(xiàn)org.hibernate.UserType或org.hibernate.CompositeUserType中的任一個(gè),并且使用類(lèi)型的Java全限定類(lèi)名來(lái)定義屬性。請(qǐng)查看org.hibernate.test.DoubleStringType這個(gè)例子,看看它是怎么做的。
- <property name="twoStrings" type="org.hibernate.test.DoubleStringType">
- <column name="first_string"/>
- <column name="second_string"/>
- property>
注意使用
CompositeUserType, EnhancedUserType, UserCollectionType, 和 UserVersionType 接口為更特殊的使用方式提供支持。
你甚至可以在一個(gè)映射文件中提供參數(shù)給一個(gè)UserType。 為了這樣做,你的UserType必須實(shí)現(xiàn)org.hibernate.usertype.ParameterizedType接口。為了給自定義類(lèi)型提供參數(shù),你可以在映射文件中使用
- <property name="priority">
- <type name="com.mycompany.usertypes.DefaultValueIntegerType">
- <param name="default">0param>
- type>
- property>
現(xiàn)在,UserType 可以從傳入的Properties對(duì)象中得到default 參數(shù)的值。
如果你非常頻繁地使用某一UserType,可以為他定義一個(gè)簡(jiǎn)稱(chēng)。這可以通過(guò)使用
- <typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
- <param name="default">0param>
- typedef>
- <property name="priority" type="default_zero"/>
也可以根據(jù)具體案例通過(guò)屬性映射中的類(lèi)型參數(shù)覆蓋在typedef中提供的參數(shù)。
盡管 Hibernate 內(nèi)建的豐富的類(lèi)型和對(duì)組件的支持意味著你可能很少 需要使用自定義類(lèi)型。不過(guò),為那些在你的應(yīng)用中經(jīng)常出現(xiàn)的(非實(shí)體)類(lèi)使用自定義類(lèi)型也是一個(gè)好方法。例如,一個(gè)MonetaryAmount類(lèi)使用CompositeUserType來(lái)映射是不錯(cuò)的選擇,雖然他可以很容易地被映射成組件。這樣做的動(dòng)機(jī)之一是抽象。使用自定義類(lèi)型,以后假若你改變表示金額的方法時(shí),它可以保證映射文件不需要修改。
【編輯推薦】