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);
}
}