隨筆 - 0, 文章 - 75, 評論 - 0, 引用 - 0
          數據加載中……

          Hibernate各種主鍵生成策略與配置詳解


          1、assigned


          主鍵由外部程序負責生成,在
          save() 之前必須指定一個。Hibernate不負責維護主鍵生成。與Hibernate和底層數據庫都無關,可以跨數據庫。在存儲對象前,必須要使用主鍵的setter方法給主鍵賦值,至于這個值怎么生成,完全由自己決定,這種方法應該盡量避免。



          <id name="id" column="id">


          <generator class="assigned" />


          </id>


          ud”是自定義的策略名,人為起的名字,后面均用“ud”表示。


          特點:可以跨數據庫,人為控制主鍵生成,應盡量避免。


          2、increment


          Hibernate從數據庫中取出主鍵的最大值(每個session只取1次),以該值為基礎,每次增量為1,在內存中生成主鍵,不依賴于底層的數據庫,因此可以跨數據庫。



          <id name="id" column="id">


          <generator class="increment" />


          </id>


          Hibernate調用org.hibernate.id.IncrementGenerator類里面的generate()方法,使用select
          max(idColumnName) from tableName
          語句獲取主鍵最大值。該方法被聲明成了synchronized,所以在一個獨立的Java虛擬機內部是沒有問題的,然而,在多個JVM同時并發訪問數據庫select
          max
          時就可能取出相同的值,再insert就會發生Dumplicate
          entry
          的錯誤。所以只能有一個Hibernate應用進程訪問數據庫,否則就可能產生主鍵沖突,所以不適合多進程并發更新數據庫,適合單一進程訪問數據庫,不能用于群集環境。


          官方文檔:只有在沒有其他進程往同一張表中插入數據時才能使用,在集群下不要使用。


          特點:跨數據庫,不適合多進程并發更新數據庫,適合單一進程訪問數據庫,不能用于群集環境。


          3、hilo


          hilo(高低位方式high
          low
          )是hibernate中最常用的一種生成方式,需要一張額外的表保存hi的值。保存hi值的表至少有一條記錄(只與第一條記錄有關),否則會出現錯誤。可以跨數據庫。



          <id name="id" column="id">


          <generator class="hilo">



          <param name="table">hibernate_hilo</param>



          <param name="column">next_hi</param>



          <param name="max_lo">100</param>


          </generator>


          </id>


          <param name="table">hibernate_hilo</param> 指定保存hi值的表名


          <param name="column">next_hi</param>
          指定保存hi值的列名


          <param name="max_lo">100</param>  
          指定低位的最大值


          也可以省略tablecolumn配置,其默認的表為hibernate_unique_key,列為next_hi



          <id name="id" column="id">


          <generator class="hilo">



          <param name="max_lo">100</param>


          </generator>


          </id>


          hilo生成器生成主鍵的過程(以hibernate_unique_key表,next_hi列為例):


          1. 獲得hi值:讀取并記錄數據庫的hibernate_unique_key表中next_hi字段的值,數據庫中此字段值加1保存。


          2. 獲得lo值:從0max_lo循環取值,差值為1,當值為max_lo值時,重新獲取hi值,然后lo值繼續從0max_lo循環。


          3. 根據公式
          hi * (max_lo + 1) +
          lo
          計算生成主鍵值。


          注意:當hi值是0的時候,那么第一個值不是0*(max_lo+1)+0=0,而是lo跳過01開始,直接是123……


          max_lo配置多大合適呢?


          這要根據具體情況而定,如果系統一般不重啟,而且需要用此表建立大量的主鍵,可以吧max_lo配置大一點,這樣可以減少讀取數據表的次數,提高效率;反之,如果服務器經常重啟,可以吧max_lo配置小一點,可以避免每次重啟主鍵之間的間隔太大,造成主鍵值主鍵不連貫。


          特點:跨數據庫,hilo算法生成的標志只能在一個數據庫中保證唯一。


          4、seqhilo


          hilo類似,通過hi/lo算法實現的主鍵生成機制,只是將hilo中的數據表換成了序列sequence,需要數據庫中先創建sequence,適用于支持sequence的數據庫,如oracle



          <id name="id" column="id">


          <generator class="seqhilo">



          <param name="sequence">hibernate_seq</param>



          <param name="max_lo">100</param>


          </generator>


          </id>



          特點:與hilo類似,只能在支持序列的數據庫中使用。

          5、sequence


          采用數據庫提供的sequence機制生成主鍵,需要數據庫支持sequence。如oralceDBSAP DBPostgerSQLMcKoi中的sequenceMySQL這種不支持sequence的數據庫則不行(可以使用identity)。



          <generator
          class="sequence">


          <param name="sequence">hibernate_id</param>



          </generator>


          <param name="sequence">hibernate_id</param> 指定sequence的名稱


          Hibernate生成主鍵時,查找sequence并賦給主鍵值,主鍵值由數據庫生成,Hibernate不負責維護,使用時必須先創建一個sequence,如果不指定sequence名稱,則使用Hibernate默認的sequence,名稱為hibernate_sequence,前提要在數據庫中創建該sequence


          特點:只能在支持序列的數據庫中使用,如Oracle


          6、identity


          identity由底層數據庫生成標識符。identity是由數據庫自己生成的,但這個主鍵必須設置為自增長,使用identity的前提條件是底層數據庫支持自動增長字段類型,如DB2SQL ServerMySQLSybaseHypersonicSQL等,Oracle這類沒有自增字段的則不支持。



          <id name="id"
          column="id">


          <generator
          class="identity" />



          </id>


          例:如果使用MySQL數據庫,則主鍵字段必須設置成auto_increment


          id int(11)
          primary key auto_increment


          特點:只能用在支持自動增長的字段數據庫中使用,如MySQL


          7、native


          nativehibernate根據使用的數據庫自行判斷采用identityhilosequence其中一種作為主鍵生成方式,靈活性很強。如果能支持identity則使用identity,如果支持sequence則使用sequence



          <id name="id" column="id">


          <generator class="native" />


          </id>


          例如MySQL使用identityOracle使用sequence


          注意:如果Hibernate自動選擇sequence或者hilo,則所有的表的主鍵都會從Hibernate默認的sequencehilo表中取。并且,有的數據庫對于默認情況主鍵生成測試的支持,效率并不是很高。


          使用sequencehilo時,可以加入參數,指定sequence名稱或hi值表名稱等,如


          <param name="sequence">hibernate_id</param>


          特點:根據數據庫自動選擇,項目中如果用到多個數據庫時,可以使用這種方式,使用時需要設置表的自增字段或建立序列,建立表等。


          8、uuid


          UUIDUniversally Unique
          Identifier
          ,是指在一臺機器上生成的數字,它保證對在同一時空中的所有機器都是唯一的。按照開放軟件基金會(OSF)制定的標準計算,用到了以太網卡地址、納秒級時間、芯片ID碼和許多可能的數字,標準的UUID格式為:


          xxxxxxxx-xxxx-xxxx-xxxxxx-xxxxxxxxxx
          (8-4-4-4-12)


          其中每個
          x
          0-9
          a-f 范圍內的一個十六進制的數字。



          <id name="id" column="id">


          <generator class="uuid" />


          </id>


          Hibernate在保存對象時,生成一個UUID字符串作為主鍵,保證了唯一性,但其并無任何業務邏輯意義,只能作為主鍵,唯一缺點長度較大,32位(HibernateUUID中間的“-”刪除了)的字符串,占用存儲空間大,但是有兩個很重要的優點,Hibernate在維護主鍵時,不用去數據庫查詢,從而提高效率,而且它是跨數據庫的,以后切換數據庫極其方便。


          特點:uuid長度大,占用空間大,跨數據庫,不用訪問數據庫就生成主鍵值,所以效率高且能保證唯一性,移植非常方便,推薦使用。


          9、guid


          GUIDGlobally Unique
          Identifier
          全球唯一標識符,也稱作
          UUID,是一個128位長的數字,用16進制表示。算法的核心思想是結合機器的網卡、當地時間、一個隨即數來生成GUID。從理論上講,如果一臺機器每秒產生10000000GUID,則可以保證(概率意義上)3240年不重復。



          <id name="id" column="id">


          <generator class="guid" />


          </id>


          Hibernate在維護主鍵時,先查詢數據庫,獲得一個uuid字符串,該字符串就是主鍵值,該值唯一,缺點長度較大,支持數據庫有限,優點同uuid,跨數據庫,但是仍然需要訪問數據庫。


          注意:長度因數據庫不同而不同


          MySQL中使用select uuid()語句獲得的為36位(包含標準格式的“-”)


          Oracle中,使用select rawtohex(sys_guid()) from
          dual
          語句獲得的為32位(不包含“-”) 特點:需要數據庫支持查詢uuid,生成時需要查詢數據庫,效率沒有uuid高,推薦使用uuid


          10、foreign


          使用另外一個相關聯的對象的主鍵作為該對象主鍵。主要用于一對一關系中。



          <id name="id" column="id">


          <generator class="foreign">



          <param name="property">user</param>


          </generator>


          </id>



          <one-to-one
          name="user" class="domain.User" constrained="true" />


          該例使用domain.User的主鍵作為本類映射的主鍵。


          特點:很少使用,大多用在一對一關系中。


          11、select


          使用觸發器生成主鍵,主要用于早期的數據庫主鍵生成機制,能用到的地方非常少。


          12、其他注釋方式配置


          注釋方式與配置文件底層實現方式相同,只是配置的方式換成了注釋方式


          自動增長,適用于支持自增字段的數據庫



          @Id


          @GeneratedValue(strategy = GenerationType.IDENTITY)


          根據底層數據庫自動選擇方式,需要底層數據庫的設置


          MySQL,會使用自增字段,需要將主鍵設置成auto_increment



          @Id


          @GeneratedValue(strategy = GenerationType.AUTO)


          使用表存儲生成的主鍵,可以跨數據庫。


          每次需要主鍵值時,查詢名為"hibernate_table"的表,查找主鍵列"gen_pk"值為"2"記錄,得到這條記錄的"gen_val"值,根據這個值,和allocationSize的值生成主鍵值。



          @Id


          @GeneratedValue(strategy = GenerationType.TABLE, generator = "ud")


          @TableGenerator(name = "ud",



          table =
          "hibernate_table",



          pkColumnName =
          "gen_pk",



          pkColumnValue =
          "2",



          valueColumnName =
          "gen_val",



          initialValue = 2,



          allocationSize = 5)



          使用序列存儲主鍵值



          @Id


          @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ud")


          @SequenceGenerator(name = "ud",



          sequenceName =
          "hibernate_seq",



          allocationSize = 1,



          initialValue = 2)


          13、小結


          1、為了保證對象標識符的唯一性與不可變性,應該讓Hibernate來為主鍵賦值,而不是程序。


          2、正常使用Hibernate維護主鍵,最好將主鍵的setter方法設置成private,從而避免人為或程序修改主鍵,而使用assigned方式,就不能用private,否則無法給主鍵賦值。


          2Hibernate中唯一一種最簡單通用的主鍵生成器就是uuid。雖然是個32位難讀的長字符串,但是它沒有跨數據庫的問題,將來切換數據庫極其簡單方便,推薦使用!


          3、自動增長字段類型與序列
















































          數據庫


          自動增長字段


          序列


          MySQL




          Oracle




          DB2




          MS SQL Server




          Sybase




          HypersonicSQL




          PostgreSQL




          SAP DB




          HSQLDB




          Infomix




          4、關于hilo機制注意:


          hilo算法生成的標志只能在一個數據庫中保證唯一。


          當用戶為Hibernate自行提供連接,或者Hibernate通過JTA,從應用服務器的數據源獲取數據庫連接時,無法使用hilo,因為這不能保證hilo單獨在新的數據庫連接的事務中訪問hi值表,這種情況,如果數據庫支持序列,可以使用seqhilo


          5、使用identitynativeGenerationType.AUTO等方式生成主鍵時,只要用到自增字段,數據庫表的字段必須設置成自動增加的,否則出錯。


          6、還有一些方法未列出來,例如uuid.hexsequence-identity等,這些方法不是很常用,且已被其他方法代替,如uuid.hex,官方文檔里建議不使用,而直接使用uuid方法。


          7Hibernate的各版本主鍵生成策略配置有略微差別,但實現基本相同。如,有的版本默認sequence不指定序列名,則使用名為hibernate_sequence的序列,有的版本則必須指定序列名。


          8、還可以自定義主鍵生成策略,這里暫時不討論,只討論官方自帶生成策略。

          posted on 2012-04-22 16:06 hantai 閱讀(73) 評論(0)  編輯  收藏


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


          網站導航:
           
          主站蜘蛛池模板: 台北县| 铜川市| 成安县| 明光市| 南宫市| 湘潭县| 吉木萨尔县| 乐亭县| 清流县| 松滋市| 承德县| 临桂县| 澄城县| 桑日县| 惠水县| 内江市| 荥经县| 华蓥市| 永安市| 武川县| 阿克苏市| 和静县| 永州市| 五原县| 志丹县| 石狮市| 卓尼县| 漳州市| 麟游县| 大庆市| 都兰县| 当涂县| 昆明市| 漾濞| 博罗县| 久治县| 兴安盟| 通州市| 高安市| 新田县| 夏邑县|