• 在库存服务中实现缓存与数据库双写一致性保障方案(一)


    库存服务和数据库双写一致性方案

    库存服务架子搭起来了,访问数据都是ok的,解决方案都分析过了。
    我们需要把思路进行代码实现。
    1.系统启动的时候初始化线程池和相关内存队列。
    2.两种请求对象的封装,1种发生交易进行库存更新,2是读库存可能在商品页面读的时候先读缓存
    ,如果缓存里面它正好清空了,发送读请求到库存服务里来,读请求过来的时候,会申请把数据库最新值查询出来更新到缓存中。
    3.封装好之后封装操作逻辑,对请求对象执行service,封装controller,扔给异步执行service,根据标识,根据商品标识取出hash值,
    对hash值取模,扔到内存队列里面去,监听内存队列线程池里的线程,消费线程。
    把对同一个商品更新库存,读取库存更新缓存进行串行化。
    4.读请求的去重优化,一个队列里,对一个商品的库存的数据库更新操作已经在内存队列中了,
    对商品库存的读取操作,要求读取库存数据库数据,然后更新到缓存中,一下子过来多个读,
    这多个读其实只要有一个读请求操作压到队列里就可以了,其他的读操作全部都wait,读请求的操作刷新缓存就可以读到缓存中的最新数据了。
    5.空数据的过滤优化,如果读请求发现redis缓存中没有数据,就会发送读请求给库存服务,
    此时缓存中为空,可能因为写请求先删除了缓存,也可能数据库中压根没有这条数据。如果是数据库压根没有这条数据的场景,
    就不应该将读请求操作压入队列中,而是直接返回空就可以了。

    这两个操作都是为了减少内存队列中的请求积压,内存队列中积压的请求越多,就可能导致每个读请求hang住的时间越长,也可能导致多个读请求被hang住,尽量把一定要执行的压倒内存队列中。

    ----------------------------------------------start-------------------------

    注册监听器:

    class Application中编写注册监听器...
       /**
         * 注册监听器
         * @return
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Bean
        public ServletListenerRegistrationBean servletListenerRegistrationBean() {
            ServletListenerRegistrationBean servletListenerRegistrationBean =
                    new ServletListenerRegistrationBean();
            servletListenerRegistrationBean.setListener(new InitListener());
            return servletListenerRegistrationBean;
        }
    

      

    内部静态类的方式,初始化单例
    package com.roncoo.eshop.thread;
    
    /**
     * 线程池
     */
    public class MyThreadPool {
    
        /**
         * 内部静态类的方式,初始化单例
         */
        private static class Singleton {
    
            private static MyThreadPool instance;
    
            static {
                instance = new MyThreadPool();
            }
    
    
    
            public static MyThreadPool getInstance() {
                return instance;
            }
    
        }
        /**
         * jvm的机制去保证多线程并发安全
         *
         * 内部类的初始化,一定只会发生一次,不管多少个线程并发去初始化
         *
         * @return
         */
        public static MyThreadPool getInstance() {
            return Singleton.getInstance();
        }
    
        public MyThreadPool() {
            System.out.println("MyThreadPool构造器初始化...");
        }
    
    
    }
    

      

     将初始化的操作交给了监听器。

     创建一个req的请求接口

    修改如下,当项目启动后,初始化MyThreadPool,然后就把list中的数据添加了10个ArrayBlockingQueue<Request>

    package com.roncoo.eshop.thread;
    
    import com.roncoo.eshop.req.Request;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.Callable;
    
    /**
     * 执行请求的工作线程
     */
    public class WorkerThread implements Callable<Boolean> {
    
        private ArrayBlockingQueue<Request> queue;
    
        public WorkerThread(ArrayBlockingQueue<Request> queue) {
            this.queue = queue;
        }
    
    
        @Override
        public Boolean call() throws Exception {
            return true;
        }
    }
    

      

    把queue和thread绑定在一起,一个queue对应一个thread,设置到线程里面去,就会执行这个线程,
    其实每个线程都会变成后台线程while true一下,10个线程上来就会把线程池填满。

  • 相关阅读:
    08 突破512字节的限制 下
    瑞芯微/全志CPU型号
    labview介绍
    07 突破512字节的限制 中
    1-20安卓自学
    1-19安卓自学
    1-18安卓自学
    关系抽取---远程监督 ---《DSGAN: Generative Adversarial Training for Distant Supervision Relation Extraction》
    关系抽取--- 远程监督---《Reinforcement Learning for Relation Classification from Noisy Data》
    关系抽取 --- 远程监督 ---《DIAG-NRE: A Neural Pattern Diagnosis Framework for Distantly Supervised Neural Relation Extraction》
  • 原文地址:https://www.cnblogs.com/q1359720840/p/15864092.html
Copyright © 2020-2023  润新知