Redis/ServiceStack客户端事务异常

3
我对Redis还比较陌生,正在进行评估。我使用了这里的Redis服务器:https://github.com/downloads/dmajkic/redis/redis-2.4.5-win32-win64.zip
我也使用了以下配置来运行服务器: port 6379 timeout 300 save 900 1 save 300 10 save 60 10000 loglevel debug logfile stdout databases 1 maxclients 32 maxmemory 2147483648
我正在尝试使用ServiceStack客户端(ServiceStack-ServiceStack.Redis-4add28a)运行以下代码:
这是我的代码。
public void InsertInsideTransaction(bool shouldTransactionRollback)
{
    RedisClient transClient = new RedisClient("localhost");

    ClearAll();
    using (var trans = transClient.CreateTransaction())
    {
        trans.QueueCommand(r => 
            {
                var redisUsers = r.GetTypedClient<User>();
                var sacha = new User { Id = redisUsers.GetNextSequence(), Name = "Sacha Barber" };
                redisUsers.Store(sacha);
                //redisUsers.Dispose();
            });

        //commit or rollback based on incoming flag
        if (shouldTransactionRollback)
            trans.Rollback();
        else
            trans.Commit();

        IList<User> users = Users();
        Console.WriteLine(string.Format("InsertInsideTransaction : There are currently {0}, Users", users.Count()));
    }




}

用户看起来像这样(来自ServiceStack中的示例之一)

public class User
{
    public User()
    {
        this.BlogIds = new List<long>();
    }

    public long Id { get; set; }
    public string Name { get; set; }
    public List<long> BlogIds { get; set; }
}

当我尝试提交事务时,会出现以下异常:
Unknown reply on multi-request: 43QUEUED, sPort: 60793, LastCommand: EXEC
该异常发生在 ServiceStack.Redis.RedisNativeClient.CreateResponseError(String error) 方法中,位于 C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\RedisNativeClient_Utils.cs 的第 146 行。 出现异常的原因是 ServiceStack.Redis.RedisNativeClient.ReadMultiDataResultCount() 方法未能正确读取多个结果。此方法在 C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\RedisNativeClient_Utils.cs 的第 578 行中定义。 进一步查看代码,可以发现 ServiceStack.Redis.Pipeline.QueuedRedisOperation.ProcessResult() 方法也出了问题,该方法在 C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\Pipeline\QueuedRedisOperation.cs 的第 169 行中定义。 最终,ServiceStack.Redis.RedisTransaction.Commit() 方法在 C:\Users\barbers\Desktop\Downloads\ServiceStack-ServiceStack.Redis-4add28a\ServiceStack-ServiceStack.Redis-4add28a\src\ServiceStack.Redis\Transaction\RedisTransaction.cs 的第 100 行中抛出异常。 此外,在 C:\Users\barbers\Desktop\DocumentDBs\DocumentDB.Redis\RedisMessAround.cs 第 63 行和 C:\Users\barbers\Desktop\DocumentDBs\DocumentDB.Redis\Program.cs 第 45 行和第 18 行也引用了出错的类和方法。
于是,我查看了 ServiceStack-ServiceStack.Redis-4add28a 中自带的“RedisTransactionTests”代码,并进行了修改。
public class User
{
    public User()
    {
        this.BlogIds = new List<long>();
    }

    public long Id { get; set; }
    public string Name { get; set; }
    public List<long> BlogIds { get; set; }
}

我有一段修改过的测试代码,

[Test]
[TestCase(true)]
[TestCase(false)]
public void TestUserTrans(bool shouldTransactionRollback)
{
    int count = 0;


    IRedisTransaction trans = Redis.CreateTransaction();

    try
    {
        trans.QueueCommand(r =>
        {
            var redisUsers = r.GetTypedClient<User>();
            var sacha = new User { Id = redisUsers.GetNextSequence(), Name = "Sacha Barber" };
            redisUsers.Store(sacha);
        });

        //commit or rollback based on incoming flag
        if (shouldTransactionRollback)
            trans.Rollback();
        else
            trans.Commit();
    }
    catch (Exception ex)
    {

    }

    IList<User> users = Users();
    count = users.Count();
    Console.WriteLine(string.Format("TestUserTrans : There are currently {0}, Users", users.Count()));
    if (shouldTransactionRollback)
        Assert.That(count == 0);
    else
        Assert.That(count == 1);

}

在这里,异常似乎被完全吞噬了。

我到底做错了什么?

1个回答

5

您不能在同一事务中读取和使用结果。

请确保先阅读关于MULTI/EXEC的工作原理: http://redis.io/topics/transactions

它有效地通过将多个命令批处理为单个复合命令来运行,并由Redis一次性发送和处理。

在您的示例中,您正在尝试使用redisUsers.GetNextSequence()进行读取并在排队的事务中使用结果。 您不能这样做,相反,如果您想在排队的事务中使用变量,则需要先读取它:

var sacha = new User { 
    Id = Redis.As<User>().GetNextSequence(), Name = "Sacha Barber" };

trans.QueueCommand(r =>  r.As<User>().Store(sacha));

注意:.As<T>()r.GetTypedClient<T>() 的简写。
为了保证读取的事务完整性,您可以发出 WATCH 命令来指定事务将使用的所有变量。然后,如果在事务完成之前修改了其中任何一个变量,则会引发异常,并且不会执行任何排队的操作。

啊太棒了,我告诉过你我是新手。这解决了我的问题,我会确保阅读你发布的链接。非常感谢。 - sacha barber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接