Как выборочно выполнять несколько обновлений (не добавлять или обновлять) в транзакции? - PullRequest
1 голос
/ 19 июня 2020

У меня есть этот метод:

    public async Task<bool> UpdateIfExist<T>(string cacheKey, IDictionary<string, T> dictionary)
    {
        ITransaction tran = m_connection.GetDatabase().CreateTransaction();

        List<HashEntry> hashEntries = new List<HashEntry>();
        foreach (KeyValuePair<string, T> keyValuePair in dictionary)
        {
            tran.AddCondition(Condition.HashExists(cacheKey, keyValuePair.Key)); // <-- this guy is the problem

            HashEntry hashEntry = GetHashEntry(keyValuePair);
            hashEntries.Add(hashEntry);
        }

        bool committed = await tran.ExecuteAsync();
        if (committed)
        {
            await tran.HashSetAsync(cacheKey, hashEntries.ToArray()));
        }

        return committed;
    }

Я намерен выполнить чистое обновление , то есть обновить те ключи в dictionary, которые также присутствуют в кешированном ha sh. Я не хочу, чтобы новые пары ключ-значение из dictionary вставлялись в кешированный ha sh. Но вышеупомянутое выполняет обновление «все или ничего», то есть, если какой-либо из ключей из словаря отсутствует в кешированном ha sh, то ничего не обновляется.


Например, у меня есть этот ha sh в моем кеше Redis:

myKey foo bar
      goo baz

И скажем, это мой входной словарь:

foo newBar
qoo qux

После вызова моего метода ..

Ожидается в кеше:

myKey foo newBar // updated since the field exists in hash
      goo baz

Фактически:

myKey foo bar   // no change to cache
      goo baz

Примечание: Если сценарий Lua - единственный способ, я попробую это, но в первую очередь ищу собственный подход к API SE.Redis.

1 Ответ

1 голос
/ 20 июня 2020

Не существует собственного способа Redis сделать это напрямую, следовательно, нет собственного способа SE-Redis сделать это напрямую. Нам действительно нужен модификатор XX (см. SET для того, что я имею в виду), но его нет ни в одной команде ha sh - только NX, что является противоположностью тому, что вы хотите (NX - «когда не существует»).

Вы могли бы сделать это без Lua с помощью:

  • проверки существования каждого первого
  • сокращение набора обновлений
  • создание транзакции только из сокращенных обновлений с условиями для утверждения проверок
  • et c

Но это лот циклов и операций, и существует высокая вероятность сбоя из-за конфликтующих изменений данных. Таким образом, я бы сказал, что лучший способ сделать это - использовать Lua (как это часто бывает для нескольких связанных операций, которые вы хотите использовать как atomi c). Я бы отправил одно значение в KEYS и пару значений для каждой записи в ARGV и l oop в Lua, по сути (полностью непроверено - может даже быть недопустимым синтаксисом)

for i=1, #ARGV, 2 do
    if redis.call('hexists', KEYS[1], ARGV[i]) == 1then
        redis.call('hset', KEYS[1], ARGV[i], ARGV[i+1])
    end
end
...