SQL - 将密钥并发插入表中

Run*_*ner 3 sql delphi concurrency firebird auto-increment

可能是一个微不足道的问题,但我希望得到最好的解决方案.

问题:

我有两个或更多工作人员将密钥插入一个或多个表.当两个或多个工作人员试图同时将同一个密钥插入其中一个密钥表时,就会出现问题.典型的问题.

  1. 如果存在密钥,则Worker A读取表(SELECT).没有钥匙.
  2. 如果存在键,则Worker B读取表(SELECT).没有钥匙.
  3. 工人A插入密钥.
  4. 工人B插入密钥.
  5. 工人A承诺.
  6. 工人B承诺.由于违反了唯一约束,因此抛出异常

关键表是简单的对.第一列是自动递增整数,第二列是varchar键.

这种并发问题的最佳解决方案是什么?我认为这是一个常见的问题.一种可靠的方法是处理抛出的异常,但不知何故我不相信这是解决这个问题的最佳方法.

我使用的数据库是Firebird 2.5

编辑:

一些额外的信息,以使事情清楚.

  1. 客户端同步不是一种好方法,因为插入来自不同的进程(工作者).而且有一天我可以让工人穿过不同的机器,所以即使是互斥也是不行的.
  2. 这种表的主键和第一列是自动增量字段.没问题.varchar字段是问题,因为它是客户端插入的东西.

典型的这种表是用户表.例如:

1  2056
2  1044
3  1896
4  5966
...

每个工作人员检查用户"xxxx"是否存在,如果不存在则插入.

编辑2:

仅供参考,如果有人会走相同的路线.IB/FB返回错误代码对(我正在使用InterBase Express组件).检查重复值违规是这样的:

except
  on E: EIBInterBaseError do
  begin
    if (E.SQLCode = -803) and (E.IBErrorCode = 335544349) then
    begin
      FKeysConnection.IBT.Rollback;
      EnteredKeys := False;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

Ond*_*lle 6

使用Firebird,您可以使用以下语句:

UPDATE OR INSERT INTO MY_TABLE (MY_KEY) VALUES (:MY_KEY) MATCHING (MY_KEY) RETURNING MY_ID
Run Code Online (Sandbox Code Playgroud)
  • 假设有一个BEFORE INSERT触发器,如果​​插入了NULL值,它将生成MY_ID.

这是文档.

更新:上述语句将避免异常并导致每个语句成功.但是,如果有许多重复的键值,它也会导致许多不必要的更新.这可以通过另一种方法来避免:只需处理客户端上的唯一约束异常并忽略它.详细信息取决于您使用哪个Delphi库来处理Firebird,但应该可以检查服务器返回的SQLCode,并且只忽略唯一约束违规的特定情况.