百度開源的分布式 ID 生成器,太強(qiáng)大了!
點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)
來源:https://lilinchao.com/archives/1226.html
一、UidGenerator是什么
UidGenerator是百度開源的一款分布式高性能的唯一ID生成器,是基于snowflake模型的一種ID生成器。
二、UidGenerator的優(yōu)勢
解決了時(shí)鐘回調(diào)的問題 使用ringbuffer,無鎖進(jìn)行id的生產(chǎn)與消費(fèi),速度非???/section> 適用于多線程,不會有單線程瓶頸
三、整合
本次通過SpringBoot2.x和MyBatis對百度UidGenerator進(jìn)行整合。
3.1 UidGenerator引入
一般使用兩種方式引入U(xiǎn)idGenerator:
1)從官網(wǎng)下載源碼作為自己項(xiàng)目的一個(gè)Module引入到項(xiàng)目中
官網(wǎng)地址:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
2)互聯(lián)網(wǎng)jar包引入(本文采取的是該種方式)
因?yàn)閁idGenerator自帶引入了mybatis,和自己項(xiàng)目有沖突的可以進(jìn)行排除
<dependency>
<groupId>com.xfvape.uid</groupId>
<artifactId>uid-generator</artifactId>
<version>0.0.4-RELEASE</version>
</dependency>
排除沖突依賴
uid-generator中依賴了logback和mybatis。一般在項(xiàng)目搭建過程中,springboot中已經(jīng)有了logback依賴,mybatis會作為單獨(dú)的依賴引入。如果版本和uid-generator中的依賴不一致的話,就會導(dǎo)致沖突。
Spring Boot 基礎(chǔ)就不介紹了,新手請看這個(gè)學(xué)習(xí)教程和示例倉庫:https://github.com/javastacks/spring-boot-best-practice
<dependency>
<groupId>com.xfvape.uid</groupId>
<artifactId>uid-generator</artifactId>
<version>0.0.4-RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
在 MySQL數(shù)據(jù)庫中建一個(gè)名為 WORKER_NODE的數(shù)據(jù)表,其 sql如下:
CREATE TABLE WORKER_NODE
(
ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
PORT VARCHAR(64) NOT NULL COMMENT 'port',
TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
CREATED TIMESTAMP NOT NULL COMMENT 'created time',
PRIMARY KEY(ID)
)
COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;
建表時(shí)可能會報(bào)錯(cuò),原因是該建表語句定義了兩個(gè)TIMESTAMP字段,因?yàn)閙ysql 低版本控制比較嚴(yán)格。MySQL 開發(fā)的 36 條軍規(guī)建議看看。
解決辦法:
方式一:
直接把TIMESTAMP改成DATETIME 即可
方式二:
建表前先設(shè)置sql_mode:
set sql_mode="NO_ENGINE_SUBSTITUTION";
3.3 將uid-generator核心對象裝配為spring的bean
uid-generator提供了兩種生成器: DefaultUidGenerator、CachedUidGenerator。如對UID生成性能有要求, 請使用CachedUidGenerator。
@Configuration
public class WorkerNodeConfig {
@Bean("disposableWorkerIdAssigner")
public DisposableWorkerIdAssigner disposableWorkerIdAssigner(){
DisposableWorkerIdAssigner disposableWorkerIdAssigner = new DisposableWorkerIdAssigner();
return disposableWorkerIdAssigner;
}
@Bean("cachedUidGenerator")
public UidGenerator uidGenerator(DisposableWorkerIdAssigner disposableWorkerIdAssigner){
CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);
return cachedUidGenerator;
}
}
直接創(chuàng)建WorkerNodeConfig類,復(fù)制以上代碼。
3.4 重寫WorkerIdAssigner接口
public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
@Resource
private WorkerNodeMapper workerNodeMapper;
@Override
@Transactional
public long assignWorkerId() {
WorkerNode workerNode = buildWorkerNode();
workerNodeMapper.addWorkerNode(workerNode);
return workerNode.getId();
}
private WorkerNode buildWorkerNode() {
WorkerNode workNode = new WorkerNode();
if (DockerUtils.isDocker()) {
workNode.setType(WorkerNodeType.CONTAINER.value());
workNode.setHostName(DockerUtils.getDockerHost());
workNode.setPort(DockerUtils.getDockerPort());
workNode.setLaunchDate(new Date());
} else {
workNode.setType(WorkerNodeType.ACTUAL.value());
workNode.setHostName(NetUtils.getLocalAddress());
workNode.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(100000));
workNode.setLaunchDate(new Date());
}
return workNode;
}
}
創(chuàng)建一個(gè)DisposableWorkerIdAssigner類直接復(fù)制以上代碼。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.uidgenerator.mapper.WorkerNodeMapper">
<resultMap id="BaseResultMap"
type="com.uidgenerator.entity.WorkerNode">
<id column="ID" jdbcType="BIGINT" property="id" />
<result column="HOST_NAME" jdbcType="VARCHAR" property="hostName" />
<result column="PORT" jdbcType="VARCHAR" property="port" />
<result column="TYPE" jdbcType="INTEGER" property="type" />
<result column="LAUNCH_DATE" jdbcType="DATE" property="launchDate" />
<result column="MODIFIED" jdbcType="TIMESTAMP" property="modified" />
<result column="CREATED" jdbcType="TIMESTAMP" property="created" />
</resultMap>
<insert id="addWorkerNode" useGeneratedKeys="true" keyProperty="id"
parameterType="com.uidgenerator.entity.WorkerNode">
INSERT INTO WORKER_NODE
(HOST_NAME,
PORT,
TYPE,
LAUNCH_DATE,
MODIFIED,
CREATED)
VALUES (
#{hostName},
#{port},
#{type},
#{launchDate},
NOW(),
NOW())
</insert>
<select id="getWorkerNodeByHostPort" resultMap="BaseResultMap ">
SELECT
ID,
HOST_NAME,
PORT,
TYPE,
LAUNCH_DATE,
MODIFIED,
CREATED
FROM
WORKER_NODE
WHERE
HOST_NAME = #{host} AND PORT = #{port}
</select>
</mapper>
注意修改resultMap中的type和insert中的keyProperty為自身項(xiàng)目的實(shí)體類地址。
在application.yml文件中增加如下配置
mybatis:
mapper-locations: classpath:mybatis/*.xml
3.6實(shí)體類
使用插件生成的實(shí)體類
3.7創(chuàng)建Mapper
@Mapper
public interface WorkerNodeMapper {
int addWorkerNode(WorkerNode workerNodeEntity);
WorkerNode getWorkerNodeByHostPort(@Param("host") String host, @Param("port") String port);
}
3.8 Service
IWorkerNodeService接口
public interface IWorkerNodeService {
public long genUid();
}
WorkerNodeServiceImpl實(shí)現(xiàn)類
@Service
public class WorkerNodeServiceImpl implements IWorkerNodeService {
@Resource
private UidGenerator uidGenerator;
@Override
public long genUid() {
Long uu_id = UidGeneratorComponent.uu_id;
return uidGenerator.getUID();
}
}
@RestController
public class WorkerNodeServiceController {
@Resource
private IWorkerNodeService workerNodeService;
/**
* 集成百度uid-generator生成id
* @return
*/
@GetMapping("/baidu/uid")
public long baiduUid(){
long uid = workerNodeService.genUid();
return uid;
}
}
http://127.0.0.1:8099/test/baidu/uid

項(xiàng)目目錄結(jié)構(gòu)

最后,關(guān)注公眾號Java技術(shù)棧,在后臺回復(fù):面試,可以獲取我整理的 Java 系列面試題和答案,非常齊全。






關(guān)注Java技術(shù)??锤喔韶?/strong>


