Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 2008 标识列的替代项_Sql Server 2008_Identity Column - Fatal编程技术网

Sql server 2008 标识列的替代项

Sql server 2008 标识列的替代项,sql-server-2008,identity-column,Sql Server 2008,Identity Column,我们有一个带有标识列(OrderID)的Orders表,但我们的订单号由OrderType(2个字符)、OrderYear(2个字符)和OrderID(6个字符)组成,总共10个字符(即XX12123456)。 此计数器有限制:我们可以将标识999999作为OrderID。下一个订单的ID由7个字符组成。显然,我们不能保存重复的订单ID 因此,我们创建了一个以渐进式OrderID和OrderYear(例如,从100000到9999999,订单年从12到16)为前缀的表:此存储过程以可序列化隔离级

我们有一个带有标识列(OrderID)的Orders表,但我们的订单号由OrderType(2个字符)、OrderYear(2个字符)和OrderID(6个字符)组成,总共10个字符(即XX12123456)。 此计数器有限制:我们可以将标识999999作为OrderID。下一个订单的ID由7个字符组成。显然,我们不能保存重复的订单ID

因此,我们创建了一个以渐进式OrderID和OrderYear(例如,从100000到9999999,订单年从12到16)为前缀的表:此存储过程以可序列化隔离级别开始事务处理,获取未使用的第一个订单id,按使用情况更新并提交事务

作为Orders表,我担心在执行OrderID计算存储过程或重复的OrderID时会出现死锁

我将使用一个控制台应用程序来测试这一点,该应用程序创建多个并发线程,并尝试提取模拟生产负载的OrderID

疑问是:

  • 是否存在另一种安全模拟标识列的方法
  • 可以考虑使用触发器吗? 可以考虑不同的隔离级别吗?
  • 其他想法D
谢谢

[编辑]

在谷歌搜索和阅读了大量MSDN文档后,我发现了许多示例,展示了如何管理错误和解除锁定,以及如何直接从SP获得自动回复,如下所示:

创建过程[dbo]。[sp_Ordine_GetOrderID]

@AnnoOrdine作为NVARCHAR(2)=空输出, @IdOrdine作为INT=NULL输出

作为

不计较

将@retry声明为INT 设置@retry=2

将事务隔离级别设置为可序列化

而(@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
begintransactionorderid
选择顶部1@AnnoOrdine=AnnoOrdine,@IdOrdine=IdOrdine
来自ORDINI_PROGRESSIVI——与(ROWLOCK)
其中,Attivo=1
--安诺丁ASC订购,伊诺丁ASC订购
使用(UPDLOCK)更新ORDINI_PROGRESSIVI
设置为0
其中AnnoOrdine=@AnnoOrdine和IdOrdine=@IdOrdine
如果ISNULL(@IdOrdine,“)=”或ISNULL(@AnnoOrdine,“)=”
开始
RAISERROR('死锁',11205)
结束
设置@retry=0
提交事务医嘱ID
选择@AnnoOrdine作为AnnoOrdine,选择@IdOrdine作为IdOrdine
结束尝试
开始捕捉
如果(错误号()=1205)
设置@retry=@retry-1;
其他的
设置@retry=-1;
如果XACT_STATE()0
回滚事务;
端接
结束

这种方法减少了死锁(根本不存在),但有时输出参数为空。 使用30个当代线程进行测试(因此,30个客户进程同时插入订单)

这里是一个带有查询持续时间的调试日志,以毫秒为单位:


对于生产来说足够健壮吗?

如果您确实发现当前解决方案正在产生问题,并且可能不会,那么另一种方法是为要创建的每个id类型创建一个表,其中包含一个标识列和一个虚拟字段

即:

然后可以将一条记录插入该表,并使用内置函数检索标识

您可以在需要时从这些表中删除,并在年底重新设置id计数器


您甚至可以在回滚的事务中包装插入-标识值不受回滚的影响

是订单类型与订单ID分开的-即:您可以拥有AA120123456和AB120123456吗?是,我们希望按订单类型使用不同的id SQL Server 2012具有
序列
对象,允许您定义数字序列,完全独立于任何表。您可以为所需的每种订单类型设置一个序列,然后在插入行之前检索这些值。Ops!我不注意“2012”(你有粗体字:D)我们使用2008。更倾向于避免手动重置身份。我将尝试序列方法,我可以设置最小值和最大值,内置缓存功能和自动循环。太完美了@ShArDiCk如果您有SQL 2012,它是:)
 ABtypeID (ABID int identity(1,1), dummy varchar(1))
insert ABTypeID (dummy) values (null)
select Scope_Identity()