1. 程式人生 > >Redis學習筆記~Redis事務機制與Lind.DDD.Repositories.Redis事務機制的實現

Redis學習筆記~Redis事務機制與Lind.DDD.Repositories.Redis事務機制的實現

回到目錄

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

回到目錄