Den här sidan ger exempel på hur man skapar atomic Redis-transaktioner med ServiceStackRedis Service Stacks C# Redis Client
Hur man skapar anpassade atomoperationer i Redis #
En av huvuddragen hos Redis är förmågan att konstruera anpassade atomoperationer. Detta uppnås genom att använda Redis MULTI/EXEC/DISCARD-operationer.
ServiceStacks C# Redis-klient gör det enkelt att använda Redis-transaktioner genom att tillhandahålla en starkt typad IRedisTransaction (för strängar) och IRedisTypedTransaction
Att skapa en transaktion görs genom att anropa IRedisClient.CreateTransaction()
. Därifrån "köar" du alla operationer som du vill ska vara en del av transaktionen genom att använda en av IRedisTransaction.QueueCommand()
överbelastningar. Efter det kan du utföra alla operationer genom att anropa IRedisTransaction.Commit()
som kommer att skicka kommandot 'EXEC' till Redis-servern och exekvera alla kommandon i kö och bearbeta deras återuppringningar.
Om du inte anropar Commit()
före slutet av användningsblocket, Dispose()
metod kommer automatiskt att anropa Rollback()
som kommer att skicka kommandot 'DISCARD' som gör dig av med den aktuella transaktionen och återställer Redis-klientanslutningen till dess tidigare tillstånd.
Redis transaktionsexempel #
Nedan är ett enkelt exempel som visar hur du ställer Redis-operationer i kö med och utan återuppringning.
int callbackResult;
using (var trans = redis.CreateTransaction())
{
trans.QueueCommand(r => r.Increment("key"));
trans.QueueCommand(r => r.Increment("key"), i => callbackResult = i);
trans.Commit();
}
//The value of "key" is incremented twice. The latest value of which is also stored in 'callbackResult'.
Andra vanliga exempel #
Den fullständiga källkoden och andra vanliga exempel finns på sidan för vanliga transaktionstester.
[Test]
public void Can_Set_and_Expire_key_in_atomic_transaction()
{
var oneSec = TimeSpan.FromSeconds(1);
Assert.That(Redis.GetString("key"), Is.Null);
using (var trans = Redis.CreateTransaction()) //Calls 'MULTI'
{
trans.QueueCommand(r => r.SetString("key", "a")); //Queues 'SET key a'
trans.QueueCommand(r => r.ExpireKeyIn("key", oneSec)); //Queues 'EXPIRE key 1'
trans.Commit(); //Calls 'EXEC'
} //Calls 'DISCARD' if 'EXEC' wasn't called
Assert.That(Redis.GetString("key"), Is.EqualTo("a"));
Thread.Sleep(TimeSpan.FromSeconds(2));
Assert.That(Redis.GetString("key"), Is.Null);
}
[Test]
public void Can_Pop_priority_message_from_SortedSet_and_Add_to_workq_in_atomic_transaction()
{
var messages = new List<string> { "message4", "message3", "message2" };
Redis.AddToList("workq", "message1");
var priority = 1;
messages.ForEach(x => Redis.AddToSortedSet("prioritymsgs", x, priority++));
var highestPriorityMessage = Redis.PopFromSortedSetItemWithHighestScore("prioritymsgs");
using (var trans = Redis.CreateTransaction())
{
trans.QueueCommand(r => r.RemoveFromSortedSet("prioritymsgs", highestPriorityMessage));
trans.QueueCommand(r => r.AddToList("workq", highestPriorityMessage));
trans.Commit();
}
Assert.That(Redis.GetAllFromList("workq"),
Is.EquivalentTo(new List<string> { "message1", "message2" }));
Assert.That(Redis.GetAllFromSortedSet("prioritymsgs"),
Is.EquivalentTo(new List<string> { "message3", "message4" }));
}
Allt-i-ett exempel #
Detta och andra exempel kan hittas genom att titta på RedisTransactionTests.cs testsvit.
Här är ett allt-i-ett-exempel som kombinerar olika Redis-operationer inom en enda transaktion:
[Test]
public void Supports_different_operation_types_in_same_transaction()
{
var incrementResults = new List<int>();
var collectionCounts = new List<int>();
var containsItem = false;
Assert.That(Redis.GetString(Key), Is.Null);
using (var trans = Redis.CreateTransaction())
{
trans.QueueCommand(r => r.Increment(Key), intResult => incrementResults.Add(intResult));
trans.QueueCommand(r => r.AddToList(ListKey, "listitem1"));
trans.QueueCommand(r => r.AddToList(ListKey, "listitem2"));
trans.QueueCommand(r => r.AddToSet(SetKey, "setitem"));
trans.QueueCommand(r => r.SetContainsValue(SetKey, "setitem"), b => containsItem = b);
trans.QueueCommand(r => r.AddToSortedSet(SortedSetKey, "sortedsetitem1"));
trans.QueueCommand(r => r.AddToSortedSet(SortedSetKey, "sortedsetitem2"));
trans.QueueCommand(r => r.AddToSortedSet(SortedSetKey, "sortedsetitem3"));
trans.QueueCommand(r => r.GetListCount(ListKey), intResult => collectionCounts.Add(intResult));
trans.QueueCommand(r => r.GetSetCount(SetKey), intResult => collectionCounts.Add(intResult));
trans.QueueCommand(r => r.GetSortedSetCount(SortedSetKey), intResult => collectionCounts.Add(intResult));
trans.QueueCommand(r => r.Increment(Key), intResult => incrementResults.Add(intResult));
trans.Commit();
}
Assert.That(containsItem, Is.True);
Assert.That(Redis.GetString(Key), Is.EqualTo("2"));
Assert.That(incrementResults, Is.EquivalentTo(new List<int> { 1, 2 }));
Assert.That(collectionCounts, Is.EquivalentTo(new List<int> { 2, 1, 3 }));
Assert.That(Redis.GetAllFromList(ListKey), Is.EquivalentTo(new List<string> { "listitem1", "listitem2" }));
Assert.That(Redis.GetAllFromSet(SetKey), Is.EquivalentTo(new List<string> { "setitem" }));
Assert.That(Redis.GetAllFromSortedSet(SortedSetKey), Is.EquivalentTo(new List<string> { "sortedsetitem1", "sortedsetitem2", "sortedsetitem3" }));
}