繁体   English   中英

避免由于延迟而在SQL Server中重复

[英]Avoid duplicates in SQL server due the latency

我在C#中有一个类似POS的系统,并且很长一段时间它都没有出现任何问题(它只是一个POS)。 但是现在,使用该系统的是4个POS,并且连接到相同的数据库,并且一个POS的所有销售都转到同一审计(表),而其他所有销售都在该审计中。 所以在这个系统中这是程序

  1. 获取最后票证编号的功能(使用简单的SELECT)
  2. 在该数字上加1(下一个打勾号)。
  3. 生成一个ID代码,将该票证号(带有终端,日期和员工代码)注入算法中
  4. 将销售记录与所有必要信息(日期,客户,雇员,IDCode等)插入数据库(通过简单的INSERT INTO)

但是使用4个POS时,我意识到有些销售具有相同的票证号,幸运的是,票证ID码不同,因为终端和员工不同,但是如何避免这种情况呢?

编辑1 :每个POS系统都具有双重功能,在一种模式下,POS的销售是集中的,并且在这种模式下,每个POS都会生成连续的票证(就像所有POS一样),在另一种模式下,每个POS都有自己的票证编号,因此我无法使用该身份。

只需使用一个序列来生成下一个票证号。

CREATE SEQUENCE Tickets
    START WITH 1
    INCREMENT BY 1;

然后每个POS都要做

SELECT NEXT VALUE FOR Tickets;

该序列保证永远不会两次返回相同的数字。

如前所述,如果TicketNumber是连续且唯一的,则听起来像IDENTITY字段是可行的方式。 但是,如果由于某种原因阻止了该操作,或者这一次需要进行太多更改,则可以通过使用Application在ID代码生成过程本身上创建锁,从而将过程本身限制为单线程锁(请参见sp_getapplocksp_releaseapplock )。 应用程序锁使您可以围绕任意概念创建锁。 意思是,您可以将@Resource定义为“ generate_id_code”,这将迫使每个调用者等待轮到他们。 它将遵循以下结构:

    BEGIN TRANSACTION;
    EXEC sp_getapplock @Resource = 'generate_id_code', @LockMode = 'Exclusive';

    ...current 4 steps to generate the ID Code...

    EXEC sp_releaseapplock @Resource = 'generate_id_code';
    COMMIT TRANSACTION;

您需要自己管理错误/回滚(如链接的MSDN文档中所述),因此请放入通常的TRY / CATCH中。 但是,这确实可以管理情况。

请注意:应当谨慎使用sp_getapplock / sp_releaseapplock 应用程序锁绝对可以非常方便(例如在这种情况下),但是只有在绝对必要时才应使用它们。

您需要通过原子操作来执行此操作。 因此,您可以将所有内容包装在事务中并锁定表。 有关锁定等的详细讨论, 请参见此处

锁定将减慢其他所有操作的速度,因为所有操作都将开始等待表释放以完成它,这可能是您无法忍受的。

或者你 能够 应该在将由数据库管理的列上使用标识 ,并保持唯一的递增编号。

您还可以将主键(希望有一个主键)组合成几件事。 然后,您可以为每个POS端点保留一个运行编号,以查看有关其性能的更多数据。 但这更多地涉及了分析,而这不在本文讨论范围之内。

如果可能的话,我强烈建议您放弃当前的方法,而改用GUID PK。

但是,我意识到在某些情况下无法进行重新设计(我们在遗留数据库中描述的场景完全相同)。

在这种情况下,可以结合使用UPDLOCK表提示和insert命令安全地获取最大值,并在需要时使用OUTPUT INSERTED功能将新的主键值检索到局部变量中:

DECLARE 
  @PK Table (PK INT NOT NULL) 

INSERT 
  INTO Audit (
       TicketNumber, 
       Terminal,
       Date,
       EmployeeCode,
       Client,
       IDCode,
       ... other fields )
  /* Record the new PK in the tablevariable */
OUTPUT INSERTED.TicketNumber INTO @PK
SELECT IsNull(MAX(TicketNumber), 0) + 1, 
       @Terminal,
       @Date,
       @EmployeeCode,
       @Client,
       @IDCode,
       ... other values
  FROM Audit WITH (UPDLOCK)

DECLARE @TicketNumber INT

  /* Move the new PK from the local tablevariable into a local variable for subsequent use */
SELECT @TicketNumber = PK
  FROM @PK

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM