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#代碼團隊的不段進步,也是我們這些程序員喜愛它的原因之一,畢竟人都有個膩的時候,多多改善,對自己,對他人都是件不錯好事!
文章列表