uid-generator
uid-generator是百度开源的,基于雪花算法的一款唯一主键生成器(数据库表的主键要求全局唯一是相当重要的)。要求java8及以上版本。
官方介绍传送门:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
引入uid-generator
方式一:下载源码,本地引入
下载链接:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
下载后用maven导入,作为本地子项目引入主项目。
a、导入下载的项目
b、引入
<dependency>
<groupId>com.baidu.fsg</groupId>
<artifactId>uid-generator</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
方式二:互联网jar包引入(本文用的是此方式)
在maven仓库只找到了一个jar包。
<dependency>
<groupId>com.xfvape.uid</groupId>
<artifactId>uid-generator</artifactId>
<version>0.0.4-RELEASE</version>
</dependency>
配置
1、排除冲突的依赖
uid-generator中依赖了logback和mybatis。一般在项目搭建过程中,springboot中已经有了logback依赖,mybatis会作为单独的依赖引入。如果版本和uid-generator中的依赖不一致的话,就会导致冲突。为了防止出现这些问题,直接排除一劳永逸。(我这里用的是mybatis-plus,mybatis-plus官方要求的是,如果要使用mybatis-plus,就不能再单独引入mybatis了,所以我这里也是必须排除mybatis的)。排除jar包冲突问题参考另外一篇博文:https://blog.csdn.net/weixin_41381863/article/details/90042220
mybatis-plus和mybatis冲突的两个常见错误:
a、java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory
b、如下图
排除冲突的依赖如下:(使用本地项目引入的方式也需要排除以下依赖)
<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>
2、配置项目。配置步骤全部参考官方介绍:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
a、配置数据库的连接和mybatis-plus。参考:https://blog.csdn.net/weixin_41381863/article/details/106533572
b、在使用的数据库中创建表WORKER_NODE。(如果数据库版本较低,需要将TIMESTAMP类型换成datetime(3),一劳永逸的做法就是直接将TIMESTAMP换成datetime(3))
DROP TABLE IF EXISTS WORKER_NODE;
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;
c、将uid-generator核心对象装配为spring的bean。
uid-generator提供了两种生成器: DefaultUidGenerator、CachedUidGenerator。如对UID生成性能有要求, 请使用CachedUidGenerator。这里装配CachedUidGenerator,DefaultUidGenerator装配方式是一样的。
/**
* <p> 百度 Uid-Generator配置
* @author zepal
* */
@Configuration
public class UidGeneratorConfig {
@Bean("disposableWorkerIdAssigner")
public DisposableWorkerIdAssigner initDisposableWorkerIdAssigner() {
DisposableWorkerIdAssigner disposableWorkerIdAssigner = new DisposableWorkerIdAssigner();
return disposableWorkerIdAssigner;
}
@Bean("cachedUidGenerator")
public CachedUidGenerator initCachedUidGenerator(WorkerIdAssigner workerIdAssigner) {
CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();
cachedUidGenerator.setWorkerIdAssigner(workerIdAssigner);
// 属性参考链接 https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
// 以下为可选配置, 如未指定将采用默认值
// cachedUidGenerator.setTimeBits(28);
// cachedUidGenerator.setWorkerBits(22);
// cachedUidGenerator.setSeqBits(13);
// cachedUidGenerator.setEpochStr("2016-09-20");
cachedUidGenerator.setBoostPower(3);
cachedUidGenerator.setPaddingFactor(50);
cachedUidGenerator.setScheduleInterval(60L);
// // 拒绝策略: 当环已满, 无法继续填充时
// 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式)
// 拒绝策略: 当环已空, 无法继续获取时
// 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式)
return cachedUidGenerator;
}
}
说明:默认的属性,是百度对雪花算法的组成部分作出的调整(所有位加起来要为64,标识位始终为1,即非标识位一共为63)。
d、配置uid-generator依赖的mybatis配置
mapper文件:(注意:<mapper>中namespace属性要修改为引入的uid-generator,WorkerNodeDAO的绝对路径。<resultMap>的type属性和<insert>中的parameterType属性,要修改为引入的uid-generator,WorkerNodeEntity的绝对路径。不然mybatis怎么取映射路径)
<?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.xfvape.uid.worker.dao.WorkerNodeDAO">
<resultMap id="workerNodeRes"
type="com.xfvape.uid.worker.entity.WorkerNodeEntity">
<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.xfvape.uid.worker.entity.WorkerNodeEntity">
INSERT INTO WORKER_NODE
(HOST_NAME,
PORT,
TYPE,
LAUNCH_DATE,
MODIFIED,
CREATED)
VALUES (
#{hostName},
#{port},
#{type},
#{launchDate},
NOW(),
NOW())
</insert>
<select id="getWorkerNodeByHostPort" resultMap="workerNodeRes">
SELECT
ID,
HOST_NAME,
PORT,
TYPE,
LAUNCH_DATE,
MODIFIED,
CREATED
FROM
WORKER_NODE
WHERE
HOST_NAME = #{host} AND PORT = #{port}
</select>
</mapper>
@MapperScan的dao层接口扫描:
@MapperScan({"com.zgn.mp.dao", "com.xfvape.uid.worker.dao"})
说明:com.xfvape.uid.worker.dao是引入的uid-generator,WorkerNodeDAO所在的包。(前面的路径请忽略,是我本地demo的dao层接口路径)
application.properties配置:
mybatis-plus.mapper-locations=classpath:mapper/*.xml,classpath:mapper/uid/WORKER_NODE.xml
说明:classpath:mapper/uid/WORKER_NODE.xml是创建上述mapper文件所在的路径。(classpath:mapper/*.xml是我本地demo的mapper文件路径,忽略或改成自己项目中的路径)
测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class UidGeneratorTest {
@Autowired
private UidGenerator uidGenerator;
@Test
public void testSerialGenerate() {
long uid = uidGenerator.getUID();
System.out.println("生成的id = " + uid);
// 生成当前唯一id所用的元素
System.out.println(uidGenerator.parseUID(uid));
}
}
输出结果:
扩展
1、如果是通过本地项目引入,参考上述步骤配置进主项目即可(注意各个类的路径)。
2、如果是分布式项目,将官方开源的项目下载下来后,参考它的配置修改,放进tomcat运行。也可以重新创建springboot项目,参考上述步骤配置运行即可(注意各个类的路径)。