本文介紹改用 Lua 方式存取 Redis,以省下連線、存取次數。
Demo內容
- 先在 redis 建立一個 key
- 以 lua 方式執行,把值取出來,加上整數 123,寫回去 redis
- 以一般指令方式,把值取出來,加上整數 123,寫回去 redis
建立連線機制
1 2 3 4 5
| private const string RedisHost = "127.0.0.1:6379"; private const string TestKey = "TestRedisKey";
using var conn = await ConnectionMultiplexer.ConnectAsync(RedisHost); var redisDb = conn.GetDatabase();
|
一般存取方式
當有一些邏輯比較複雜就必須把值取回程式中運算。
1 2 3 4 5 6 7 8 9 10 11 12
| private static async Task RunWithoutLua(IDatabase db) { var currentValue = await db.StringGetAsync(TestKey);
var newValue = Convert.ToInt32(currentValue) + 123; await db.StringSetAsync(TestKey, newValue);
var afterUpdatedValue = await db.StringGetAsync(TestKey); Console.WriteLine($"RunWithoutLua: After updated value: {afterUpdatedValue}"); }
|
用 Lua 方式存取
這邊是示意才用這種方式寫,但大型專案還是建議把 .lua 整理起來分類放在資料夾內,這樣 repository 層比較乾淨,也不會有過多、複雜的邏輯。
1 2 3 4 5 6 7 8 9 10 11 12
| private static async Task RunWithoutLua(IDatabase db) { var currentValue = await db.StringGetAsync(TestKey);
var newValue = Convert.ToInt32(currentValue) + 123; await db.StringSetAsync(TestKey, newValue);
var afterUpdatedValue = await db.StringGetAsync(TestKey); Console.WriteLine($"RunWithoutLua: After updated value: {afterUpdatedValue}"); }
|
執行結果
1 2
| RunWithLua: After updated value: 123 RunWithoutLua: After updated value: 246
|
兩者都能達到預期的結果,但把處理邏輯放在 lua 內會比較乾淨,且你只需要呼叫一次而已。
完整 Sample Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| using System; using System.Threading.Tasks; using StackExchange.Redis;
namespace ConsoleApp1 { public static class ConsoleApp1 { private const string RedisHost = "127.0.0.1:6379"; private const string TestKey = "TestRedisKey";
public static async Task Main() { using var conn = await ConnectionMultiplexer.ConnectAsync(RedisHost); var redisDb = conn.GetDatabase();
await redisDb.StringSetAsync(TestKey, 0);
await RunWithLua(redisDb); await RunWithoutLua(redisDb);
Console.WriteLine("Main end"); } private static async Task RunWithLua(IDatabase db) { var luaScript = @" local currentValue = redis.call('GET','[ReplaceKey]') local newValue = currentValue + 123 redis.call('SET', '[ReplaceKey]', newValue)";
luaScript = luaScript.Replace("[ReplaceKey]", TestKey);
await db.ScriptEvaluateAsync(luaScript);
var afterUpdatedValue = await db.StringGetAsync(TestKey); Console.WriteLine($"RunWithLua: After updated value: {afterUpdatedValue}"); }
private static async Task RunWithoutLua(IDatabase db) { var currentValue = await db.StringGetAsync(TestKey);
var newValue = Convert.ToInt32(currentValue) + 123; await db.StringSetAsync(TestKey, newValue);
var afterUpdatedValue = await db.StringGetAsync(TestKey); Console.WriteLine($"RunWithoutLua: After updated value: {afterUpdatedValue}"); } } }
|
docker-compose.yml
我很懶惰,都會寫在 docker-compose.yml 內,以後起、停 container 就能少打點指令。
1 2 3 4 5 6 7 8
| version: "3"
services: database: image: redis:latest container_name: local_redis ports: - 6379:6379
|