Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net core 如何使用StackExchange.Redis使多个操作原子化_.net Core_Redis_Transactions_Locking_Stackexchange.redis - Fatal编程技术网

.net core 如何使用StackExchange.Redis使多个操作原子化

.net core 如何使用StackExchange.Redis使多个操作原子化,.net-core,redis,transactions,locking,stackexchange.redis,.net Core,Redis,Transactions,Locking,Stackexchange.redis,您好,我有以下问题: 我有一个包含字符串的哈希。此哈希将被多个用户查询 当用户使用键来首先检查此哈希中是否存在此哈希,如果不存在,则添加它 如何使“检查哈希是否存在”、“如果不存在则添加”操作成为原子操作? 阅读redis文档,我需要的似乎是Watch。基本上,启动一个事务,并在变量发生变化时结束它 我已尝试使用条件。HashNotExists无效: class Program { public static async Task<bool> LockFileFor

您好,我有以下问题:

我有一个包含字符串的哈希。此哈希将被多个用户查询

当用户使用
键来首先检查此哈希中是否存在此哈希,如果不存在,则添加它

如何使“检查哈希是否存在”、“如果不存在则添加”操作成为原子操作? 阅读redis文档,我需要的似乎是
Watch
。基本上,启动一个事务,并在变量发生变化时结束它

我已尝试使用
条件。HashNotExists
无效:

class Program {

        public static async Task<bool> LockFileForEditAsync(int fileId) {
            var database = ConnectionMultiplexer.Connect(CON).GetDatabase();
            var exists = await database.HashExistsAsync("files", fileId); //this line is for  shorting the transaction if hash exists 

            if (exists) {
                return false;
            }

            var tran = database.CreateTransaction();
            tran.AddCondition(Condition.HashNotExists("files", fileId));
            var setKey = tran.HashSetAsync("files", new HashEntry[] { new HashEntry(fileId, 1) });
            var existsTsc = tran.HashExistsAsync("files", fileId);

            if (!await tran.ExecuteAsync()) {
                return false;
            }

            var rezult = await existsTsc;
            return rezult;
        }

        public const string CON = "127.0.0.1:6379,ssl=False,allowAdmin=True,abortConnect=False,defaultDatabase=0";

        static async Task Main(string[] args) {
            int fid = 1;
            var locked = await LockFileForEditAsync(fid);
        }
    }
类程序{
公共静态异步任务LockFileForEditAsync(int-fileId){
var database=ConnectionMultiplexer.Connect(CON).GetDatabase();
var exists=await database.HashExistsAsync(“files”,fileId);//如果存在哈希,此行用于缩短事务
如果(存在){
返回false;
}
var tran=database.CreateTransaction();
tran.AddCondition(Condition.HashNotExists(“files”,fileId));
var setKey=tran.HashSetAsync(“文件”,新HashEntry[]{newhashentry(fileId,1)});
var existsc=tran.HashExistsAsync(“文件”,fileId);
如果(!wait tran.ExecuteAsync()){
返回false;
}
var rezult=等待退出;
返回rezult;
}
public const string CON=“127.0.0.1:6379,ssl=False,allowAdmin=True,abortConnect=False,defaultDatabase=0”;
静态异步任务主(字符串[]args){
int fid=1;
var locked=等待LOCKFILEFOREDITANCH(fid);
}
}
如果我通过
redis cli
连接并在
cli
中发出:
hset files{fileId}1
,在发出
ExecuteAsync
(在调试器中)之前发出
ExecuteAsync
,我预计该事务将失败,因为我放置了
条件。但事实并非如此

基本上如何使用redis命令在两个操作上放置类似于锁的东西:

  • 检查hashentry是否存在
  • 添加hashentry

  • 坏消息,好消息,还有其他一切

    坏消息

    这不起作用,因为SE.Redis通过管道传输事务。这意味着调用
    ExecuteAsync()
    时,所有事务命令都会同时发送到服务器。但是,先评估条件

    tran.AddCondition(Condition.HashNotExists(“files”,fileId))转换为:

    WATCH "files"
    HEXISTS "files" "1"
    
    当调用
    ExecuteAsync()
    来评估条件时,首先发送这两个命令。如果条件为true(
    hexist“files”1
    =0),则发送其余的事务命令

    这有效地确保了没有误报,因为如果
    文件
    键在其间被修改(而SE.Redis正在评估条件),
    监视
    将使事务失败

    问题在于假阴性。例如,如果在SE.Redis评估条件时设置了哈希的另一个字段,则事务也将失败。
    WATCH“files”
    就是这样做的

    我通过调用
    ExecuteAsync()
    时运行
    redis benchmark-c5hset files2 1
    来测试这一点。条件已通过,但事务失败,尽管字段“1”不存在,因为字段“2”设置在两者之间

    我在单独的redis cli窗口中使用该命令进行了验证。这对于排除未达到的期望值很方便,或者只是查看服务器的实际运行情况和运行时间

    当您关心散列的某个字段时,
    WATCH
    是没有帮助的,因为当触及其他字段时,它会产生误报

    解决这个问题的一个方法是使用一个常规键(
    files:1

    好消息

    有一个命令可以完全按照您的要求执行:

    这将完全简化LockFileForEditAsync():

        public static async Task<bool> LockFileForEditAsync(int fileId)
        {
            var database = ConnectionMultiplexer.Connect(CON).GetDatabase();
            var setKey = await database.HashSetAsync("files", fileId, 1, When.NotExists);
            return setKey;
        }
    
    公共静态异步任务LockFileForEditAsync(int-fileId)
    {
    var database=ConnectionMultiplexer.Connect(CON).GetDatabase();
    var setKey=await database.HashSetAsync(“files”,fileId,1,When.NotExists);
    返回设置键;
    }
    
    请注意.note存在时的
    参数。它会导致发送
    HSETNX“文件”“1”“1”
    命令

    其他一切…

    您可以在这样的情况下使用,在这种情况下,您希望以原子方式完成一些条件操作,例如


    似乎您正在尝试执行分布式锁定。请参阅其他您可能需要考虑的方面。请参阅,以获取关于此版本的精彩故事。

    显然它适用于我的变体。如果不存在,我不想只添加。我想添加并返回true(如果它不存在并且创建成功),如果它确实存在,则返回false,或者,它试图创建它,但同时有人创建了它。(事务)这正是HSETNX所做的:“仅当字段尚不存在时,才在“键到值”处存储的哈希中设置字段。若密钥不存在,则创建一个包含散列的新密钥。如果字段已存在,则此操作无效。“.Your last condition”它试图创建它,但有人同时创建了它。(事务)“如果使用一个命令,则不适用,Redis是单线程的,因此一个命令自动是原子的。如果字段是散列中的新字段并且设置了值,请参阅HSETNX:1的返回值。”。如果散列中已存在字段且未执行任何操作,则为0。我看不出这与您想要的不完全匹配:-)您指的是什么变体?在我的代码中,您可以看到每个用户首先尝试查看哈希是否存在,然后添加它。如果用户1检查哈希并成功,则在写入哈希u之前