• C# lock 避免多人同时操作


    当多人同时操作时有可能会出现一些意外情况,我们可以应用lock关键词,lock是将语句块标示为临界区,确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其它线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。

    以下以订单号做一个实验。

    Table表結構如下:

    Table表結構
    ifobject_id('tb') isnotnulldroptable tb
    createtable tb(PONo nvarchar(10) ,CreateBy nvarchar(20) ,CreateDate smalldatetime)
    go
    select*from tb
    go
    --PONo CreateBy CreateDate
    --
    ---------- -------------------- -----------------------
    --
    (0 个数据列受到影响)

    前台代码如下:

    前臺代碼如下
    protectedvoid Button1_Click(object sender, EventArgs e)
    {
    string name = User.Identity.Name.ToString();
    string PONo = TestFactory.GetPONumber(name);
    Response.Write(PONo);
    }

    后臺代碼如下,未使用lock:

    后臺代碼,未使用lock:
    publicclass TestFactory
    {
    privatestaticobject objPONo =newobject();

    publicstaticstring GetPONumber(string name)
    {
    //lock (objPONo)
    //{
    //定義訂單號PONo
    string PONo =string.Empty;

    //將訂單號PONo自動加1
    string strsql ="update tb set PONo=PONo+1,CreateBy='"+ name +"',CreateDate=getdate()";
    int i = SQLHelper.ExecuteNonQuery(strsql);

    //如果登陸人為Takako,線程睡眠3秒.以作測試
    if (name.ToLower() =="takako_yang")
    {
    Thread.Sleep(
    3000);
    }

    //如果update失敗,表示DB中不存在資料,則往DB塞入第一筆訂單號PONo:1000000000.
    if (i ==0)
    {
    strsql
    ="insert into tb values(1000000000,'"+ name +"',getdate())";
    i
    = SQLHelper.ExecuteNonQuery(strsql);
    }

    //選出最后一筆
    strsql ="select max(PONo) from tb";
    object o = SQLHelper.ExecuteScalar(strsql);
    if (o == DBNull.Value)
    {
    PONo
    ="1000000000";
    }
    else
    {
    PONo
    = SQLHelper.ExecuteScalar(strsql).ToString();
    }
    return PONo;
    //}
    }
    }

    实验者路人甲、路人乙,在程序中添加了一段Thread.Sleep(3000),判断当实验者为甲时,睡眠3秒再继续后面的动作。

    当甲按下甲页面上的按钮,乙在1秒后也按下乙页面上按钮;

    这时乙页面会往DB塞一笔订单号PONo:1000000000;

    3秒后,甲页面也会往系统塞一笔订单号PONo:1000000000;

    很显然,出现了两笔一模一样的订单号,这不是我们想要的。

    后台代码,使用lock后

    后臺代碼,使用lock后:
    publicclass TestFactory
    {
    privatestaticobject objPONo =newobject();

    publicstaticstring GetPONumber(string name)
    {
    lock (objPONo)
    {
    //定義訂單號PONo
    string PONo =string.Empty;

    //將訂單號PONo自動加1
    string strsql ="update tb set PONo=PONo+1,CreateBy='"+ name +"',CreateDate=getdate()";
    int i = SQLHelper.ExecuteNonQuery(strsql);

    //如果登陸人為Takako,線程睡眠3秒.以作測試
    if (name.ToLower() =="takako_yang")
    {
    Thread.Sleep(
    3000);
    }

    //如果update失敗,表示DB中不存在資料,則往DB塞入第一筆訂單號PONo:1000000000.
    if (i ==0)
    {
    strsql
    ="insert into tb values(1000000000,'"+ name +"',getdate())";
    i
    = SQLHelper.ExecuteNonQuery(strsql);
    }

    //選出最后一筆
    strsql ="select max(PONo) from tb";
    object o = SQLHelper.ExecuteScalar(strsql);
    if (o == DBNull.Value)
    {
    PONo
    ="1000000000";
    }
    else
    {
    PONo
    = SQLHelper.ExecuteScalar(strsql).ToString();
    }
    return PONo;
    }
    }
    }

    將DB中的資料刪光,delete tb

    和上一個實驗一樣,甲按下甲頁面按鈕后,乙在1秒后也按下乙頁面按鈕.

    結果如下:甲頁面在3秒后顯示了订单号PONo:1000000000;乙在3秒后顯示了訂單號PONo:1000000001。

    這正是理想的結果。

  • 相关阅读:
    Apache httponly Cookie泄露

    shell脚本
    Linux与windows的文件系统结构
    使用rsync进行远程同步
    电子邮件服务
    httpd虚拟主机
    Enpass 基于 Mezzanine
    powershell: 生成随机字符串
    thinkPHP5.x 更新字段为 NULL
  • 原文地址:https://www.cnblogs.com/takako_mu/p/1710957.html
Copyright © 2020-2023  润新知