2016-02-12 119 views
0

因此,我有多个调用C#方法的ajax请求,其中包括检查数据库中的值并将其减1。针对异步请求同时触发数据库的解决方案

public SomeModel Get(int id) 
    ... 
    credit.Available -= 1; 
    dbContext.SaveChanges(); 

因此,从理论上讲,每次该方法运行时,可用信用减1。但是,因为它们几乎平行运行,所以credit.Available总是相同的,并且仅减少一次,例如,即使它运行5次。如果数字是20次,则会减少两次

可以做些什么来解决这个问题?

+0

不要为此使用ORM。考虑你的代码的作用 - 所有5个用户读取相同的值,例如10.所有5个将其减1,然后所有5个保存* same *值,9.如果你使用了SQL命令,比如'UPDATE ... SET AVAILABLE = AVAILABLE-1'你没有问题 –

+0

重复解释了为什么ORMs不能增加/减少,但这个问题提供了一个实际的解决方案 –

+0

@PanagiotisKanavos,继续,我在听 – chiapa

回答

0

可以锁定关键部分:

private static readonly object o = new Object(); 

public SomeModel Get(int id) 

    lock (o) 
    { 
     ... 
     credit.Availbale -= 1; 
     dbContext.SaveChanges(); 
    } 

你锁定的对象必须是静态的,没有任何实例。这样,多个线程将不得不为相同的锁运行,因此不会交错执行。

+1

在C#中使用锁时,如果真的想要锁定数据库端,似乎并不是最好的解决方案。 – jhilden

+0

他没有谈论前端层中的工作负载均衡器或多个节点,所以我假设他只有一台服务器。锁定应用程序是一种非常普遍的做法。他还没有任何性能问题(还没?),所以早期优化没有意义。指出你的观点,因为它违背了所有常见做法。此外,downvoting没有意义,冷静下来:) – pid

+0

这只会损害吞吐量的具体方法。它将*不*防止来自其他方法的无效更新。数据库应该能够为数千个并发用户提供服务。并发问题应该通过修改代码来解决,而不是限制访问。甚至一个桌面应用程序也不应该在使用简单的UPDATE时使用客户端锁 –

1

我建议使用原始SQL或SQL存储过程来完成这项工作。事情是这样的:

var sql = "UPDATE tbl SET Balance = Balance - 1 WHERE id = @id"; 
dbContext.ExecuteSqlCommand(sql, id); 
+0

那么代码会在那里? – chiapa

+0

@chiapa我添加了一个如何使用EF调用它的示例。 – jhilden

0

你可以使用一个存储过程来更新在为你的同时数据库值:

UPDATE tbl 
SET Balance = Balance - 1 
WHERE id = @id 

如果您正在使用实体框架,你可以使用以下称此在做了。

+0

如果5个用户试图保存相同的错误值,则使用存储过程根本无济于事 –

+0

@PanagiotisKanavos但是,如果使用返回值运行更新脚本,它不会保存错误的值。 –

+0

无论是存储过程还是原始语句都无关紧要。这是重要的内容。简单地写一个带有未指定内容的存储过程将无济于事 –

相关问题