在Oracle中编写雪花算法升学雪花ID
目录
在Oracle中编写雪花算法升学雪花ID
雪花算法的定义不详细说了哈,直接给出代码!
--雪花配置
--DROP TABLE SNOWFLAKE_CONFIG;
CREATE TABLE SNOWFLAKE_CONFIG (
DATA_CENTER_ID NUMBER(5) NOT NULL,
WORKER_ID NUMBER(5) NOT NULL,
LAST_TIMESTAMP NUMBER(20) NOT NULL,
SEQUENCE NUMBER(12) DEFAULT 0 NOT NULL,
CONSTRAINT PK_SNOWFLAKE_CONFIG PRIMARY KEY (DATA_CENTER_ID, WORKER_ID)
);
COMMENT ON TABLE SNOWFLAKE_CONFIG IS '雪花配置';
COMMENT ON COLUMN SNOWFLAKE_CONFIG.DATA_CENTER_ID IS '数据中心ID';
COMMENT ON COLUMN SNOWFLAKE_CONFIG.WORKER_ID IS '工作序列';
COMMENT ON COLUMN SNOWFLAKE_CONFIG.LAST_TIMESTAMP IS '上次生成的时间戳';
COMMENT ON COLUMN SNOWFLAKE_CONFIG.SEQUENCE IS '存储序列号';
--给雪花配置初始化
insert into SNOWFLAKE_CONFIG VALUES(1,1, TO_NUMBER(TO_CHAR(SYSTIMESTAMP, 'YYYYMMDDHH24MISS')),1);
-- 自定义按位或函数
CREATE OR REPLACE FUNCTION CUSTOM_BITWISE_OR(A NUMBER, B NUMBER) RETURN NUMBER IS
RESULT NUMBER := 0;
BIT_A NUMBER;
BIT_B NUMBER;
I NUMBER;
BEGIN
-- 循环处理每一位
FOR I IN 0..63 LOOP
-- 提取 A 的第 I 位
BIT_A := MOD(FLOOR(A / POWER(2, I)), 2);
-- 提取 B 的第 I 位
BIT_B := MOD(FLOOR(B / POWER(2, I)), 2);
-- 如果至少有一个位为 1,则将该位对应的 2 的幂次方加到结果中
RESULT := RESULT +
CASE
WHEN (BIT_A + BIT_B) > 0 THEN 1
ELSE 0
END * POWER(2, I);
END LOOP;
RETURN RESULT;
END;
/
CREATE OR REPLACE PROCEDURE GENERATE_SNOWFLAKE_ID (
P_DATA_CENTER_ID IN NUMBER,
P_WORKER_ID IN NUMBER,
P_ID OUT NUMBER
) IS
V_LAST_TIMESTAMP NUMBER(20);
V_SEQUENCE NUMBER(12);
V_CURRENT_TIMESTAMP NUMBER(20);
V_TIMESTAMP_DIFF NUMBER(20);
BEGIN
-- 获取当前时间戳
V_CURRENT_TIMESTAMP := TO_NUMBER(TO_CHAR(SYSTIMESTAMP, 'YYYYMMDDHH24MISS'));
-- 锁定配置表
SELECT LAST_TIMESTAMP, SEQUENCE INTO V_LAST_TIMESTAMP, V_SEQUENCE
FROM SNOWFLAKE_CONFIG
WHERE DATA_CENTER_ID = P_DATA_CENTER_ID AND WORKER_ID = P_WORKER_ID
FOR UPDATE;
-- 时间戳比较
V_TIMESTAMP_DIFF := V_CURRENT_TIMESTAMP - V_LAST_TIMESTAMP;
IF V_TIMESTAMP_DIFF < 0 THEN
-- 时钟回拨处理
RAISE_APPLICATION_ERROR(-20001, 'CLOCK MOVED BACKWARDS');
ELSIF V_TIMESTAMP_DIFF = 0 THEN
-- 同一毫秒内,序列号自增
V_SEQUENCE := V_SEQUENCE + 1;
IF V_SEQUENCE > 4095 THEN
-- 序列号溢出,等待下一毫秒
LOOP
V_CURRENT_TIMESTAMP := EXTRACT(SECOND FROM SYSTIMESTAMP) * 1000;
V_TIMESTAMP_DIFF := V_CURRENT_TIMESTAMP - V_LAST_TIMESTAMP;
EXIT WHEN V_TIMESTAMP_DIFF > 0;
END LOOP;
V_SEQUENCE := 0;
END IF;
ELSE
-- 新的毫秒,重置序列号
V_SEQUENCE := 0;
END IF;
-- 更新配置表
UPDATE SNOWFLAKE_CONFIG
SET LAST_TIMESTAMP = V_CURRENT_TIMESTAMP, SEQUENCE = V_SEQUENCE
WHERE DATA_CENTER_ID = P_DATA_CENTER_ID AND WORKER_ID = P_WORKER_ID;
-- 生成 ID,使用自定义按位或函数
P_ID := CUSTOM_BITWISE_OR(
CUSTOM_BITWISE_OR(
CUSTOM_BITWISE_OR(
V_CURRENT_TIMESTAMP * POWER(2, 22),
P_DATA_CENTER_ID * POWER(2, 17)
),
P_WORKER_ID * POWER(2, 12)
),
V_SEQUENCE
);
END;
/
--调用存储过程,默认添加数据是雪花算法主键字段
-- 创建触发器 PERSON
CREATE OR REPLACE TRIGGER TRG_PERSON_SNOWFLAKE_ID
BEFORE INSERT ON PERSON
FOR EACH ROW
DECLARE
V_DATA_CENTER_ID NUMBER := 1; -- 数据中心 ID,可根据实际情况修改
V_WORKER_ID NUMBER := 1; -- 机器 ID,可根据实际情况修改
V_GENERATED_ID NUMBER;
BEGIN
-- 调用生成雪花 ID 的存储过程
GENERATE_SNOWFLAKE_ID(V_DATA_CENTER_ID, V_WORKER_ID, V_GENERATED_ID);
-- 将生成的 ID 赋值给插入行的 ID 列
:NEW.UUID := V_GENERATED_ID;
END;
/