C# ASP.NETWebMethods同步

C# ASP.NETWebMethods同步,c#,asp.net,sql,multithreading,C#,Asp.net,Sql,Multithreading,我在asp.net.asmx服务中有一个webmethod,它应该检查数据库中是否有记录,如果没有记录,它应该添加一个记录 代码的简化示例如下所示: object Mutex = new object(); [WebMethod] public void InsertIfNotExists(string CLI) { lock (Mutex) { using (SqlConnection conn = new SqlConnection(ConnectionStr

我在asp.net.asmx服务中有一个webmethod,它应该检查数据库中是否有记录,如果没有记录,它应该添加一个记录

代码的简化示例如下所示:

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);
        }
    }
}
实际上,它执行更多的检查和逻辑,这就是为什么我在.net中实现它,而不是在SQL语句本身中实现它,但本质上就是这样

大多数时候代码都运行良好,但有时我会因为多线程而陷入竞争状态,尽管我使用了锁

我今天得到的示例输出:

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
我们在这里看到,3个线程试图并行地将CLI 0501234567插入表中。 线程21和13进入座圈条件,每个线程插入1条记录。然后线程27也尝试插入一条记录,但找到了现有记录并退出

他们为什么在锁定互斥锁时这么做

注意:线程21永远无法完成-我认为这是由线程21中的异常引起的,因为我试图在实函数中重新检查后删除“附加”行,然后尝试执行该操作的第二个线程应该进入异常。我知道这很难看,但这是我目前唯一的解决办法,我想知道如何正确地做


为什么asp.net会以这种方式运行?在没有竞争条件的情况下,完成该任务的正确方式是什么?

锁定发生的对象必须是静态的,否则服务中的每个请求都会有一个实例