如何原子性插入特定前缀对应的唯一序号客户编码记录?
并发场景下客户编码原子性插入解决方案
方案1:使用数据库原生序列(推荐)
多数现代数据库(SQL Server、PostgreSQL、Oracle等)都支持独立的序列生成器,能原生保证并发环境下的序号唯一性,彻底避免约束冲突。
以SQL Server为例,先为每个CodePrefix创建专属序列:
-- 为WIP前缀创建序列,初始值1,步长1 CREATE SEQUENCE Seq_CustomerCode_WIP START WITH 1 INCREMENT BY 1;
插入时直接调用序列获取下一个值:
INSERT INTO CustomerCodes (CustomerId, CodePrefix, Ordinal) VALUES (1, 'WIP', NEXT VALUE FOR Seq_CustomerCode_WIP);
如果需要适配多个前缀,可提前为所有可能的前缀创建序列,或用动态SQL生成序列调用语句。
方案2:用辅助计数器表+UPSERT实现锁机制
如果数据库不支持序列,可创建一个辅助表维护各前缀的当前最大序号,通过UPDATE的行级锁保证并发安全:
- 先创建辅助表:
CREATE TABLE CustomerCodeCounters ( CodePrefix VARCHAR(3) PRIMARY KEY, CurrentOrdinal INT DEFAULT 0 );
- 原子性插入逻辑(含事务):
BEGIN TRANSACTION; -- 更新对应前缀的计数器,行锁会阻塞其他并发事务 UPDATE CustomerCodeCounters SET CurrentOrdinal = CurrentOrdinal + 1 WHERE CodePrefix = 'WIP'; -- 若该前缀无记录,初始化计数器 IF @@ROWCOUNT = 0 BEGIN INSERT INTO CustomerCodeCounters (CodePrefix, CurrentOrdinal) VALUES ('WIP', 1); END -- 获取新序号 DECLARE @NewOrdinal INT; SELECT @NewOrdinal = CurrentOrdinal FROM CustomerCodeCounters WHERE CodePrefix = 'WIP'; -- 插入客户编码 INSERT INTO CustomerCodes (CustomerId, CodePrefix, Ordinal) VALUES (1, 'WIP', @NewOrdinal); COMMIT TRANSACTION;
方案3:添加锁定提示(轻量临时方案)
无需额外建表,在查询最大序号时添加UPDLOCK, HOLDLOCK提示,强制锁定目标记录范围,直到事务结束:
BEGIN TRANSACTION; DECLARE @NewOrdinal INT; SELECT @NewOrdinal = ISNULL(MAX(Ordinal), 0) + 1 FROM CustomerCodes WITH (UPDLOCK, HOLDLOCK) WHERE CodePrefix = 'WIP'; INSERT INTO CustomerCodes (CustomerId, CodePrefix, Ordinal) VALUES (1, 'WIP', @NewOrdinal); COMMIT TRANSACTION;
UPDLOCK为符合条件的记录添加更新锁,HOLDLOCK将锁的持有时间延长至事务提交,确保其他事务无法同时读取并生成重复序号。
内容的提问来源于stack exchange,提问作者Michael P
相关产品推荐
相关产品推荐

