Hibernate采用對象標識符,也就是通常我們所說的OID來創建對象和數據庫表里記錄的對應關系,對象的OID和表里的主鍵對應,所以說OID是非常重要的,不應該讓程序來給它賦值.數據庫區分同一表的不同記錄是用主鍵來區分.數據庫中的主鍵最重要的3個基本要素就是不允許為null,不允許有重復值,主鍵永遠不會改變.所以通常我們設計表都會設計主鍵的值為自動增加,沒有業務邏輯含義的一組數字,當然針對每個數據庫,設置的方法也不同.但是都非常簡單.加一個屬性就可以了.
而JAVA區分同一類的不同對象是用內存地址,在JAVA語言中判斷兩個對象的引用變量是否想相等,有以下兩種比較方式.1)用運算符"=="比較內存地址,此外還可以用Object的equals方法也是按內存地址比較.2)比較兩個對象的值是否相同,JAVA中的一些覆蓋了Object類的equals方法實現比較合適.例如String和Date類,還有JAVA包裝類.如果是String.equals(String)這種方式的比較就是比較這兩個String的值的.如果是Object原是的equals方法就是比較地址了.這點很容易混淆.
通常,為了包裝Hibernate的OID的唯一性和不可變性,由Hibernate或者底層數據庫來給OID賦值比較合理.因此我們在編程的時候最好把持久化類的OID設置為private或者protected類型,這樣可以防止JAVA程序隨便更改OID.而OID的get方法我們還是要設置為public類型,這樣方便我們讀取. 在對象-關系映射文件里的<id元素是用來設置對象標識符OID的.type通常設置為long.而<generator子元素用來設置OID的標識符生成器,Hibernate提供了標識符生成器的接口net.sf.hibernate.id.IdentifierGenerator接口,并且提供了N多中內置的實現,和對應的縮寫.我們只要把這些實現類的類名或者所寫設置在<generator子元素的class屬性中,就能完成OID的配置了.具體的內置標識符生成器如下:
1)increment 代理主鍵,hibernate自動以遞增的方式來生成標識符,每次增加1.
2)identity 代理主鍵,由底層數據庫生成標識符,前提就是底層的數據庫支持自動增長的類型.
3)sequence 代理主鍵,hibernate根據底層數據庫生成的標識符,前提是底層數據庫支持序列
4)hilo 代理主鍵,hibernate根據higg/low算法來生成的標識符,把特定表的字段作為high的值,默認選用hibernate_unique_key表的next_hi字段
5)native 代理主鍵,根據底層數據庫對自動生成標識符的支持能力,還選擇identity,sequence,或hilo.
6)uuid.hex 代理主鍵,hibernate采用128位的UUID算法生成標識符,UUID算法能夠在網絡環境下生成唯一字符串標識符.不過字符串要比數據占用的空間多的多.所以不流行使用.
7)assigned 適用于自然主鍵,由JAVA應用程序負責生成標識符,為了能讓JAVA設置OID.不能吧setId方法設置為非公共類型了,這種方式也盡量避免使用.
這里個人覺得第一種方式,也就是說由Hibernate來生成對象標識符的方式比較好.但是這種方式的缺點是只能一個Hibernate對應一個數據庫的表.當同時創建了SeesionFactory實例的時候.兩個或者更多的Hibernate對應同一個數據庫的時候就會插入出錯.這個時候我們可以選擇第二種方式把標識符的生成工作交給底層數據庫.還有一個小知識點要注意就是OID必須定義為long,int,short類型,如果定義為byte會報異常,這里推薦用long.
總結一下,這7中生成OID標識符的方法,increment 比較常用,把標識符生成的權力交給Hibernate處理.但是當同時多個Hibernate應用操作同一個數據庫,甚至同一張表的時候.就推薦使用identity 依賴底層數據庫實現,但是數據庫必須支持自動增長,sequence 以來底層數據庫實現,但是數據庫必須支持系列.hilo 根據特定的表實現.這三種方式了.當然針對不同的數據庫選擇不同的方法.如果你不能確定你使用的數據庫具體支持什么的情況下.可以選擇第三種.或者用native 讓Hibernate來幫選擇identity,sequence,或hilo.后邊的自然主鍵不推薦使用,因為自然主鍵就是具有業務含義的主鍵,在現在的軟件開發結構中,已經很少有人用了.下面總結一下幾種常用數據庫,可以使用的標識符類型.
MySQL:identity數據庫底層實現,需要支持自動增長,increment由Hibernate實現,hilo用特定的表實現,
MSSQL:identity數據庫底層實現,需要支持自動增長,increment由Hibernate實現,hilo用特定的表實現,
Oracle:sequence數據庫底層實現,需要支持序列,increment由Hibernate實現,hilo用特定的表實現,
以上不難發現,所有的數據庫都支持Hibernate用increment實現OID的生成,MYSQL和MSSQL數據庫底層實現支持自動增長,而Oracle支持序列,還有用特殊表的實現方式這三個數據庫都支持.還有一種實現方式適用于所有的數據庫,就是native,由Hibernate去選擇使用什么樣的方式來生成IOD對象標識符,這種方式也是跨平臺的.下面是各種設置方式的例子*.hbm.xml文件四個.例題來源孫MM的<<精通Hibernate>>一書.我非常喜歡這本書,講的非常簡單明了.感興趣的朋友可以去買一本看看(當當打7.3折哦).
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"<hibernate-mapping>
<class name="mypack.HiloTester" table="HILO_TESTER">
<id name="id" type="long" column="ID">
<generator class="hilo">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
<property name="name" type="string" >
<column name="name" length="15" />
</property>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"<hibernate-mapping>
<class name="mypack.IdentityTester" table="IDENTITY_TESTER">
<id name="id" type="long" column="ID">
<generator class="identity"/>
</id>
<property name="name" type="string" >
<column name="name" length="15"/>
</property>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"<hibernate-mapping>
<class name="mypack.NativeTester" table="NATIVE_TESTER" >
<id name="id" type="long" column="ID">
<generator class="native"/>
</id>
<property name="name" type="string" >
<column name="name" length="15" />
</property>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"<hibernate-mapping>
<class name="mypack.IncrementTester" table="INCREMENT_TESTER" >
<id name="id" type="long" column="ID">
<meta attribute="scope-set">private</meta>
<generator class="increment"/>
</id>
<property name="name" type="string" >
<column name="NAME" length="15" />
</property>
</class>
</hibernate-mapping>