回到目錄
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
支付寶掃一掃,為大叔打賞!
