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項目,參考上述步驟配置運行即可(注意各個類的路徑)。