c#:基於數據庫的簡單分佈式鎖

環境:

  • win10
  • sqlserver 2014
  • vs2019

參照: 基於數據庫實現的分佈式鎖

實現過程:

1、在數據庫中新建一張鎖表

create table db_lock(
	id int identity(1,1),
	lock_str varchar(200) unique not null,
	lock_time datetime default(GetDate()),
	lock_userid int not null
)

2、c#代碼中獲取鎖和釋放鎖

代碼中的Common.GetIDb()表示的是獲取數據庫的操作對象,具體可以參照:https://blog.csdn.net/u010476739/article/details/54882950

public class DBLock
{
    /// <summary>
    /// 獲取分佈式鎖
    /// </summary>
    /// <param name="lock_str">鎖定的資源名稱</param>
    /// <param name="timeout">超時次數(1秒1次)</param>
    /// <returns></returns>
    public static bool GetLock(string lock_str, long trycount)
    {
        if (trycount <= 0) trycount = 1;
        var iDb = Common.GetIDb();
        for (int i = 0; i < trycount; i++)
        {
            try
            {
                iDb.ExecuteSql("insert into db_lock(lock_str,lock_userid) values('" + lock_str + "','1')");
                return true;
            }
            catch (Exception ex)
            {
                Thread.Sleep(1000);
            }
        }
        return false;
    }

    /// <summary>
    /// 釋放分佈式鎖
    /// </summary>
    /// <param name="lock_str"></param>
    public static void ReleaseLock(string lock_str)
    {
        try
        {
            var iDb = Common.GetIDb();
            iDb.ExecuteSql("delete from db_lock where lock_str='" + lock_str + "' and lock_userid='1'");
        }
        catch { }
    }
}

3、調用測試

class Program
{
    static void Main(string[] args)
    {

        Console.WriteLine("開始獲取鎖[" + DateTime.Now.ToString("HH:mm:ss.fff") + "]...");
        if (DBLock.GetLock("lock_demo", 3))
        {
            Console.WriteLine("獲取到了鎖[" + DateTime.Now.ToString("HH:mm:ss.fff") + "]...");
            Thread.Sleep(10 * 1000);
            DBLock.ReleaseLock("lock_demo");
            Console.WriteLine("已釋放鎖[" + DateTime.Now.ToString("HH:mm:ss.fff") + "]!");
        }
        else
        {
            Console.WriteLine("獲取鎖失敗[" + DateTime.Now.ToString("HH:mm:ss.fff") + "]!");
        }
        Console.WriteLine("ok");
        Console.ReadLine();
    }
}

測試效果如下:
在這裏插入圖片描述
另外,如果想提高鎖的性能的話(減少不必要的鎖競爭),記着使用雙重判斷:

if(true)
{
	if (DBLock.GetLock("lock_demo", 3))
	{
	   if(true)
	   {
		   	//...
	   }
	}
}

4、關於死鎖以及處理方法

當程序獲取鎖後突然斷電或意外情況導致沒有主動釋放鎖,這種情況下是會發生死鎖的,即使服務器重啓也不行。爲了解決這種問題,我們可以在程序中定時執行sql語句(每兩分鐘)或者是直接在數據庫服務器上建立定時作業。
下面演示了在sqlsever2014上新建作業定時清除過期鎖:

4.1 確保開啓SQL Server代理

在這裏插入圖片描述
如果你的代理顯示已禁用,可以嘗試右鍵-》啓動或啓動SQL Server代理服務:
在這裏插入圖片描述
或者是參考:“代理 XP”服務器配置選項

4.2 新建作業

在這裏插入圖片描述
在這裏插入圖片描述
左側選擇“步驟”繼續:
在這裏插入圖片描述
點擊上面的“新建”:
在這裏插入圖片描述
上面的“步驟”設置完成後,開始設置“計劃”,也就是執行的間隔,這裏我們希望每3分鐘運行一次:
在這裏插入圖片描述
新建完成後確定即可!

4.3 可以查看執行記錄

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章