方案一:
本算法首先随机生成一个32位字符的UUID;接着,由于UUID都为十六进制,所以将UUID分成8组,每4个为一组;然后,通过分别将他们进行模91操作,通过模运算的结果,去字典数组中索引得到相应的字符。
而字典数组,则是62+29个可打印字符,大小写字母、数字、不包括单双引号的符号,相比网上能找到62个字符的版本,进一步降低了重复概率。
经测试,62个字符的方案在我这里测试的时候,生成三百万条数据时出现了一个重复;目前我正在测试91个字符的方案,准备生成10个小目标的数据量,看看会不会发生重复。
网上都是JAVA版,这里按语法简单调整成C#的版本,代码贴出来供大家参考。
//***************************
//测试结果:
//62个字符时,一百多万的时候就已经有一个重复项了,不过直到1个小目标也没再出现第二个重复项;
//91个字符时,直到1个小目标的量,一直没有出现重复项。
//结论:短UUID在一定业务场景下可以用,但其重复的可能性依然存在,所以要给字段加聚集索引,且判断Insert是否失败,若失败则重新生成一个,理论上不可能失败3次。
//***************************
C#版:
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", // 6
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", // 13
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", // 13
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", // 13
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", // 13
"W", "X", "Y", "Z",
"!", "#", "$", "%", "&", "(", ")", "*", "+", ",", "-", ".", "/", // 13
":", ";", "<", "=", ">", "?", "@", "[", @"\", "]", "^", "_", "{", // 13
"|", "}", "~"}; // 3
/// <summary>
/// 生成8位的短UUID
/// </summary>
public string ShortUuid()
{
StringBuilder shortBuffer = new StringBuilder();
// 生成32位UUID
var uuidN = Guid.NewGuid().ToString("N");
for (int i = 0; i < 8; i++)
{
// 4个一组
string strSub = uuidN.Substring(i * 4, 4);
int x = Int32.Parse(strSub, System.Globalization.NumberStyles.HexNumber);
// 模91(62+29=91=0x5B),取chars[]对应的字符
string strTmp = chars[x % 0x5B]; // 风险点
shortBuffer.Append(strTmp);
}
return shortBuffer.ToString();
}
JAVA版:
// 62+29个字符
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z",
"!", "#", "$", "%", "&", "(", ")", "*", "+", ",", "-", ".", "/", // 13
":", ";", "<", "=", ">", "?", "@", "[", "\\", "]", "^", "_", "{", // 13
"|", "}", "~"}; // 3
public static String generateShortUuid() {
StringBuffer shortBuffer = new StringBuffer();
// 生成32位UUID
String uuid = UUID.randomUUID().toString().replace("-", "");
for (int i = 0; i < 8; i++) {
// 4个一组
String str = uuid.substring(i * 4, i * 4 + 4);
int x = Integer.parseInt(str, 16);
// 模91(62+29=91=0x5B),取chars[]对应的字符
shortBuffer.append(chars[x % 0x5B]);
}
return shortBuffer.toString();
}
// ************************** 可爱的分隔线 **************************
方案二:
上面的代码还是重复的可能性,还是这个靠谱绝对不重复,虽然最大长度达22位:
//JAVA
private String generateShortUuid(String uuidString)
{
//UUID uuid1 = UUID.randomUUID();
UUID uuid1 = UUID.fromString(uuidString);
ByteBuffer byteBuffer1 = ByteBuffer.wrap(new byte[16]);
byteBuffer1.putLong(uuid1.getMostSignificantBits());
byteBuffer1.putLong(uuid1.getLeastSignificantBits());
String base64String1 = Base64.getEncoder().encodeToString(byteBuffer1.array());
// 删除尾部的"=="
base64String1 = base64String1.substring(0, base64String1.length() - 2);
return base64String1;
}
// C#就只有一行
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=');