我们有一个带有标识列(OrderID)的Orders表,但我们的订单号由OrderType(2个字符),OrderYear(2个字符)和OrderID(6个字符)组成,总共10个字符(即XX12123456)。 此计数器有限制:我们可以作为OrderID到达身份999999。下一个订单将由7个字符组成ID。显然,我们不能重复订单ID。
因此我们创建了一个预先填充了OrderID和OrderYear的表(例如,从100000到999999,订单年从12到16):这个存储过程以SERIALIZABLE隔离级别开始交易,不使用第一个订单ID,将其更新为已使用并提交事务。
作为我们的订单表,我担心执行订单ID计算存储过程或重复订单时出现死锁。
我将使用一个创建多个并发线程的控制台应用程序来测试它,并尝试提取模拟生产负载的orderid。
怀疑是:
谢谢!
[编辑]
在谷歌搜索并阅读了大量MSDN文档之后,我发现了许多示例,展示了如何直接从SP管理错误和处理错误以及接受某种类型的自动回复,如下所示:
CREATE PROCEDURE [dbo]。[sp_Ordine_GetOrderID]
@AnnoOrdine AS NVARCHAR(2)= NULL OUTPUT, @IdOrdine AS INT = NULL OUTPUT
AS
设置NOCOUNT
DECLARE @retry AS INT SET @retry = 2
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
WHILE(@retry> 0) 开始 开始尝试
BEGIN TRANSACTION OrderID
SELECT TOP 1 @AnnoOrdine = AnnoOrdine, @IdOrdine = IdOrdine
FROM ORDINI_PROGRESSIVI --WITH (ROWLOCK)
WHERE Attivo = 1
--ORDER BY AnnoOrdine ASC, IDOrdine ASC
UPDATE ORDINI_PROGRESSIVI WITH (UPDLOCK)
SET Attivo = 0
WHERE AnnoOrdine = @AnnoOrdine AND IdOrdine = @IdOrdine
IF ISNULL(@IdOrdine, '') = '' OR ISNULL(@AnnoOrdine,'') = ''
BEGIN
RAISERROR('Deadlock', 1, 1205)
END
SET @retry = 0
COMMIT TRANSACTION OrderID
SELECT @AnnoOrdine AS AnnoOrdine, @IdOrdine AS IdOrdine
END TRY
BEGIN CATCH
IF (ERROR_NUMBER() = 1205)
SET @retry = @retry - 1;
ELSE
SET @retry = -1;
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION;
END CATCH
END
这种方法减少了死锁(根本不存在),但有时候我得到了EMPTY输出参数。 使用30个当代线程进行测试(因此,30个客户流程在同一时刻插入订单)
这是一个带有查询持续时间的调试日志,以毫秒为单位:http://nopaste.info/285f558758.html
足够强大的生产?
答案 0 :(得分:0)
如果您确实发现当前的解决方案正在创建问题,并且它可能不会产生问题,那么另一种方法是为要使用标识列和虚拟字段创建的每个id类型创建一个表< / p>
即:
ABtypeID (ABID int identity(1,1), dummy varchar(1))
然后,您可以在此表中插入记录,并使用内置函数来检索标识。
即
insert ABTypeID (dummy) values (null)
select Scope_Identity()
您可以根据需要从这些表中删除,并在年底截断它们以重置ID计数器。
您甚至可以将插件包装在回滚的事务中 - 标识值不受回滚的影响