生成短的UUID(C#+JAVA+数据库)

方案一:

本算法首先随机生成一个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生成区分大小写的22位短UUID

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('=');
-- MySQL8.0+才支持下面的函数生成区分大小写的22位短UUID

DELIMITER //
CREATE FUNCTION generate_short_uuid(uuid_str CHAR(36))
RETURNS CHAR(11)
READS SQL DATA
DETERMINISTIC
BEGIN
    DECLARE uuid_bytes BINARY(16);
    DECLARE base64_str TEXT;
    DECLARE short_uuid CHAR(11);

    -- Convert UUID string to binary
    SET uuid_bytes = UNHEX(REPLACE(uuid_str, '-', ''));

    -- Encode to Base64
    SET base64_str = TO_BASE64(uuid_bytes);

    -- Remove trailing '=='
    SET short_uuid = LEFT(base64_str, LENGTH(base64_str) - 2);

    RETURN short_uuid;
END//
DELIMITER ;
-- PgSQL8.3+ 可以支持下面的函数生成区分大小写的22位短UUID

CREATE OR REPLACE FUNCTION generate_short_uuid(uuid_str TEXT)
RETURNS CHAR(11) AS $$
DECLARE
    uuid_bytes BYTEA;
    base64_str TEXT;
    short_uuid CHAR(11);
BEGIN
    -- Convert UUID string to bytea
    uuid_bytes := decode(replace(uuid_str, '-', ''), 'hex');

    -- Encode to Base64
    base64_str := encode(uuid_bytes, 'base64');

    -- Remove trailing '=='
    short_uuid := left(base64_str, length(base64_str) - 2);

    RETURN short_uuid;
END;
$$ LANGUAGE plpgsql;
-- MSSQL2016+ 支持下面的函数生成区分大小写的22位短UUID

CREATE FUNCTION dbo.generate_short_uuid (@uuid_str CHAR(36))
RETURNS CHAR(11)
AS
BEGIN
    DECLARE @uuid_bytes VARBINARY(16);
    DECLARE @base64_str NVARCHAR(MAX);
    DECLARE @short_uuid CHAR(11);

    -- Convert UUID string to binary
    SET @uuid_bytes = CONVERT(VARBINARY(16), REPLACE(@uuid_str, '-', ''), 2);

    -- Encode to Base64
    SET @base64_str = CAST('' AS XML).value('xs:base64Binary(sql:column("@uuid_bytes"))', 'NVARCHAR(MAX)');

    -- Remove trailing '=='
    SET @short_uuid = LEFT(@base64_str, LEN(@base64_str) - 2);

    RETURN @short_uuid;
END;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值