日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis 使用 Lua 脚本进行原子操作

發(fā)布時(shí)間:2023/12/4 数据库 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis 使用 Lua 脚本进行原子操作 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Redis 使用 Lua 腳本進(jìn)行原子操作

Intro

之前寫過一篇文章也是 Redis 使用 LUA 腳本實(shí)現(xiàn)分布式的 CAS 操作,可以參考:基于 Redis 實(shí)現(xiàn) CAS 操作

最近使用 Redis 的時(shí)候有一個(gè)需求,只有值發(fā)生變化的時(shí)候才更新,如果要更新的值和現(xiàn)在的值是一樣的就不用更新,有點(diǎn)類似于 SET NX,只是 SET NX 只有值不存在的時(shí)候才會(huì) SET,我的需求則是要檢查要 SET 的值和 Redis 里的值,如果不一樣就 SET,一樣就直接返回

Implement

我實(shí)現(xiàn)了針對 String 和 Hash 的 SET 檢查,核心就是我們的 Lua 腳本

實(shí)現(xiàn)代碼如下:

對于 Hash 會(huì)多一個(gè)參數(shù) —— hash field name,?對于 string?則直接是 value 了,就會(huì)比 hash?少一個(gè)參數(shù)

private?const?string?HashSetWhenValueChangedLuaScript?=?@" if?redis.call(""HGET"",?KEYS[1],?ARGV[1])?==?ARGV[2]?thenreturn?0 elseredis.call(""HSET"",?KEYS[1],?ARGV[1],?ARGV[2])return?1 end ";private?const?string?StringSetWhenValueChangedLuaScript?=?@" if?redis.call(""GET"",?KEYS[1])?==?ARGV[1]?thenreturn?0 elseredis.call(""SET"",?KEYS[1],?ARGV[1])return?1 end ";

實(shí)現(xiàn)起來也比較簡單,就是先取一下 Redis 中的數(shù)據(jù),如果和輸入的值是一樣就返回 0,不一樣則更新值,然后返回 1

StackExchange.Redis 使用 API

在 StackExchange.Redis 中可以使用 ScriptEvaluate/ScriptEvaluateAsync 來執(zhí)行 Lua 腳本,為了方便使用我把他們封裝成了擴(kuò)展方法,實(shí)現(xiàn)如下:

public?static?bool?StringSetWhenValueChanged(this?IDatabase?db,?RedisKey?key,?RedisValue?value) {return?(int)db.ScriptEvaluate(StringSetWhenValueChangedLuaScript,?new[]?{?key?},?new[]?{?value?})?==?1; }public?static?async?Task<bool>?StringSetWhenValueChangedAsync(this?IDatabase?db,?RedisKey?key,?RedisValue?value) {return?await?db.ScriptEvaluateAsync(StringSetWhenValueChangedLuaScript,?new[]?{?key?},?new[]?{?value?}).ContinueWith(r?=>?(int)r.Result?==?1); }public?static?bool?HashSetWhenValueChanged(this?IDatabase?db,?RedisKey?key,?RedisValue?field,?RedisValue?value) {return?(int)db.ScriptEvaluate(HashSetWhenValueChangedLuaScript,?new[]?{?key?},?new[]?{?field,?value?})?==?1; }public?static?async?Task<bool>?HashSetWhenValueChangedAsync(this?IDatabase?db,?RedisKey?key,?RedisValue?field,?RedisValue?value) {return?await?db.ScriptEvaluateAsync(HashSetWhenValueChangedLuaScript,?new[]?{?key?},?new[]?{?field,?value?}).ContinueWith(r?=>?(int)r.Result?==?1); }

Sample

使用示例可以參考下面的測試用例:

[Fact] public?void?StringSetWhenValueChangedTest() {var?key?=?$"{nameof(StringSetWhenValueChangedTest)}";var?redis?=?DependencyResolver.Current.GetRequiredService<IConnectionMultiplexer>().GetDatabase();redis.StringSet(key,?1);//?update?to?1?if?now?is?not?1Assert.False(redis.StringSetWhenValueChanged(key,?1));Assert.Equal(1,?redis.StringGet(key));//?update?to?2?if?now?is?not?2Assert.True(redis.StringSetWhenValueChanged(key,?2));Assert.Equal(2,?redis.StringGet(key)); }[Fact] public?void?HashSetWhenValueChangedTest() {var?key?=?$"{nameof(HashSetWhenValueChangedTest)}";var?field?=?"testField";var?redis?=?DependencyResolver.Current.GetRequiredService<IConnectionMultiplexer>().GetDatabase();redis.HashSet(key,?field,?1);Assert.False(redis.HashSetWhenValueChanged(key,?field,?1));Assert.Equal(1,?redis.HashGet(key,?field));Assert.True(redis.HashSetWhenValueChanged(key,?field,?2));Assert.Equal(2,?redis.HashGet(key,?field)); }

More

在使用 Lua 腳本的時(shí)候,如果要使用不等于的邏輯需要小心一些,和其他語言不同,需要使用 ~= 而非 != 來表示不等

References

  • https://github.com/WeihanLi/WeihanLi.Redis/blob/dev/src/WeihanLi.Redis/RedisExtensions.cs

  • https://github.com/WeihanLi/WeihanLi.Redis/blob/dev/test/WeihanLi.Redis.UnitTest/RedisExtensionsTest.cs

  • 基于 Redis 實(shí)現(xiàn) CAS 操作

總結(jié)

以上是生活随笔為你收集整理的Redis 使用 Lua 脚本进行原子操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。