本文來自http://my.oschina.net/noahxiao/blog/132277,我的儲藏使用java
在採用Hibernate作對象映射時,我一直都採用UUID來作主鍵。因爲Hibernate的UUID須要佔用32位的字符,因此通常都會讓人感受響效率且增長存儲佔用。apache
我在查看公司項目時發現了一種比較好的生成UUID的方法,就是將UUID數據進行Base64化。以爲比較有意義拿出來給你們分享。安全
Java中的UUID採用RFC 4122的標準,按標準數據按16進制進行表示(36個字符)。如:f81d4fae-7dec-11d0-a765-00a0c91e6bf6session
Hibernate默認產生的UUID與RFC 4122標準相比,去掉了沒有用的"-"分割符號,因此更短(32個字符)。如:f81d4fae7dec11d0a76500a0c91e6bf6dom
因爲Base64編碼使用的字符包括大小寫字母各26個,加上10個數字,和加號「+」,斜槓「/」,一共64個字符。因此纔有Base64名字的由來。Base64至關於使用64進制來表示數據,相同長度位數的狀況下要比16進製表示更多的內容。ide
因爲UUID標準數據總共是128-bit,因此咱們就能夠對這個128-bit從新進行Base64編碼。工具
128-bit的UUID在Java中表示爲兩個long型數據,能夠採用java.util.UUID中的getLeastSignificantBits與getMostSignificantBits分別得到兩個long(64-bit)。再經過Base64轉碼就能夠得到咱們所要的UUID。ui
UuidUtils工具類編碼
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_JUxSnyAspa
比Hibernate32個字符還短了10個字符。
在處理Base64時,這裏用到了apache的commons-codec編碼工具包,由於它提供了簡單的編碼轉換方法。並且還有encodeBase64URLSafeString方法,採用URL安全方式生成Base64編碼。默認的Base64含有+與/字符,若是這種編碼出如今URL中將形成混亂。URL安全方式採用了-替換+,_替換/,並去掉告終束==。很是適合Web直接傳參。
因爲Hibernate4對SessionImplementor的包作出了調整因此ID生成器的實現稍有不一樣(import)。
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(); } }
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(); } }
@Id @GenericGenerator(name = "uuidGenerator", strategy = "org.noahx.uuid.Base64UuidGenerator") @GeneratedValue(generator = "uuidGenerator") @Column("UUID", length = 22) private String uuid;