携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
UUID(Universally Unique IDentifier) 是128位的全局唯一标识符,通常由32字节的字符串表示。它可以保证时间和空间的唯一性,也称为 GUID(Globally Unique IDentifier)。
它通过MAC地址、时间戳、命名空间、随机数、伪随机数来保证生成ID的唯一性。
不一定分布式唯一ID一定要使用雪花算法或者其变种来生成,UUID也有其应用场景。比如在数据量不大的多个数据库之间,例如100w数据以内,那么可以考虑使用UUID进行分布式ID生成。虽然会导致像传统关系型数据库MySQL的InnoDB引擎对于自增主键的分页查询失效,但是基于整体分布式ID维护的成本降低和UUID本身生成的高效率而言,其实是可以接受的。其实像Linux系统中磁盘序列号就是采用UUID生成的,这证明UUID本身并没有问题,但是得用在正确的场景。
而引入雪花算法,就不得不考虑时钟回拨问题;有采用NTP时钟同步的方案,还有采用ZK来维护唯一ID生成服务的,这些只会让系统变得更为复杂。因此,随着技术年龄变长以后,慢慢发现:其实任何技术的引入的都是有优缺点和代价的,因此才会有《人月神话》中没有"银弹"的说法,可惜的是很多技术人到了专家级别,去主动接触架构和系统设计时才意识到这一点。
每一个技术栈的使用过程中,都需要有自己的思考,跟风使用网络上的各种"踩一捧一"教程只会丧失自己对于技术的独立思考。
下面我们来介绍UIID的使用教程:
直接使用
package com.deepinsea.common.utils;
import java.util.UUID;
/**
* uuid唯一主键生成工具
* @author deepinsea
*/
public class UUIDTools {
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
System.out.println(uuid);//e7375574-d87f-43b0-93f5-5915d58d960f
String dxmbid = uuid.toString().replace("-", "");
System.out.println(dxmbid);//e7375574d87f43b093f55915d58d960f
System.out.println(dxmbid.length());//32
}
}
还有其他生成方式
public class IDGenerator {
private static long num=0;
/**
* 随机生成UUID
* @return
*/
public static synchronized String getUUID(){
UUID uuid=UUID.randomUUID();
String str = uuid.toString();
String uuidStr=str.replace("-", "");
return uuidStr;
}
/**
* 根据字符串生成固定UUID
* @param name
* @return
*/
public static synchronized String getUUID(String name){
UUID uuid=UUID.nameUUIDFromBytes(name.getBytes());
String str = uuid.toString();
String uuidStr=str.replace("-", "");
return uuidStr;
}
/**
* 根据日期生成长整型id
* @param args
*/
public static synchronized long getLongId(){
String date=DateUtil.getDate2FormatString(new Date(), "yyyyMMddHHmmssS");
System.out.println("原始id="+date);
if(num>=99) num=0l;
++num;
if(num<10) {
date=date+00+num;
}else{
date+=num;
}
return Long.valueOf(date);
}
}
生成方式
用户ID首先生成,订单ID的生成可依赖用户ID。
下面代码前六位是日期,后八位是随机数,用于生成用户ID。
public String getNewUserId() {
String ipAddress = "";
try {
//获取服务器IP地址
ipAddress = InetAddress.getLocalHost().getHostAddress();
} catch (Exception e) {
logger.error("getNewUserId=" + e.getMessage());
}
//获取UUID
String uuid = ipAddress + "$" + UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
//生成后缀
long suffix = Math.abs(uuid.hashCode() % 100000000);
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
String time = sdf.format(new Date(System.currentTimeMillis()));
//生成前缀
long prefix = Long.parseLong(time) * 100000000;
String userId = String.valueOf(prefix + suffix);
return userId;
}
接下来的订单ID就可以随意点了,可添加自定义前缀等。
public String buildOrderIdByUserId(String userId) {
SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");
String time = df.format(new Date());
Random random = new Random();
int randomNum = random.nextInt(999) % 900 + 100;
StringBuilder sb = new StringBuilder("ZMM");
return sb.append(time).append(userId).append(randomNum).toString();
}
如果还有相应的月份分表,之后就可以根据用户ID得到该用户所在月表,根据该订单得到该订单所在月表,直接截取相应ID的固定位置即可
比如:
public String getMonthByOrderId(String orderId) {
return "20" + orderId.substring(3, 7);
}
时间字符串可以使用JDK8新增的线程安全的时间格式化类来生成:
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String dateStr = dateTimeFormatter.format(localDateTime);
System.out.println(dateStr);
下面是实际项目中使用到的代码:
/**
* 根据指定前缀生成ID
*/
public static String generateId(String preStr){
if (StringUtils.isEmpty(preStr)){
logger.error("buildId preStr is error, preStr = " + preStr);
return null;
}
//获取UUID
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
//生成后缀
long suffix = Math.abs(uuid.hashCode() % 100000000);
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
String time = sdf.format(new Date(System.currentTimeMillis()));
//生成前缀
long prefix = Long.parseLong(time) * 100000000;
String userId = preStr + String.valueOf(prefix + suffix);
return userId;
}
欢迎关注白羊🐏,感谢观看ヾ(◍°∇°◍)ノ゙