Base64壓縮UUID長度替換Hibernate原有UUID生成器

一、背景

在採用Hibernate作對象映射時,我一直都採用UUID來作主鍵。因爲Hibernate的UUID須要佔用32位的字符,因此通常都會讓人感受響效率且增長存儲佔用。java

我在查看公司項目時發現了一種比較好的生成UUID的方法,就是將UUID數據進行Base64化。以爲比較有意義拿出來給你們分享。apache

二、傳統UUID

a、java.util.UUID(RFC 4122 http://www.ietf.org/rfc/rfc4122.txt

Java中的UUID採用RFC 4122的標準,按標準數據按16進制進行表示(36個字符)。如:f81d4fae-7dec-11d0-a765-00a0c91e6bf6安全

b、Hibernate UUID

Hibernate默認產生的UUID與RFC 4122標準相比,去掉了沒有用的"-"分割符號,因此更短(32個字符)。如:f81d4fae7dec11d0a76500a0c91e6bf6session

三、Base64格式的UUID

因爲Base64編碼使用的字符包括大小寫字母各26個,加上10個數字,和加號「+」,斜槓「/」,一共64個字符。因此纔有Base64名字的由來。Base64至關於使用64進制來表示數據,相同長度位數的狀況下要比16進製表示更多的內容。dom

因爲UUID標準數據總共是128-bit,因此咱們就能夠對這個128-bit從新進行Base64編碼。ide

128-bit的UUID在Java中表示爲兩個long型數據,能夠採用java.util.UUID中的getLeastSignificantBits與getMostSignificantBits分別得到兩個long(64-bit)。再經過Base64轉碼就能夠得到咱們所要的UUID。工具

UuidUtils工具類ui

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package org.noahx.uuid;
 
import org.apache.commons.codec.binary.Base64;
 
import java.util.UUID;
 
public abstract class UuidUtils {
 
     public static String uuid() {
         UUID uuid = UUID.randomUUID();
         return uuid.toString();
     }
 
     public static String compressedUuid() {
         UUID uuid = UUID.randomUUID();
         return compressedUUID(uuid);
     }
 
     protected static String compressedUUID(UUID uuid) {
         byte [] byUuid = new byte [ 16 ];
         long least = uuid.getLeastSignificantBits();
         long most = uuid.getMostSignificantBits();
         long2bytes(most, byUuid, 0 );
         long2bytes(least, byUuid, 8 );
         String compressUUID = Base64.encodeBase64URLSafeString(byUuid);
         return compressUUID;
     }
 
     protected static void long2bytes( long value, byte [] bytes, int offset) {
         for ( int i = 7 ; i > - 1 ; i--) {
             bytes[offset++] = ( byte ) ((value >> 8 * i) & 0xFF );
         }
     }
 
     public static String compress(String uuidString) {
         UUID uuid = UUID.fromString(uuidString);
         return compressedUUID(uuid);
     }
 
     public static String uncompress(String compressedUuid) {
         if (compressedUuid.length() != 22 ) {
             throw new IllegalArgumentException( "Invalid uuid!" );
         }
         byte [] byUuid = Base64.decodeBase64(compressedUuid + "==" );
         long most = bytes2long(byUuid, 0 );
         long least = bytes2long(byUuid, 8 );
         UUID uuid = new UUID(most, least);
         return uuid.toString();
     }
 
     protected static long bytes2long( byte [] bytes, int offset) {
         long value = 0 ;
         for ( int i = 7 ; i > - 1 ; i--) {
             value |= ((( long ) bytes[offset++]) & 0xFF ) << 8 * i;
         }
         return value;
     }
}

經過調用UuidUtils.compressedUuid()方法就能夠得到個人須要的UUID字符串(22個字符,128-bit的Base64只須要22個字符)。如:BwcyZLfGTACTz9_JUxSnyA編碼

比Hibernate32個字符還短了10個字符。spa

在處理Base64時,這裏用到了apache的commons-codec編碼工具包,由於它提供了簡單的編碼轉換方法。並且還有encodeBase64URLSafeString方法,採用URL安全方式生成Base64編碼。默認的Base64含有+與/字符,若是這種編碼出如今URL中將形成混亂。URL安全方式採用了-替換+,_替換/,並去掉告終束==。很是適合Web直接傳參。

四、Hibernate的UUID生成器

因爲Hibernate4對SessionImplementor的包作出了調整因此ID生成器的實現稍有不一樣(import)。

a、Hibernate3

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.noahx.uuid;
 
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
 
import java.io.Serializable;
 
public class Base64UuidGenerator implements IdentifierGenerator {
 
     @Override
     public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
         return UuidUtils.compressedUuid();
     }
}

b、Hibernate4

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.noahx.uuid;
 
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
 
import java.io.Serializable;
 
public class Base64UuidGenerator implements IdentifierGenerator {
 
     @Override
     public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
         return UuidUtils.compressedUuid();
     }
 
}

五、映射中使用Base64的UUID

?
1
2
3
4
5
@Id
     @GenericGenerator (name = "uuidGenerator" , strategy = "org.noahx.uuid.Base64UuidGenerator" )
     @GeneratedValue (generator = "uuidGenerator" )
     @Column ( "UUID" , length = 22 )
     private String uuid;
相關文章
相關標籤/搜索