Тази страница предоставя примери за това как да създавате атомарни транзакции Redis с C# Redis клиента на ServiceStackRedis Service Stack
Как да създадете персонализирани атомни операции в Redis #
Една от основните характеристики на Redis е способността да се конструират персонализирани атомни операции. Това се постига чрез използване на операциите MULTI/EXEC/DISCARD на Redis.
C# Redis Client на ServiceStack улеснява използването на Redis транзакции, като предоставя строго типизирани IRedisTransaction (за низове) и IRedisTypedTransaction
Създаването на транзакция се извършва чрез извикване на IRedisClient.CreateTransaction()
. Оттам вие "подреждате" в опашка всички операции, които искате да бъдат част от транзакцията, като използвате един от IRedisTransaction.QueueCommand()
претоварвания. След това можете да изпълните всички операции, като извикате IRedisTransaction.Commit()
което ще изпрати командата 'EXEC' до сървъра на Redis, изпълнявайки всички команди в опашката и обработвайки техните обратни извиквания.
Ако не извикате Commit()
преди края на блока using, Dispose()
метод автоматично ще извика Rollback()
това ще изпрати командата 'DISCARD' за премахване на текущата транзакция и нулиране на клиентската връзка на Redis обратно към предишното й състояние.
Примери за транзакции на Redis #
По-долу е даден прост пример, показващ как да поставите в опашка операции на Redis със и без обратно извикване.
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'.
Други често срещани примери #
Пълният изходен код и други често срещани примери могат да бъдат намерени на страницата за общи тестове за транзакции.
[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" }));
}
Пример за всичко в едно #
Този и други примери можете да намерите, като разгледате тестовия пакет RedisTransactionTests.cs.
Ето примери всичко в едно, комбиниращи различни операции на Redis в рамките на една транзакция:
[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" }));
}