gpt4 book ai didi

sql - 使用简单更新的计数器列的原子增量

转载 作者:行者123 更新时间:2023-12-04 12:30:51 26 4
gpt4 key购买 nike

我试图了解如何安全地递增计数器列,该列可能由许多用户同时递增(它是移动应用程序的 Web API)。

我已经阅读了 SO 中有关处理该问题的策略的热门问题,但我似乎无法弄清楚使用简单的方法有什么问题:

UPDATE Table SET Counter = Counter + 1  

我已经构建了以下代码示例来尝试获取不一致的值并证明自己仅使用这个简单的更新语句不是好的做法:
class Program
{
static void Main(string[] args)
{
List<Task> tasks = new List<Task>();

for (int i = 0; i < 100; i++)
{
Task t = Task.Factory.StartNew(() =>
{
WriteToCounter();
});

tasks.Add(t);
}

Task.WaitAll(tasks.ToArray());
}

static void WriteToCounter()
{
string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
Random rnd = new Random();
for (int i = 1; i <= 100; i++)
{
int wait = rnd.Next(1, 3);
Thread.Sleep(wait);

string sql = "UPDATE Table SET Counter = Counter + 1";

SqlCommand command = new SqlCommand(sql, connection);
command.ExecuteNonQuery();
}
}
}
}

在示例中,我试图模拟许多用户同时访问 API 并更新计数器的场景。代码运行时,计数器为 总是在 10000 ,这意味着它是一致的。

测试是否正确模拟了我描述的场景?
如果是这样,为什么我可以在没有任何特殊锁定/事务策略的情况下使用更新语句并仍然获得一致的结果?

最佳答案

如果你只是像这样简单地使用它,那就没问题了。

问题开始于:

  • 您添加一个条件 - 大多数条件都可以,但要避免基于 Counter 进行过滤,这是失去确定性的好方法
  • 你在 里面更新交易 (注意这一点 - 在实际更新语句范围之外的事务中很容易,如果您使用例如 TransactionScope 则更是如此)
  • 你结合插入和更新(例如,通常的“如果不存在则插入”模式)——如果你只有一个计数器,这不是问题,但对于多个计数器,很容易陷入这个陷阱;不太难解决,除非你也有删除,否则它就变成了一个完全不同的联盟:)
  • 也许如果你依赖 Counter 的值是唯一的自动递增标识符。如果将 select 分开,显然不起作用和 update (不,基于 updateselect 没有帮助 - 与普通的 update 不同,select 没有在同一行更新序列化;这就是锁定提示出现的地方),我不是确定是否使用 output是安全的。

  • 当然,如果事务隔离级别发生变化,情况可能会大不相同。这实际上是导致错误的合理原因,因为 SQL 连接池不会重置事务隔离级别,因此如果您更改它,您需要确保它永远不会影响您在 SqlConnection 上执行的任何其他 SQL。从池中取出。

    关于sql - 使用简单更新的计数器列的原子增量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29943772/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com