zoukankan      html  css  js  c++  java
  • ABP中使用Redis Cache(2)

         上一篇讲解了如何在ABP中使用Redis Cache,虽然能够正常的访问Redis,但是Redis里的信息无法同步更新。本文将讲解如何实现Redis Cache与实体同步更新。要实现数据的同步更新,我们能够想到的最基本、最简单、也是复杂的方法:在每一个增、删、改的方法里添加同步缓存的代码,说它最简单,是因为技术实现非常简单,就是在每一个方法里多加一句代码;说它复杂,是因为这样的写的话,会出现很多重复的代码,并且容易出现遗漏,维护起来很不方便。那么有没有一种更简单的方式呢,在数据出现变化后,触发一个事件,主动通知订阅者执行相关操作呢?答案是肯定的,我们可以通过注册领域事件来实现,在ABP中,实体增加、删除、修改后会触发相关事件,只要注册就可以了。要注册事件,有两种方式可以实现,第一是自动注册,实现IEventHandler就可以了,ABP会自动注册;第二是通过IEventBus的Register方法手动注册。ABP中推荐使用自动注册的方式实现,本文也会采用第一种方式实现。下面我们就来看具体的实现方式,首先增加一个处理缓存同步的接口ICacheSyncService,代码如下(本文的代码是在上一篇的基础之上编写的):

    作者:loyldg 出处:http://www.cnblogs.com/loyldg/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:loyldg@126.com 联系我,非常感谢。

    ICacheSyncService.cs

     public interface ICacheSyncService
        {
            void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
            void Remove<TEntity>(int id) where TEntity : class, IEntity<int>;
            void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
        }
    View Code

    CacheSyncService.cs

    public class CacheSyncService : ICacheSyncService, ISingletonDependency
        {
            public ICacheService CacheService { get; set; }
    
            public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                CacheService.Set(entity.Id, entity);
            }
    
            public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
            {
                CacheService.Remove<int, TEntity>(id);
            }
    
            public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                CacheService.Set(entity.Id, entity);
            }
        }

    第二增加一个处理实体事件的泛型基类EntityChangedHandlerBase<TEntity>,代码如下:

    public abstract class EntityChangedHandlerBase<TEntity>:
            ISingletonDependency,
            IEventHandler<EntityCreatedEventData<TEntity>>,
            IEventHandler<EntityDeletedEventData<TEntity>>,
            IEventHandler<EntityUpdatedEventData<TEntity>>
            where TEntity : class, IEntity<int>
        {
            public ICacheSyncService CacheSyncService { get; set; }
    
            public virtual void HandleEvent(EntityCreatedEventData<TEntity> eventData)
            {
                CacheSyncService.Add(eventData.Entity);
            }
    
            public virtual void HandleEvent(EntityDeletedEventData<TEntity> eventData)
            {
                CacheSyncService.Remove<TEntity>(eventData.Entity.Id);
            }
    
            public virtual void HandleEvent(EntityUpdatedEventData<TEntity> eventData)
            {
                CacheSyncService.Update(eventData.Entity);
            }
        }

    第三,增加一个需要进行缓存同步的实体类,继承自EntityChangedHandlerBase<TEntity>就可以了,不需要编写任何代码,如果有特殊情况,可以重新HandleEvent方法,代码如下:

    public class ArticleChangedHandler : EntityChangedHandlerBase<Article>
        {
            
        }
    View Code

    至此,缓存同步的全部代码已编写完成,我们运行来看看效果:

    我们添加文章后,什么操作也不做,直接到Redis里查看是否有新增的数据,如果有新增的数据表示缓存能够自动更新了(删除和修改是一样的,这里就不编写相关代码了),直接看单元测试代码。

    public class CacheSync_Tests : UsingRedisInAbpTestBase
        {
             [Fact]
            public void Test_Entity_Changed_Event()
            {
                 LoginAsHostAdmin();
                 var title = "unit_test";
                 var articleId = 0;
                 var service = Resolve<TestCacheSyncService>();
                 service.IsCreatedEventFired.ShouldBeFalse();
                 service.IsUpdatedEventFired.ShouldBeFalse();
                 service.IsDeletedEventFired.ShouldBeFalse();
                 
                 //新增文章测试
                 UsingDbContext(c =>c.Articles.Add(new Article {Title = title}));
                 
                 service.IsCreatedEventFired.ShouldBe(true);
    
                 //更新文章测试
                 UsingDbContext(c =>
                 {
                     var article=c.Articles.First();
                     c.Articles.Attach(article);
                     article.Title = "new_title";
                 });
                 service.IsUpdatedEventFired.ShouldBe(true);
    
                 //删除文章测试
                 UsingDbContext(c =>
                 {
                     var article = c.Articles.First();
                     c.Articles.Remove(article);                 
                 });
                 service.IsDeletedEventFired.ShouldBe(true);
            }
        }

    TestSyncCache.cs代码:

     public class TestCacheSyncService : ICacheSyncService
        {
            public bool IsCreatedEventFired { get; set; }
            public bool IsDeletedEventFired { get; set; }
            public bool IsUpdatedEventFired { get; set; }
            public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                IsCreatedEventFired = true;
                
            }
    
            public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
            {
                IsDeletedEventFired = true;
    
            }
    
            public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                IsUpdatedEventFired = true;
            }
        }  
    View Code

    通过以上方式已实现了ABP中Redis缓存的读取和设置,也实现了缓存的同步更新,如果要在ABP中使用其他缓存也是一样的,只需要把缓存实现部分换成其他缓存就行。本文的所有源代码下载地址:

    https://files.cnblogs.com/files/loyldg/UsingRedisInAbp_2.src.rar

    作者:loyldg 出处:http://www.cnblogs.com/loyldg/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:loyldg@126.com 联系我,非常感谢。

    作者:loyldg
    出处:http://www.cnblogs.com/loyldg/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。如有问题,可以邮件:loyldg@126.com  联系我,非常感谢。

  • 相关阅读:
    poj 1026 Cipher
    python中的global
    基于DL的文本分类综述
    K近邻算法学习
    聚类评价指标学习
    pytorch自动求导学习
    反向传播的推导
    二分搜索常用【转载】
    《Attention is all you need》论文学习
    5-28日|5-30日
  • 原文地址:https://www.cnblogs.com/loyldg/p/using-redis-in-abp-2.html
Copyright © 2011-2022 走看看