高并发业务号、订单号、流水号等唯一编号生成策略之——Oracle触发器

前言

如何解决高并发环境下系统流水号保证唯一性问题?时间戳+订单类型+随机数?加锁?集群环境又如何解决?

如常见系统中的业务号、订单系统中的订单号,物流系统的运单号等都要确保全局唯一性。除此之外,一个设计良好的流水号生成规则还应该包含如下特性:

  • 全局唯一性:在整个系统中唯一,可以通过单号直接定位到具体数据

  • 可读性:能够直接从单号上获取一些基本信息

  • 可扩展性:支持海量id,当应用扩展时可以做到平滑升级

  • 递增趋势:需要根据业务或时间呈递增趋势

  • 不可推测性:使用户无法猜测下一个或上一个订单号是什么

  • 高性能:流水号生成速度要快,不能成为业务瓶颈

  • 高可用:流水号生成必须要稳定,不能影响业务发展

背景

项目需求指出工单管理模块工单编号要求由6位县级行政区划代码+4位年份代码+6位顺序号组成,后十位数递增,并保证系统编号唯一。

编号规则:由6位县级行政区划代码+4位年份代码+6位顺序号组成。

例如:3305242022000001

假设表结构如下

CREATE TABLE TEST_TABLE (
  YWH NVARCHAR2(16) NOT NULL,
  XZQHDM NVARCHAR2(14),
  XZQHMC NVARCHAR2(100),
  BLZT CHAR(1 BYTE)
);

COMMENT ON COLUMN TEST_TABLE.YWH IS '业务号';
COMMENT ON COLUMN TEST_TABLE.XZQHDM IS '行政区划代码';
COMMENT ON COLUMN TEST_TABLE.XZQHMC IS '行政区划名称';
COMMENT ON COLUMN TEST_TABLE.BLZTIS '办理状态';

关注点:保证编号唯一,那么得解决并发情况。

方案

触发器:

触发器是指被隐含执行的存储过程(存储过程是单线程的),它可以使用PL/SQL进行开发,当发生特定事件(如修改表、创建对象、登录到数据库)时,是由一个事件来触发运行,当事件触发会自动地隐式运行。它的组成可以分为三个部分:

1、触发器执行的条件,即触发器被触发的事件

2、执行触发器的时间,发生事件之前(before)或发生事件之后(after)

3、触发器要做的事情,就是触发器被触发以后具体想执行的任务(PL/SQL语句块)。

下面我们根据需求,当新增一个工单,在执行insert语句之前,我们先设计好触发器TRIG_TEST_TABLE ,并在表TEST_TABLE关联触发器(配置:行级触发、执行插入之前),触发器设计如下所示:

CREATE OR REPLACE TRIGGER TRIG_TEST_TABLE 
  BEFORE INSERT ON TEST_TABLE FOR EACH ROW WHEN (new.ywh IS NULL) /*触发条件:当表执行insert操作并且ywh为null时触发*/
DECLARE /*定义变量*/
  lwxzqh NVARCHAR2(6); /*6位县级行政区划代码*/
  swnf NVARCHAR2(4); /*4位年份代码*/
  lwxxh NVARCHAR2(6); /*6位顺序号*/
BEGIN
  /*判断并行政区划代码是否为空、长度是否大于等于6位,是给默认值,否截取前6位*/
  IF :new.xzqhdm IS NOT NULL AND LENGTH(:new.xzqhdm)>=6 THEN
    lwxzqh:=SUBSTR(:new.xzqhdm,0,6);
  ELSE
    lwxzqh:='330524';
  END IF;
  /*按数据库日期生成4位年份代码*/
  swnf:=TO_CHAR(SYSDATE,'yyyy');
  /*默认6位顺序号为000001*/
  lwxxh:='000001';
  /*根据6位县级行政区划代码+4位年份代码,查询该表最大ywh加1并赋值给新的ywh*/
  SELECT MAX(ywh)+1 INTO:new.ywh FROM TEST_TABLE WHERE INSTR(ywh,lwxzqh||swnf)>0;
  /*判断新的ywh是否为空,为空说明此6位县级行政区划代码+4位年份代码当前并未生成ywh,这里给新的ywh赋值未默认的即可*/
  IF :new.ywh IS NULL THEN
    :new.ywh:=lwxzqh||swnf||lwxxh;
  END IF;
END;

测试:

INSERT INTO TEST_TABLE(XZQHDM, XZQHMC, BLZT) VALUES ('330524104202', '荒草圩村', '1');
INSERT INTO TEST_TABLE(XZQHDM, XZQHMC, BLZT) VALUES ('330524104204', '沙石村', '1');

 结果:

 到此使用Oracle触发器生成流水号的功能就完成了,以上方案仅供参考,若有不足之处请多多指点

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

招风的黑耳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值