如何防止Web应用程序中的竞争条件

时间:2015-12-16 11:02:18

标签: c# sql-server entity-framework concurrency database-concurrency

我有一个Web应用程序,用户通过单击“加入”按钮进行注册。网站上可以有这么多用户,这就是为什么要快速保持我的数据库查询;我选择不在数据库中添加foriegnkey约束(虽然它是关系数据库)。

现在发生的情况是,具有相同userId的用户在两个不同的浏览器中打开应用程序并同时点击“加入”按钮;同一用户的两行被添加到数据库中是错误的。

我必须停止这一点的想法是:

  1. 在存储过程中和SQL事务隔离级别为SERIALIZABLE的事务中执行检查/插入逻辑;但是使用这种方法,即使两个不同的用户同时点击“加入”按钮,表也会被锁定。
  2. 在c#中使用lock关键字并从中执行检查/插入逻辑,但我相信如果来自两个浏览器的同一个用户他们将获得自己的锁,并且仍然可以在数据库中有两个条目。此外,对于不同的用户,它可能会产生问题,因为其他代码将等待第一个代码释放资源。
  3. 使用由EntityFramework支持的乐观并发,但我不确定它是否能解决我的问题。
  4. 你能帮帮我吗?

2 个答案:

答案 0 :(得分:1)

您可以通过在用户名中创建唯一索引来轻松解决问题。因此,只保存第一个。下一个将被报告为错误,因为它会破坏唯一索引。

事实上,它应该是主键。

根据你的评论,你的桌子很大。因此,在每次插入操作中不使用索引而是在每个插入/删除/更新操作上更新索引时,在整个表中查找行必须更糟。你应该考虑这个。

无论如何,解决不插入值的问题的唯一方法就是检查它。

乐观并发与此无关。乐观并发与读取数据,修改数据和保存更改有关,而无需锁定表。乐观并发的作用可以通过以下步骤解释:

  1. 从数据库中读取原始行,没有任何锁定或事务
  2. 该应用修改原始行
  3. 当应用程序尝试保存更改时,它会检查数据库中的行是否与步骤1中读取的行完全相同。如果是,则保存更改。如果不是并发异常则抛出。
  4. 所以乐观的并发性对你没有帮助。

    我坚持使用一种独特的索引,这是最安全,最简单,可能更具优势的解决方案。

答案 1 :(得分:0)

我会使用Entity及其Optimistic Concurrency。

它会将它包装在一个事务中并为您处理这些问题。请记住在表格上放置标识和主键。如果用户名必须是唯一的,则在表格中添加唯一注释。