環境:
- 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 可以查看執行記錄