在采用Hibernate作对象映射时,我一直都采用UUID来作主键。因为Hibernate的UUID须要占用32位的字符,因此通常都会让人感受响效率且增长存储占用。java
我在查看公司项目时发现了一种比较好的生成UUID的方法,就是将UUID数据进行Base64化。以为比较有意义拿出来给你们分享。apache
Java中的UUID采用RFC 4122的标准,按标准数据按16进制进行表示(36个字符)。如:f81d4fae-7dec-11d0-a765-00a0c91e6bf6安全
Hibernate默认产生的UUID与RFC 4122标准相比,去掉了没有用的"-"分割符号,因此更短(32个字符)。如:f81d4fae7dec11d0a76500a0c91e6bf6session
因为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直接传参。
因为Hibernate4对SessionImplementor的包作出了调整因此ID生成器的实现稍有不一样(import)。
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();
}
}
|
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();
}
}
|
1
2
3
4
5
|
@Id
@GenericGenerator
(name =
"uuidGenerator"
, strategy =
"org.noahx.uuid.Base64UuidGenerator"
)
@GeneratedValue
(generator =
"uuidGenerator"
)
@Column
(
"UUID"
, length =
22
)
private
String uuid;
|