UUID扩展存储更多数据

161 阅读3分钟

UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和随机数。

一.开发中使用UUID遇到的问题

目前代码中生成UUID的方式如下

public static String getUUID() {  
    return UUID.randomUUID().toString().replace("-", "");
}

随着业务的激增,当然不可避免的需要对数据库进行分表操作,目前业务使用uuid作为业务表的主键,将uuid当成参数发送到下游,下游异步执行完业务逻辑后,通过回调传递uuid到本服务进行一个数据的更新。目前遇到的问题是uuid下游回调到服务后,因为分表的缘故需要多次查询多个表进行判断当前uuid归属于那个表,然后进行一个业务状态的更新,因为业务数据量较多,并发较高,且一请求需要查询多个表判断,导致对数据库CPU负载较高。所以可简化在uuid中加入分表信息,用以解析后直接入库,无需通过查询数据库表判断该条数据归属。

二.解决方案

将分表的编号拼接入主键uuid中,同时不能改变uuid的32长度,要确保重新生成的uuid唯一。uuid长度为128bit,也就是32个16进制组成,1个16进制数占4bit。针对此特性,可添加占位符8个16进制凑成40个16进制,长度为160bit。一个32进制数占5bit,32个32进制数正好等于160bit。所以可采用进制转换用0占位的方式生成32长度的32进制字符串。 此处分表为1到50.

import static org.apache.commons.lang3.StringUtils.leftPad;

/**
 * @author 专修虚拟机
 *
 * 16进制与32进制转换
 */
public class HexUtil {
    //占位符,按需设置
    private static String PLACEHOLDER = "000000";

    /**
     * 传入32位uuid和参数本文param为0到50
     * @param str
     * @param param
     * @return
     */
    public static String convertHexTo32(String str, String param) {
        if (str == null) {
            throw new NumberFormatException("null");
        }
        str = str + PLACEHOLDER + String.format("%s", leftPad(param, 0b10, (char) 0b110000));
        return hexTo32By40Character(str);
    }

    /**
     * 拼接的40个16进制字符串转换为32个32进制字符串
     * @param str
     * @return
     */
    public static String hexTo32By40Character(String str) {
        int len = str.length();
        if (len != 0b101000) {
            throw new NumberFormatException(String.format("string length is not equal to 40,length:%s ", len));
        }
        String hex32 = "";
        for (int i = 0; i < len; i += 0b101) {
            String sub = str.substring(i, i + 0b101);
            hex32 = hex32 + String.format("%s", leftPad(hexTo32(sub), 0b100, (char) 0b110000));
        }
        return hex32;
    }

    /**
     * 16进制转32进制
     * @param hex
     * @return
     */
    public static String hexTo32(String hex) {
        int result = 0;
        for (int i = 0; i < hex.length(); i++) {
            result = (result << 0b100) | Character.digit(hex.charAt(i), 0b10000);
        }
        return Integer.toString(result, 0b100000);
    }

    /**
     * 拆分获取拼接的分表编号
     * @param hex32
     * @return
     */
    public static int splitParam(String hex32) {
        String lastFourDigits = hex32.substring(0b11100);
        String hex16 = Integer.toHexString(Integer.parseInt(lastFourDigits, 0b100000));
        return Integer.parseInt(hex16);
    }
    
}