当前位置: 首页>数据库>正文

本地redis文件默认用户名 redis本地化

1.简介

    在大型企业网站项目中,由于高并发等因素,常常需要集成一些中间件,而缓存几乎是必不可少的,因为它对于性能提升非常巨大,比如说redis。但是我们不仅仅需要redis,因为redis存放的是可变的用户数据。我们常常会需要一种东西来存放我们系统的一些配置,这些数据不是动态的,基本不会改变的。如果我们把这些数据放入redis诚然是一个选择,但是当我们需要更改我们的配置时,要去redis更改,这是非常不方便的,redis没有控制台(当然可以自己做一个,但是不如接下来介绍的方便)。所以本地缓存就被大佬们造出来了。在项目上的做法是:把一些配置,存到数据库。然后用本地缓存去读取,这样当使用的时候,直接从本地缓存中拿,不用再去访问数据库,不仅提高了效率,还减轻了数据库的压力。不过却占用了内存空间。所以本地缓存不应该存储过多的数据(这里的过多一般指大于1万条,视情况而定)。

2.实现方案

    首先看看我们对本地缓存的功能要求:

        1.要有一个本地缓存管理器,管理着所有的缓存

        2.本地缓存需要自动动态刷新,来保持和数据库数据的一致性

        3.本地缓存要求不同系统能存储不同类型的数据

        4.本地缓存要求能适配项目内所有的系统

    第1点,增加一个缓存管理器非常的简单,就增加一个LocalCacheManager来管理所有的缓存即可。

    第2点,可以使用线程来刷新。每隔一段时间,请求数据库,同步数据。

    第3点,对于存储所有类型的数据,简单啊,泛型。

    第4点,要求能适配。所以说设计模式还是要好好学一下的。我们可以用模板方法模式,我给你规定死了抽象方法,你就按照自己的需求实现就行了,其它的你不用管,我提供模板方法。

    好了,不纸上谈兵了,看看具体的实现。

3.实现

    先看抽象的本地缓存类,注释非常详细

/**
 * 抽象缓存类
 */
public abstract class AbstractCache<V> {

    //用于存储数据
    private V data;

    //在构造方法中,就把该缓存交给缓存管理器管理
    public AbstractCache(String cacheName){
        LocalCacheManage.add(cacheName,this);
    }

    //模板方法,final 不能改
    protected final V get(){
        if(null == this.data){
            this.data = load();
        }

        return this.data;
    }

    //模板方法
    protected final void refresh(){
        this.data = load();
    }

    //各子系统自行实现该抽象方法
    protected abstract V load();
}

    在看看缓存管理器

/**
 * 缓存管理器
 */
public class LocalCacheManage {

    //可以看作是缓存池的概念,存储了本系统所有的缓存
    private static Map<String, AbstractCache> caches = new HashMap<>();

    static {
        Thread refreshThread = new Thread(new RefreshThread());
        refreshThread.setName("cache_refresh_thread");
        //refreshThread.setDaemon(true);
        // 在这里不设为守护进程,因为main方法执行完了,如果剩下的所有线程都是守护线程,那么jvm会直接退出!
        // 但是在web服务中可以设置为守护线程
        refreshThread.start();
    }

    //把缓存添加到缓存池
    public static void add(String cacheName, AbstractCache abstractCache) {
        caches.put(cacheName,abstractCache);
    }

    //获取缓存池
    public static Map<String, AbstractCache> get(){
        return caches;
    }


    //线程动态刷新
    static class RefreshThread implements Runnable{

        @Override
        public void run() {

            while (true){
               try {
                    //实验起见,设置成1S,实际项目中至少1分钟以上刷新一次,否则数据库压力暴增,导致服务挂掉
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                //遍历刷新缓存池中的所有缓存
                if(null != caches && caches.size() > 0){
                    for(Map.Entry<String, AbstractCache> cacheEntry : caches.entrySet()){
                        cacheEntry.getValue().refresh();//这就是模板方法的好处
                    }
                }
            }
        }
    }

}

    main方法

public class Main {

    public static void main(String[] args) {
        //==================第一个缓存==================
        AbstractCache<List<String>> conf1 = new AbstractCache<List<String>>("confCache1") {
            @Override
            protected List<String> load() {
                List<String> result = new ArrayList<String>();

                //模拟从数据库获取数据,实际开发中可以进行数据库操作
                System.out.println("我从数据库获得最新数据啦1");
                result.add("conf1");
                result.add("conf2");
                return result;
            }
        };
        //查看缓存中的数据
        AbstractCache confCache1 = LocalCacheManage.get().get("confCache1");
        List<String> list1 = (List<String>) confCache1.get();
        System.out.println(list1.get(0));

        //========================另一个缓存===============
        AbstractCache<Map<String, Object>> conf2 = new AbstractCache<Map<String, Object>>("confCache2") {
            @Override
            protected Map<String, Object> load() {
                Map<String, Object> map = new HashMap<>();

                //模拟从数据库获取数据,实际开发中可以进行数据库操作
                System.out.println("我从数据库获得最新数据啦2");
                map.put("conf3","conf3333");
                map.put("conf4","conf4444");
                return map;
            }
        };
        AbstractCache confCache2 = LocalCacheManage.get().get("confCache2");
        Map<String, Object> map = (Map<String, Object>) confCache2.get();
        System.out.println(map.get("conf4"));


    }
}


//输出
我从数据库获得最新数据啦1
conf1
我从数据库获得最新数据啦2
conf4444
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
我从数据库获得最新数据啦1
我从数据库获得最新数据啦2
。。。。。一直执行下去,除非手动关闭jvm

4.分析

    上面的代码注释都非常清晰,下面就讲解一些设计的精妙之处。

    首先看AbstractCache,它使用了泛型,这样,放什么类型的都可以,Map,List,甚至是一个单一Object也可以,灵活。

    再看AbstractCache的 load() 方法,这是一个抽象方法,它的作用就是为了获得数据,但是每个系统要的数据不一样啊,怎么办,声明成抽象的就行了,让子系统自己去实现。最巧妙的就是再它的两个模板方法,利用了load()方法。做到了 “你做好你的事,我做好我的事”。

    再看AbstractCache的构造方法,直接把自己添加到了本地缓存管理器,只要你new出对象,就得给我进来,我就负责你的生命周期。

    再看 LocalCacheManager,这个类有一个缓存池,就是用来存放所有的本地缓存的,就可以来管理这些缓存。并提供一个获取所有缓存的方法get()。最主要的是它的内置线程,自动刷新。遍历缓存池,对每一个缓存进行刷新,如何刷新? 还是要靠模板方法模式,直接由模板方法提供,进行统一式刷新。

5.总结

    至此,我们实现了达到上述4点要求的缓存,是不是有点像SpringCluod的动态配置刷新,哈哈。虽然不知道大佬是不是从源码中学的,但是我是从大佬的源码中学的!虽然不知道这个有没有更好的方案,但是这个方案已经让我学习到了很多。


https://www.xamrdz.com/database/6kp1935716.html

相关文章: