如何在一个事务中选择性地执行多个更新(不是添加或更新)?
How to selectively perform multiple updates (not add or update) in a transaction?
我有这个方法:
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
中也存在于缓存哈希中的那些键。我不想将来自 dictionary
的新键值对插入到缓存的哈希中。但是上面执行的是 "all or nothing" 更新,也就是说,如果缓存哈希中缺少字典中的任何一个键,则不会更新任何内容。
例如假设我的 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 脚本是我会尝试的唯一方法,但主要是寻找原生 SE.Redis API 方法.
没有原生的 redis 方法可以直接执行此操作,因此没有原生的 SE-Redis 方法可以直接执行此操作。我们在这里真正想要的是一个 XX
修饰符(请参阅 SET
了解我的意思),但在任何哈希命令中都不存在 - 只有 NX
,这是相反的您想要的(NX
是“当不存在时”)。
你可以在没有Lua的情况下做到这一点:
- 先检查每个是否存在
- 修剪你的更新集
- 创建仅包含已修剪更新的事务,并带有断言检查的条件
- 等等
但这是一个 lot 的往返和操作,并且由于数据更改冲突而导致失败的可能性很高。因此,我会说最好的方法是使用 Lua (对于您希望原子化的多个相关操作通常就是这种情况)。我会在 KEYS
中发送一个值,在 ARGV
中为每个条目发送一对值,然后在 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
我有这个方法:
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
中也存在于缓存哈希中的那些键。我不想将来自 dictionary
的新键值对插入到缓存的哈希中。但是上面执行的是 "all or nothing" 更新,也就是说,如果缓存哈希中缺少字典中的任何一个键,则不会更新任何内容。
例如假设我的 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 脚本是我会尝试的唯一方法,但主要是寻找原生 SE.Redis API 方法.
没有原生的 redis 方法可以直接执行此操作,因此没有原生的 SE-Redis 方法可以直接执行此操作。我们在这里真正想要的是一个 XX
修饰符(请参阅 SET
了解我的意思),但在任何哈希命令中都不存在 - 只有 NX
,这是相反的您想要的(NX
是“当不存在时”)。
你可以在没有Lua的情况下做到这一点:
- 先检查每个是否存在
- 修剪你的更新集
- 创建仅包含已修剪更新的事务,并带有断言检查的条件
- 等等
但这是一个 lot 的往返和操作,并且由于数据更改冲突而导致失败的可能性很高。因此,我会说最好的方法是使用 Lua (对于您希望原子化的多个相关操作通常就是这种情况)。我会在 KEYS
中发送一个值,在 ARGV
中为每个条目发送一对值,然后在 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