我们有带有标识列(OrderID)的订单表,但我们的订单号由 OrderType(2 个字符)、OrderYear(2 个字符)和 OrderID(6 个字符)组成,总共 10 个字符(即 XX12123456)。此计数器有局限性:我们可以将身份 999999 视为 OrderID 。下一个订单的 ID 由 7 个字符组成。显然我们不能重复订单 ID。
所以我们创建了一个预先填充了渐进式 OrderID 和 OrderYear 的表(例如,从 100000 到 999999,订单年从 12 到 16):这个存储过程开始一个具有 SERIALIZABLE 隔离级别的事务,取第一个未使用的订单 ID,将其更新为使用并提交事务。
作为我们的订单表,我担心执行订单 ID 计算存储过程或重复订单 ID 时出现死锁。
我将使用创建多个并发线程并尝试提取模拟生产负载的 orderid 的控制台应用程序对此进行测试。
疑点是:
- 是否存在另一种安全模拟标识列的方法?
- 可以考虑使用触发器吗?
- 可以考虑不同的隔离级别吗?
- 其他想法?:D
谢谢!
[编辑]
在谷歌搜索并阅读了一堆 MSDN 文档之后,我发现了许多示例,这些示例显示了如何管理错误和解除锁定以及直接从 SP 处理一种自动回复,如下所示:
创建过程 [dbo].[sp_Ordine_GetOrderID]
@AnnoOrdine AS NVARCHAR(2) = 空输出,@IdOrdine AS INT = 空输出
作为
设置无计数
声明 @retry 为 INT SET @retry = 2
设置事务隔离级别可序列化
WHILE (@retry > 0) BEGIN BEGIN TRY
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
结尾
这种方法减少了死锁(根本不存在),但有时我得到了 EMPTY 输出参数。使用 30 个当代线程进行测试(因此,30 个同时插入订单的客户进程)
这是一个带有查询持续时间的调试日志,以毫秒为单位:http: //nopaste.info/285f558758.html
足够强大的生产能力?