このページでは、ServiceStackRedis Service StackのC#Redisクライアントを使用してアトミックRedisトランザクションを作成する方法の例を示します
Redisでカスタムアトミック操作を作成する方法#
Redisの主な機能の1つは、カスタムアトミック操作を構築する機能です。これは、RedisのMULTI / EXEC/DISCARD操作を利用することで実現されます。
ServiceStackのC#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" }));
}