[英]ASP .NET WebMethods Synchronization
I have a webmethod in asp.net .asmx service, wich is supposed to check if there are records in a DB, and if there are no records it should add a record 我在asp.net .asmx服务中有一个web方法,应该检查数据库中是否有记录,如果没有记录,则应添加一条记录
the simplified example of code is like this: 简化的代码示例如下所示:
object Mutex = new object();
[WebMethod]
public void InsertIfNotExists(string CLI)
{
lock (Mutex)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
using (SqlDataAdapter adapter = new SqlDataAdapter())
using (DataSet ds = new System.Data.DataSet()){
{
//I log with log4net
logger.Debug("InsertIfNotExists: Start Function: CLI:" + CLI);
int dummy = 0;
string sql = "SELECT * CLI Promote where CLI=" + CLI + " ";
adapter.SelectCommand = new SqlCommand(sql, conn);
adapter.Fill(ds);
DataTable t = ds.Tables[0];
logger.Debug("InsertIfNotExists: " + t.Rows.Count + " records found for CLI:" + CLI);
if (t.Rows.Count == 0)
{
logger.Debug("InsertIfNotExists: starting to add to table: CLI:" + CLI);
DataRow dr = t.NewRow();
dr["CLI"] = CLI;
dr["DateOfSend"] = DateTime.Now;
InsertToTable(t, dr, sql);
logger.Debug("InsertIfNotExists: added to table: CLI:" + CLI + ", starting re-check");
//checking if exist more then one lines - one more time
sql = "SELECT * CLI Promote where CLI=" + CLI + "";
adapter.SelectCommand = new SqlCommand(sql, conn);
adapter.Fill(ds);
t = ds.Tables[0];
logger.Debug("InsertIfNotExists: re-check for CLI:" + CLI + ", records count=" + t.Rows.Count);
}
logger.Debug("InsertIfNotExists: Finish Function for CLI:" + CLI);
}
}
}
Actually it does more checks and logic, that's why I implement it in .net and not in the SQL statement itself, but essentially that is it. 实际上,它执行更多的检查和逻辑,这就是为什么我在.net中而不是在SQL语句本身中实现它的原因,但实际上就是这样。
Most of the time the code works well, but sometimes I get into race conditions because of multithreading, though I use lock. 大多数情况下,代码运行良好,但是有时我会因为多线程而陷入竞争状态,尽管我使用锁。
Sample output I got today: 我今天得到的样本输出:
2013-09-15 11:47:14,145 [21] DEBUG Namespace.Service1 InsertIfNotExists: Start Function: CLI: 0501234567
2013-09-15 11:47:14,145 [13] DEBUG Namespace.Service1 InsertIfNotExists: Start Function: CLI: 0501234567
2013-09-15 11:47:14,148 [21] DEBUG Namespace.Service1 InsertIfNotExists: 0 records found for CLI: 0501234567
2013-09-15 11:47:14,148 [21] DEBUG Namespace.Service1 InsertIfNotExists: starting to add to table: CLI: 0501234567
2013-09-15 11:47:14,148 [13] DEBUG Namespace.Service1 InsertIfNotExists: 0 records found for CLI: 0501234567
2013-09-15 11:47:14,148 [13] DEBUG Namespace.Service1 InsertIfNotExists: starting to add to table: CLI: 0501234567
2013-09-15 11:47:14,149 [21] DEBUG Namespace.Service1 InsertIfNotExists: added to table: CLI: 0501234567, starting re-check
2013-09-15 11:47:14,149 [13] DEBUG Namespace.Service1 InsertIfNotExists: added to table: CLI: 0501234567, starting re-check
2013-09-15 11:47:14,154 [27] DEBUG Namespace.Service1 InsertIfNotExists: Start Function: CLI: 0501234567
2013-09-15 11:47:14,157 [27] DEBUG Namespace.Service1 InsertIfNotExists: 2 records found for CLI: 0501234567
2013-09-15 11:47:14,157 [27] DEBUG Namespace.Service1 InsertIfNotExists: Finish Function for CLI: 0501234567
2013-09-15 11:47:14,183 [13] DEBUG Namespace.Service1 InsertIfNotExists: re-check for CLI: 0501234567, records count=2
2013-09-15 11:47:14,184 [21] DEBUG Namespace.Service1 InsertIfNotExists: re-check for CLI: 0501234567, records count=2
2013-09-15 11:47:14,185 [13] DEBUG Namespace.Service1 InsertIfNotExists: Finish Function for CLI: 0501234567
2013-09-15 11:49:19,626 [21] DEBUG Namespace.Service1 InsertIfNotExists: Start Function: CLI:0507654321
What we see here that 3 threads attempted to insert CLI 0501234567 to the table in the parallel. 我们在这里看到的是3个线程试图将CLI 0501234567插入并行表中。 Threads 21 and 13 entered the race conditons and each one inserted 1 record.
线程21和13进入比赛状态,每个线程插入1条记录。 Then thread 27 also tried to insert a record, but found existing records and exited.
然后线程27也尝试插入一条记录,但是找到了现有记录并退出了。
Why did they do it when locked on mutex? 他们为什么在互斥锁上锁定了?
Note: Thread 21 never gets to Finish - I think it is caused by an exception in thread 21, because I try to remove the "additional" rows after the re-check in the real function, and then the second thread which tries to do it should get into an exception. 注意:线程21永远无法完成-我认为这是由线程21中的异常引起的,因为在重新检查实函数后,我尝试删除“附加”行,然后尝试删除第二个线程它应该成为一个例外。 I know it's ugly but that's the only solution I got for now, I'd like to know how to do it properly.
我知道这很丑陋,但这是我目前唯一的解决方案,我想知道如何正确执行。
Why does asp.net behave in such a way and what is the proper way to accomplish that task without the race conditions? 为什么asp.net的行为方式如此,在没有竞争条件的情况下完成该任务的正确方法是什么?
您要进行锁定的对象必须是静态的,否则对于服务中的每个请求都将有一个实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.