首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >IsolationLevel.RepeatableRead以防止重复?

IsolationLevel.RepeatableRead以防止重复?
EN

Stack Overflow用户
提问于 2018-09-11 00:38:29
回答 2查看 0关注 0票数 0

当我收到PayPal即时付款通知时,我正在开发一个应该创建产品(如运输保险单)的应用程序。不幸的是,PayPal有时会发送重复的通知。此外,还有另一个第三方在从PayPal获取更新时同时执行Web服务更新。

这是所涉及的数据库表的基本图。

代码语言:javascript
复制
// table "package"
// columns packageID, policyID, other data...
// 
// table "insurancepolicy"
// columns policyID, coverageAmount, other data...

这是我想要做的基本图表:

代码语言:javascript
复制
using (SqlConnection conn = new SqlConnection(...))
{
  sqlTransaction sqlTrans = conn.BeginTransaction(IsolationLevel.RepeatableRead);

  // Calls a stored procedure that checks if the foreign key in the transaction table has a value.
  if (PackageDB.HasInsurancePolicy(packageID, conn))
  { 
    sqlTrans.Commit();
    return false;
  }

  // Insert row in foreign table.
  int policyID = InsurancePolicyDB.Insert(coverageAmount, conn);
  if (policyID <= 0)
  {
    sqlTrans.Rollback();
    return false;
  }

  // Assign foreign key to parent table.  If this fails, roll back everything.
  bool assigned = PackageDB.AssignPolicyID(packageID, policyID, conn);
  if (!assigned)
  {
    sqlTrans.Rollback();
    return false;
  }
}

如果有两个(或多个)线程(或进程或应用程序)同时执行此操作,我希望第一个线程在没有policyID的情况下锁定“package”行,直到创建策略并分配policyID为止到包表。然后在将policyID分配给包表后释放锁。我希望调用同一代码的另一个线程在读取包行时会暂停,以确保它首先没有policyID。当第一个事务的锁被释放时,我希望第二个事务将看到policyID存在,因此返回时不会在策略表中插入任何行。

注意:由于CRUD数据库设计,每个存储过程都涉及读取(选择),创建(插入)或更新。

这是否正确使用了RepeatableRead事务隔离?

谢谢。

EN

回答 2

Stack Overflow用户

发布于 2018-09-11 09:11:07

如果insert into Policy只是在尝试插入重复时遇到一些唯一性表约束,它会更安全和更清晰。提高隔离级别可以降低并发性并导致其他令人讨厌的问题,如死锁。

另一种方法是始终插入Policy行,如果Package已经附加到Policy,则将其回滚:

代码语言:javascript
复制
begin tran (read committed)

/* tentatively insert new Policy */
insert Policy

/* attach Package to Policy if it's still free */
update Package
  set Package.policy_id = @policy_id
  where Package.package_id = @package_id and Package.policy_id is null

if @@rowcount > 0
  commit
else
  rollback

当冲突很少发生时,这种方法效果最好,这似乎就是您的情况。

票数 0
EN

Stack Overflow用户

发布于 2018-09-11 10:23:26

我同意aaronjensen的回应中的“消息队列”的想法。如果您担心同时尝试更新同一行数据的多个并发线程,则应该让线程将其数据插入工作队列,然后由单个线程按顺序处理。这显着减少了对数据库的争用,因为目标表仅由一个线程而不是“N”更新,并且工作队列操作仅限于消息传递线程的插入,以及数据处理线程的读取/更新。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100000746

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档