本文来自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;