能,sequence与存储过程可搭配生成流水号,但sequence不保证事务一致性与绝对连续性,适用于日志id等非强一致场景;强一致需求应改用update+output等原子操作。

SQL Server里SEQUENCE和存储过程搭配能生成流水号吗
能,但得清楚SEQUECE不是为高并发流水号场景设计的。它本身不锁表、不事务绑定,NEXT VALUE FOR 每次调用就递增,哪怕后续事务回滚也不会倒退——这在金融类严格连续、不可跳号的业务里是硬伤。
如果你的需求只是“全局唯一+大致递增+不重复”,比如日志ID、内部单据号,SEQUENCE配合存储过程完全够用;如果要求“事务内强一致+回滚后不占号+按天/按业务分段”,就得绕开它,改用带UPDATE + OUTPUT的原子更新或临时表缓冲。
怎么写一个用SEQUENCE的流水号生成存储过程
核心是把NEXT VALUE FOR封装进CREATE PROCEDURE,并处理好默认值、前缀拼接、位数补零这些实际要面对的细节:
CREATE SEQUENCE dbo.seq_order_no
START WITH 1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
CACHE 10;
对应存储过程示例:
CREATE PROCEDURE dbo.usp_GetNextOrderNo
@Prefix NVARCHAR(10) = N'ORD',
@Length INT = 8,
@NextNo NVARCHAR(20) OUTPUT
AS
BEGIN
DECLARE @RawNum BIGINT = NEXT VALUE FOR dbo.seq_order_no;
SET @NextNo = @Prefix + RIGHT('00000000' + CAST(@RawNum AS NVARCHAR(20)), @Length);
END;
-
@Prefix和@Length是常见定制点,别写死在序列定义里 - 用
RIGHT('00000000' + ...)补零比FORMAT()兼容性更好(SQL Server 2012+都支持) - 别在存储过程中加
TRY...CATCH捕获SEQUENCE异常——它几乎不会失败,除非序列被删或权限不足
为什么直接SELECT NEXT VALUE FOR在应用层调用不推荐
因为应用代码里裸调NEXT VALUE FOR会暴露数据库细节,且难以统一控制格式、前缀、缓存策略。更关键的是:
- 每次调用都是独立语句,无法和主业务逻辑共用事务上下文
- 应用重试时可能重复取号(比如网络超时后重发请求,但数据库已成功返回)
- 不同服务或语言驱动对
NEXT VALUE FOR的参数化支持不一,容易出SQL注入或类型转换错
封装成存储过程后,所有规则收口,还能加日志、限流、甚至对接号段预分配逻辑。
SEQUENCE CACHE选项对流水号连续性的影响
CACHE 10 这类设置会让SQL Server一次从内存拿10个号,下次再取才去持久化更新current_value。这意味着:
- 服务器意外重启,未用完的缓存号直接丢失 → 出现“跳号”
- 高并发下CACHE越大,性能越好,但跳号幅度也越大
- 设
NO CACHE能保证绝对不跳,但每取一次都要写系统表,性能下降明显
生产环境建议CACHE 50~100,同时接受“跳号”是常态;真不能跳,就别用SEQUENCE,老实用带UPDLOCK, HOLDLOCK的UPDATE语句去抢号。
真正难的不是生成一个号,而是定义清楚“唯一流水号”在你业务里到底意味着什么:是全局唯一?是否允许跳?是否必须时间有序?是否要支持分库分表?这些决定了该不该用SEQUENCE,以及怎么兜底。










