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 可以查看执行记录

在这里插入图片描述
在这里插入图片描述

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