Redis學習筆記~Redis事(shi)務機制(zhi)(zhi)與Lind.DDD.Repositories.Redis事(shi)務機制(zhi)(zhi)的實現
Redis本身支持事務,這就是SQL數據庫有Transaction一樣,而Redis的驅動也支持事務,這在ServiceStack.Redis就有所體現,它也是目前最受業界認可的Redis驅動,而它將Redis的事務機制(MULTI,Exec,Watch等(deng))封裝成了比較友(you)好(hao)的實現(xian)方式,如下(xia)面的代碼
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(); // 提交(jiao)事務 } }
當(dang)然上(shang)(shang)面漂(piao)亮的(de)代碼有一(yi)(yi)些功(gong)勞要歸于C#漂(piao)亮的(de)語法(fa),你在JAVA里可(ke)以很難寫出如此漂(piao)亮的(de)東(dong)西,當(dang)然上(shang)(shang)面的(de)代碼是ServiceStack.Redis為(wei)我們封裝的(de),平時我們可(ke)以直(zhi)接(jie)使用,現在再說(shuo)一(yi)(yi)下(xia)大叔Lind.DDD框(kuang)架里的(de)RedisRepository對它(ta)的(de)支持!
如果大叔RedisRepository想支持redis事務,前提:倉儲的IRedisClient必須與產生事務的IRedisClient是同一個對象,否則redis事務在大叔框架里(li)不會起作用
實現方法:
一 RedisRepository<T>實現SetDataContext方法,將IRedisClient從外面(mian)傳(chuan)入,這樣可(ke)以保存事務的和倉(cang)儲的用的是(shi)一個對(dui)象
public void SetDataContext(object db) { try { //手動(dong)Redis數(shu)據庫(ku)對象,在redis事務時啟用 redisDB = (IRedisClient)db; redisTypedClient = redisDB.GetTypedClient<TEntity>(); table = redisTypedClient.Lists[typeof(TEntity).Name]; } catch (Exception) { throw new ArgumentException("redis.SetDataContext要求db為IRedisClient類型(xing)"); } }
二 添(tian)加基(ji)于Redis的(de)事務(wu)管理者,讓大叔倉儲與事務(wu)更好的(de)結(jie)合,方便開發(fa)人員的(de)使用
/// <summary> /// Redis事務管理機制 /// </summary> public class RedisTransactionManager { /// <summary> /// 事務塊(kuai)處理(li) /// </summary> /// <param name="redisClient">當前redis庫</param> /// <param name="action">事(shi)務(wu)中的動作</param> public static void Transaction(IRedisClient redisClient, Action action) { using (IRedisTransaction IRT = redisClient.CreateTransaction()) { try { action(); IRT.Commit(); } catch (Exception) { IRT.Rollback(); } } } }
三 在(zai)領域代(dai)碼中,我們通(tong)常可以這樣使用大叔redis的事務塊(kuai),看代(dai)碼
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" }); });
這樣,大叔(shu)框架就支(zhi)(zhi)持了Redis的事(shi)務,希望MongoDB早日也能對事(shi)務進(jin)行支(zhi)(zhi)持,到那時(shi),大叔(shu)將(jiang)會為它提供一(yi)種(zhong)實(shi)現機制,呵(he)呵(he)!
下面(mian)是大叔對分布式多數(shu)據(ju)源(yuan)事(shi)務的測試,可以實現SQLSERVER與Redis的事(shi)務共存機制,下面(mian)是代碼
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(); } });
上面代(dai)碼我們還能進(jin)行一些封裝,一些修改,讓它(ta)支持redis和sql兩種事務,使(shi)用.net4.5的默認參數,可以省去一個方法的重載,代(dai)碼又便(bian)得(de)越來越簡潔了!
/// <summary> /// 事務塊處理 /// </summary> /// <param name="redisClient">當前(qian)redis庫</param> /// <param name="redisAction">Redis事(shi)務中的動作</param> /// <param name="sqlAction">Sql事務中(zhong)的動作</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(); } } }
代碼在調用(yong)時(shi),我(wo)們(men)很方便,簡單!
Lind.DDD.RedisClient.RedisTransactionManager.Transaction(redisClient, () => { redis.Insert(new User { UserName = "gogod111" }); redis.Insert(new User { UserName = "gogod211" }); }, () => { userRepository.Insert(new UserInfo { UserName = "zzl3" }); });
對(dui)于C#代碼團(tuan)隊(dui)的(de)(de)不段(duan)進(jin)步,也是我們這些程序員喜愛它的(de)(de)原因之一,畢竟人都(dou)(dou)有個膩的(de)(de)時候,多多改(gai)善,對(dui)自己(ji),對(dui)他人都(dou)(dou)是件(jian)不錯好事(shi)!