简体   繁体   English

ASP .NET WebMethods同步

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM