Tato stránka poskytuje příklady, jak vytvořit atomické transakce Redis pomocí klienta C# Redis Client ServiceStackRedis Service Stack
Jak vytvořit vlastní atomické operace v Redis #
Jedním z hlavních rysů Redis je schopnost konstruovat vlastní atomové operace. Toho je dosaženo využitím operací Redis MULTI/EXEC/DISCARD.
C# Redis Client služby ServiceStack usnadňuje používání transakcí Redis tím, že poskytuje rozhraní API se silným typem IRedisTransaction (pro řetězce) a IRedisTypedTransaction
Vytvoření transakce se provádí voláním IRedisClient.CreateTransaction()
. Odtud zařadíte všechny operace, které chcete být součástí transakce, do fronty pomocí jednoho z IRedisTransaction.QueueCommand()
přetížení. Poté můžete provést všechny operace voláním IRedisTransaction.Commit()
který odešle příkaz 'EXEC' na server Redis, který provede všechny příkazy ve frontě a zpracuje jejich zpětná volání.
Pokud nevoláte Commit()
před koncem bloku using, Dispose()
metoda automaticky vyvolá Rollback()
to odešle příkaz 'DISCARD', který odstraní aktuální transakci a resetuje připojení klienta Redis zpět do předchozího stavu.
Příklady transakcí Redis #
Níže je jednoduchý příklad ukazující, jak zařadit operace Redis do fronty s a bez zpětného volání.
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'.
Další běžné příklady #
Úplný zdrojový kód a další běžné příklady lze nalézt na stránce běžných testů transakcí.
[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" }));
}
Příklad vše v jednom #
Tento a další příklady lze nalézt v testovací sadě RedisTransactionTests.cs.
Zde jsou příklady all-in-one kombinující různé operace Redis v rámci jedné transakce:
[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" }));
}