Yar*_*evi 7 sql transactions atomic sql-update
我试图了解如何安全地增加计数器列,这可能会被许多用户同时递增(它是移动应用程序的Web API).
我已经阅读了SO中用于处理该问题的策略的热门问题,但我似乎无法弄清楚使用简单的问题:
UPDATE Table SET Counter = Counter + 1
Run Code Online (Sandbox Code Playgroud)
我已经构建了以下代码示例来尝试获取不一致的值并证明自己只使用这个简单的更新语句并不是一个好习惯:
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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在示例中,我试图模拟许多用户同时访问API并更新计数器的场景.当代码运行时,计数器始终为10000,这意味着它是一致的.
测试是否正确模拟了我描述的场景?
如果是这样,为什么我可以在没有任何特殊锁定/交易策略的情况下使用更新语句并且仍能获得一致的结果?
如果您只使用这么简单的方法,那就没问题。
问题开始于以下情况:
Counter,这是失去确定性的好方法TransactionScope)Counter如果您依赖于唯一的自动递增标识符的值。select如果您将and分开,它显然不起作用update(不,update 基于 select没有帮助 - 与 plain 不同update, theselect没有与同一行上的更新序列化;这就是锁定提示的用武之地),我不确定如果使用output安全的话。当然,如果事务隔离级别发生变化,情况可能会完全不同。这实际上是错误的合理原因,因为 SQL 连接池不会重置事务隔离级别,因此如果您更改它,您需要确保它不会影响您在取出的数据库上执行的任何其他SqlConnectionSQL游泳池。
| 归档时间: |
|
| 查看次数: |
3553 次 |
| 最近记录: |