回到目录
Redis本身支持事务,这就是SQL数据库有Transaction一样,而Redis的驱动也支持事务,这在ServiceStack.Redis就有所体现,它也是目前最受业界认可的Redis驱动,而它将Redis的事务机制(
MULTI
,Exec,Watch等)封装成了比较友好的实现方式,如下面的代码 using (IRedisClient RClient = prcm.GetClient())
{
using (IRedisTransaction IRT = RClient.CreateTransaction())
{
IRT.QueueCommand(r => r.AddItemToList("zzl", "2"));
IRT.QueueCommand(r => r.AddItemToList("lr", "2"));
IRT.Commit(); // 提交事务
}
}
当然上面漂亮的代码有一些功劳要归于C#漂亮的语法,你在JAVA里可以很难写出如此漂亮的东西,当然上面的代码是ServiceStack.Redis为我们封装的,平时我们可以直接使用,现在再说一下大叔Lind.DDD框架里的RedisRepository对它的支持!
如果大叔RedisRepository想支持redis事务,前提:仓储的IRedisClient必须与产生事务的IRedisClient是同一个对象,否则redis事务在大叔框架里不会起作用
实现方法:
一 RedisRepository<T>实现SetDataContext方法,将IRedisClient从外面传入,这样可以保存事务的和仓储的用的是一个对象
public void SetDataContext(object db)
{
try
{
//手动Redis数据库对象,在redis事务时启用
redisDB = (IRedisClient)db;
redisTypedClient = redisDB.GetTypedClient<TEntity>();
table = redisTypedClient.Lists[typeof(TEntity).Name];
}
catch (Exception)
{
throw new ArgumentException("redis.SetDataContext要求db为IRedisClient类型");
}
}
二 添加基于Redis的事务管理者,让大叔仓储与事务更好的结合,方便开发人员的使用
/// <summary>
/// Redis事务管理机制
/// </summary>
public class RedisTransactionManager
{
/// <summary>
/// 事务块处理
/// </summary>
/// <param name="redisClient">当前redis库</param>
/// <param name="action">事务中的动作</param>
public static void Transaction(IRedisClient redisClient, Action action)
{
using (IRedisTransaction IRT = redisClient.CreateTransaction())
{
try
{
action();
IRT.Commit();
}
catch (Exception)
{
IRT.Rollback();
}
}
}
}
三 在领域代码中,我们通常可以这样使用大叔redis的事务块,看代码
var redis = new Lind.DDD.Repositories.Redis.RedisRepository<User>();
IRedisClient redisClient = Lind.DDD.RedisClient.RedisManager.GetClient();
redis.SetDataContext(redisClient);
Lind.DDD.RedisClient.RedisTransactionManager.Transaction(redisClient, () =>
{
redis.Insert(new User { UserName = "gogod111" });
redis.Insert(new User { UserName = "gogod211" });
});
这样,大叔框架就支持了Redis的事务,希望MongoDB早日也能对事务进行支持,到那时,大叔将会为它提供一种实现机制,呵呵!
下面是大叔对分布式多数据源事务的测试,可以实现SQLSERVER与Redis的事务共存机制,下面是代码
Lind.DDD.RedisClient.RedisTransactionManager.Transaction(redisClient, () =>
{
redis.Insert(new User { UserName = "gogod111" });
redis.Insert(new User { UserName = "gogod211" });
using (var trans = new TransactionScope())
{
userRepository.Insert(new UserInfo { UserName = "zzl3" });
trans.Complete();
}
});
上面代码我们还能进行一些封装,一些修改,让它支持redis和sql两种事务,使用.net4.5的默认参数,可以省去一个方法的重载,代码又便得越来越简洁了!
/// <summary>
/// 事务块处理
/// </summary>
/// <param name="redisClient">当前redis库</param>
/// <param name="redisAction">Redis事务中的动作</param>
/// <param name="sqlAction">Sql事务中的动作</param>
public static void Transaction(IRedisClient redisClient, Action redisAction, Action sqlAction = null)
{
using (IRedisTransaction IRT = redisClient.CreateTransaction())
{
try
{
redisAction();
if (sqlAction != null)
{
using (var trans = new TransactionScope())
{
sqlAction();
trans.Complete();
}
}
IRT.Commit();
}
catch (Exception)
{
IRT.Rollback();
}
}
}
代码在调用时,我们很方便,简单!
Lind.DDD.RedisClient.RedisTransactionManager.Transaction(redisClient, () =>
{
redis.Insert(new User { UserName = "gogod111" });
redis.Insert(new User { UserName = "gogod211" });
}, () =>
{
userRepository.Insert(new UserInfo { UserName = "zzl3" });
});
对于C#代码团队的不段进步,也是我们这些程序员喜爱它的原因之一,毕竟人都有个腻的时候,多多改善,对自己,对他人都是件不错好事!
作者:仓储大叔,张占岭,
荣誉:微软MVP
QQ:853066980
支付宝扫一扫,为大叔打赏!
