如何确保不执行两次相同的数据库事务?

时间:2013-07-24 21:33:24

标签: javascript sql

我正在通过网络对数据库执行插入操作,我想确保我从不尝试插入已插入的数据。客户端在Web浏览器中运行,使用Javascript将XMLHttpRequest发送到包含要插入的数据的服务器。如果出现错误,我必须稍后再试 - 例如,可能存在暂时的网络错误。但是,我无法知道我可以得到保证,我将收到插件成功的通知,因为在请求进入服务器之后但在成功回复之前网络可能会被拒绝。虽然这对我来说似乎不太可能,但是如果它发生的话,它会完全弄乱数据库,因为没有办法知道某些条目不应该存在。

2 个答案:

答案 0 :(得分:1)

使用您正在插入的数据的存在与否,以便在第二个相同的交易通过时,它将被忽略。类似的东西:

INSERT MyTable (Value1, Value2, Value3)
SELECT @Value1, @Value2, @Value3
WHERE
   NOT EXISTS (
      SELECT *
      FROM dbo.MyTable T
      WHERE
          T.Value1 = @Value1
          AND T.Value2 = @Value2
   )
;

请注意,这并不能完全解决两个客户端同时尝试执行相同操作的潜在竞争条件 - EXISTS子句在INSERT操作之前及时执行,并且这可以产生两个试图插入的客户端。因此,您必须添加诸如WITH (UPDLOCK, HOLDLOCK)之类的锁定(对于并发而言非常糟糕,因为如果该行不存在则必须采用可以阻止不相关数据插入的范围锁定),或者在容错中容忍有关重复键的错误。客户端。

如果数据实际上可以复制,只要客户端发送数据,那么您可以通过以下几种方式来处理数据:

  1. 向表中添加其他列,直到它是唯一的。

  2. 或者,创建作为事务一部分的时间戳/序列号,并在插入(在数据库事务中)之后将此序列号记录到表中。将插入与缺少此序列号相关联。

  3. 为您的客户端制定一些策略,直到可以获取已发送的请求,这可能是一个额外的保护层,同时可能首先阻止一些重复尝试 - 如果您现在没有得到确认,但是它会在以后到达,您确认/删除排队的已发送交易。

    要概括为防止重复DELETEUPDATE,您应该添加column of type rowversion。在所有查询的WHERE子句中包含此值,如果其他人在您上次读取该行后触摸了该行,则这些查询将不会影响任何行。您仍然必须检测到没有行受到影响并在之后做一些智能 - 这可能非常困难 - 但至少您已检测到并避免了编辑冲突或重复操作。

    如果问题无法隔离到特定行的特定编辑,那么请提出一个新问题,提供一些具体示例,以便您可以获得更好的建议。给我发表评论,并附上新问题的链接,我会看看。

答案 1 :(得分:0)

尝试在字段中添加一些约束:

ALTER TABLE Persons ADD CONSTRAINT MyTable UNIQUE (Value1, Value2, Value3)