Redis牛客网学习笔记(二)

251 阅读7分钟

1. 记录帖子的阅读数量

image.png

1.1 业务代码

public class PostService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();
    
    // 增加帖子的阅读数量
    public void increaseReadCount(int postId) {
        String key = "post:read:count:" + postId;
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.incr(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 增加帖子的点赞数量
    public void increaseLikeCount(int postId) {
        String key = "post:like:count:" + postId;
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.incr(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 减少帖子的点赞数量
    public void decreaseLikeCount(int postId) {
        String key = "post:like:count:" + postId;
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.decr(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.2 测试代码

public class ServiceTest {
    PostService postService = new PostService();

    @Test
    public void testIncreasePostReadCount() {
        postService.increaseReadCount(101);
        postService.increaseReadCount(101);
        postService.increaseReadCount(101);
    }

    @Test
    public void testIncreasePostLikeCount() {
        postService.increaseLikeCount(101);
        postService.increaseLikeCount(101);
        postService.increaseLikeCount(101);
    }

    @Test
    public void testDecreasePostLikeCount() {
        postService.decreaseLikeCount(101);
    }
}

image.png

2. 生成热门帖子排行榜

image.png

2.1 业务代码

public class PostService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();
    
    // 添加热门帖子
    public void addPostList(int postId, double score) {
        String key = "post:list";
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.zadd(key, score, String.valueOf(postId));
            if (jedis.zcard(key) > 10) {
                jedis.zpopmin(key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 返回热门帖子列表
    public List<Integer> getPostList() {
        String key = "post:list";
        try (Jedis jedis = jedisPool.getResource()) {
            Set<String> set = jedis.zrevrange(key, 0, -1);
            List<Integer> list = new ArrayList<>();
            for (String id : set) {
                list.add(Integer.valueOf(id));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

2.2 测试代码

public class ServiceTest {
    PostService postService = new PostService();

    @Test
    public void testAddPostList() {
        for (int i = 0; i < 30; i++) {
            postService.addPostList(i + 1, (i + 1) * 10);
        }
    }

    @Test
    public void testGetPostList() {
        List<Integer> list = postService.getPostList();
        System.out.println(list);
    }
}

image.png

3. 记录用户的粉丝数量

image.png

3.1 业务代码

public class UserService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    // 关注 userId:用户id, targetId:用户将要关注的用户id
    public void follow(int userId, int targetId) {
        String key1 = "following:" + userId;
        String key2 = "follower:" + targetId;
        Jedis jedis = jedisPool.getResource();
        Transaction tx = null;
        try {
            // 加乐观锁,
            // 为什么加在key1上?因为同一时刻A只能关注一个人,而B可以同一时刻被多个人关注
            jedis.watch(key1);
            tx = jedis.multi();
            tx.sadd(key1, String.valueOf(targetId));
            tx.sadd(key2, String.valueOf(userId));
            tx.exec();
        } catch (Exception e) {
            e.printStackTrace();
            // 捕捉到异常则取消提交事务
            if (tx != null) {
                tx.discard();
            }
        } finally {
            if (tx != null) {
                tx.close();
            }
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    // 获取粉丝数
    public long getFollowerCount(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "follower:" + userId;
            return jedis.scard(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    // 获取关注数
    public long getFollowingCount(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "following:" + userId;
            return jedis.scard(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    // 获取共同关注列表
    public Set<Integer> getSameFollowing(int userId1, int userId2) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key1 = "following:" + userId1;
            String key2 = "following:" + userId2;
            Set<String> set = jedis.sinter(key1, key2);
            Set<Integer> result = new HashSet<>();
            for (String member : set) {
                result.add(Integer.valueOf(member));
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

3.2 测试代码

public class ServiceTest {
    UserService userService = new UserService();

    @Test
    public void testFollow() {
        userService.follow(1, 8);
        userService.follow(2, 8);
        userService.follow(3, 8);
        userService.follow(1, 9);
        userService.follow(2, 9);
        userService.follow(9, 1);
        userService.follow(9, 2);
    }

    @Test
    public void testGetFollowCount() {
        System.out.println(userService.getFollowingCount(1));
        System.out.println(userService.getFollowerCount(1));
        System.out.println(userService.getSameFollowing(1, 2));
        System.out.println(userService.getSameFollowing(3, 2));
    }
}

image.png

4. 记录用户的兴趣标签

4.1 业务代码

public class UserService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    // 添加兴趣标签
    public void addTags(int userId, String... tags) {
        if (tags == null || tags.length == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "tags:" + userId;
            // pipeline流水线
            Pipeline pipeline = jedis.pipelined();
            for (String tag : tags) {
                pipeline.sadd(key, tag);
            }
            pipeline.syncAndReturnAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取兴趣标签
    public Set<String> getTags(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "tags:" + userId;
            return jedis.smembers(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

4.2 测试代码

public class ServiceTest {
    UserService userService = new UserService();

    @Test
    public void testTags() {
        // 添加标签
        userService.addTags(1, "音乐");
        userService.addTags(1, "运动");
        userService.addTags(1, new String[]{"游戏", "交友", "鬼畜"});
        // 查询标签
        System.out.println(userService.getTags(1));
    }
}

image.png

5. 记录用户的待办事项

5.1 业务代码

public class UserService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    // 添加待办事项
    public void addTodoItem(int userId, String item) {
        if (item == null || item.length() == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "todo:list:" + userId;
            jedis.rpush(key, item);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 移除待办事项
    public void delTodoItem(int userId, String item) {
        if (item == null || item.length() == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "todo:list:" + userId;
            jedis.lrem(key, 1, item);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取所有待办事项
    public List<String> getTodoItem(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "todo:list:" + userId;
            return jedis.lrange(key, 0, -1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

5.2 测试代码

public class ServiceTest {
    UserService userService = new UserService();

    @Test
    public void testTodoItem() {
        // 添加待办事项
        userService.addTodoItem(1, "看书");
        userService.addTodoItem(1, "购物");
        userService.addTodoItem(1, "订外卖");
        userService.addTodoItem(1, "打游戏");
        // 删除待办事项
        userService.delTodoItem(1, "打游戏");
        // 查询待办事项
        System.out.println(userService.getTodoItem(1));
    }
}

image.png

6. 存储用户的登录会话

image.png

6.1 业务代码

public class UserService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    // 创建令牌
    public String createToken(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String token = CommonUtil.generateUUID();
            String key = "token:" + token;
            jedis.setex(key, 10, String.valueOf(userId));
            return token;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // 验证令牌
    public Integer validateToken(String token) {
        if (token == null || token.length() == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "token:" + token;
            String userId = jedis.get(key);
            if (userId != null) {
                return Integer.valueOf(userId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

6.2 测试代码

public class ServiceTest {
    UserService userService = new UserService();

    @Test
    public void testToken() throws InterruptedException {
        String token = userService.createToken(1);
        System.out.println(userService.validateToken(token));

        Thread.sleep(10000);
        System.out.println(userService.validateToken(token));

        System.out.println(userService.validateToken(CommonUtil.generateUUID()));
    }
}

image.png

7. 限制服务的访问次数

image.png

7.1 业务代码

public class UserService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    private Map<String, Integer> serviceMap = new HashMap<>();

    public UserService() {
        serviceMap.put("request", 20); // 普通请求
        serviceMap.put("password", 5); // 输入密码
    }

    // 是否可用
    public boolean isAvailable(String service, int userId) {
        if (service == null || service.length() == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        boolean result = false;
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "times:" + service + ":" + userId;
            String times = jedis.get(key);
            if (times == null) {
                result = true;
                jedis.setex(key, 15, String.valueOf(serviceMap.get(service)));
            } else {
                result = Integer.valueOf(times) > 0;
            }
            jedis.decr(key);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

7.2 测试代码

public class ServiceTest {
    UserService userService = new UserService();

    @Test
    public void testServiceAvailable() throws InterruptedException {
        System.out.println(userService.isAvailable("password", 1));
        System.out.println(userService.isAvailable("password", 1));
        System.out.println(userService.isAvailable("password", 1));
        System.out.println(userService.isAvailable("password", 1));
        System.out.println(userService.isAvailable("password", 1));
        System.out.println(userService.isAvailable("password", 1));
        Thread.sleep(15 * 1000);
        System.out.println(userService.isAvailable("password", 1));

    }
}

image.png

8. 统计网站的独立访客

8.1 业务代码

public class DataService {

    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    private SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");

    // 将指定的ip计入UV
    public void recordUV(String ip) {
        if (ip == null || ip.length() == 0) {
            throw new IllegalArgumentException("参数为空!");
        }
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "uv:" + df.format(new Date());
            jedis.pfadd(key, ip);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 统计指定日期范围内的UV
    public long calculateUV(Date start, Date end) {
        if (start == null || end == null) {
            throw new IllegalArgumentException("参数为空!");
        }
        // 整理该日期范围内的key
        List<String> keys = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        while (!calendar.getTime().after(end)) {
            String key = "uv:" + df.format(calendar.getTime());
            keys.add(key);
            calendar.add(Calendar.DATE, 1);
        }
        // 合并统计结果
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.pfcount(keys.toArray(new String[0]));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

8.2 测试代码

public class ServiceTest {
    DataService dataService = new DataService();

    @Test
    public void testRevordUV() {
        dataService.recordUV("139.9.119.1");
        dataService.recordUV("139.9.119.2");
        dataService.recordUV("139.9.119.3");
        dataService.recordUV("139.9.119.1");
        dataService.recordUV("139.9.119.2");
        dataService.recordUV("139.9.119.3");
        dataService.recordUV("139.9.119.1");
        dataService.recordUV("139.9.119.2");
        dataService.recordUV("139.9.119.3");
    }

    @Test
    public void testCalculateUV() {
        Date start = new Date("2021/11/01");
        Date end = new Date("2021/11/30");
        long uv = dataService.calculateUV(start, end);
        System.out.println(uv);
    }
}

image.png

9. 统计用户的在线天数

9.1 业务代码

public class DataService {
    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    private SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
    
    // 记录用户的在线状态
    public void recordOnline(int userId) {
        Calendar calendar = Calendar.getInstance();
        int y = calendar.get(Calendar.YEAR);
        int n = calendar.get(Calendar.DAY_OF_YEAR);
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "online:" + y + ":" + userId;
            jedis.setbit(key, n - 1, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 统计用户的在线状态
    public int[] calculateOnline(int userId) {
        Calendar calendar = Calendar.getInstance();
        int y = calendar.get(Calendar.YEAR);
        int n = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "online:" + y + ":" + userId;
            Pipeline pipeline = jedis.pipelined();
            for (int i = 0; i < n; i++) {
                pipeline.getbit(key, i);
            }
            List<Object> list = pipeline.syncAndReturnAll();
            int[] flags = new int[n];
            for (int i = 0; i < n; i++) {
                flags[i] = Boolean.parseBoolean(list.get(i).toString()) ? 1 : 0;
            }
            return flags;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

9.2 测试代码

public class ServiceTest {
    DataService dataService = new DataService();
    
    @Test
    public void testRecordOnline() {
        dataService.recordOnline(1);
        dataService.recordOnline(2);
        dataService.recordOnline(3);
        dataService.recordOnline(1);
        dataService.recordOnline(2);
        dataService.recordOnline(3);
        dataService.recordOnline(1);
        dataService.recordOnline(2);
        dataService.recordOnline(3);
    }

    @Test
    public void testCalculateOnline() {
        int[] flags = dataService.calculateOnline(1);
        for (int i = 0; i < flags.length; i++) {
            System.out.print(flags[i] + " ");
            if ((i + 1) % 20 == 0)
                System.out.println();
        }
    }
}

image.png

10. 布隆过滤器

详解布隆过滤器的原理

11. 延时队列(通过Jedis实现)

image.png

11.1 业务代码

public interface DelayQueueHandler {
    void handle(String message);
}
public class DelayQueue {

    private String key;

    private DelayQueueHandler handler;

    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    public DelayQueue(String service, DelayQueueHandler handler) {
        this.key = "delay:queue" + service;
        this.handler = handler;
    }

    // 加入队列
    public void push(String message, long delayMiliseconds) {
        if (message == null || message.length() == 0) {
            return;
        }
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.zadd(key, System.currentTimeMillis() + delayMiliseconds, message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 消费数据
    public void consume() {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("尝试消费...");
                try (Jedis jedis = jedisPool.getResource()) {
                    Set<String> set = jedis.zrangeByScore(
                            key, 0, System.currentTimeMillis(), 0, 100);
                    if (set != null && set.size() > 0) {
                        for (String message : set) {
                            handler.handle(message);
                            jedis.zrem(key, message);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 0, 3000);
    }

    public static void main(String[] args) {
        DelayQueue queue = new DelayQueue("EndExam", new DelayQueueHandler() {
            @Override
            public void handle(String message) {
                System.out.println("处理消息: " + message);
            }
        });

        queue.consume();

        queue.push("aaa", 10 * 1000);
        queue.push("bbb", 10 * 1000);
        queue.push("ccc", 10 * 1000);
        queue.push("ddd", 20 * 1000);
        queue.push("eee", 30 * 1000);
    }
}

image.png

12. 延时队列(Redisson内置的延时队列)

image.png

12.1 业务代码

public class RedissonTest {
    RedissonClient client = RedissonFactory.getInstance().getClusterClient();
    
    @Test
    public void testDelayQueue() {
        // 目标队列
        RBlockingDeque<String> queue = client.getBlockingDeque("queue:EndExam");
        // 临时队列
        RDelayedQueue<String> delayedQueue = client.getDelayedQueue(queue);

        // 消费数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        System.out.println("正在消费...");
                        String message = (String) queue.take();
                        System.out.println("处理消息:" + message);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        delayedQueue.offer("aaa", 10, TimeUnit.SECONDS);
        delayedQueue.offer("bbb", 10, TimeUnit.SECONDS);
        delayedQueue.offer("ccc", 10, TimeUnit.SECONDS);
        delayedQueue.offer("ddd", 20, TimeUnit.SECONDS);
        delayedQueue.offer("eee", 30, TimeUnit.SECONDS);

        try {
            Thread.sleep(1000 * 60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

image.png

13. 分布式锁(通过Jedis实现)

image.png image.png

13.1 业务代码

public class DistributedLock {

    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    private String key, value;

    private String unlockScript =
            "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";

    public DistributedLock(String lockName) {
        this.key = lockName;
    }

    // 加锁,单位毫秒
    public void lock(long expireTime) {
        try (Jedis jedis = jedisPool.getResource()) {
            while (true) {
                value = CommonUtil.generateUUID();
                String result = jedis.set(key, value, SetParams.setParams().nx().px(expireTime));
                if ("OK".equals(result)) {
                    break;
                }
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 解锁
    public void unlock() {
        try (Jedis jedis = jedisPool.getResource()) {
            List<String> keys = Arrays.asList(new String[]{key});
            List<String> args = Arrays.asList(new String[]{value});
            jedis.eval(unlockScript, keys, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    DistributedLock lock = new DistributedLock("lock:vote");
                    System.out.println("尝试加锁...");
                    lock.lock(1000 * 5);
                    System.out.println("加锁成功...");
                    try {
                        System.out.println("修改票数: " + Thread.currentThread().getName());
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                        System.out.println("解锁成功...");
                    }
                }
            }).start();
        }
    }
}

image.png

14. 分布式锁(通过Redisson实现)

14.1 业务代码——单节点实现

public class RedissonTest {
    RedissonClient client = RedissonFactory.getInstance().getClusterClient(); 

    @Test
    public void testDistributedLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    RLock rlock = client.getLock("lock:vote");
                    System.out.println("尝试加锁...");
                    rlock.lock(5000, TimeUnit.MILLISECONDS);
                    System.out.println("加锁成功...");
                    try {
                        System.out.println("修改票数: " + Thread.currentThread().getName());
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        rlock.unlock();
                        System.out.println("解锁成功...");
                    }
                }
            }).start();
        }
        Thread.sleep(1000 * 15);
    }

}

image.png image.png

15. 分布式缓存(一)

image.png

15.1 业务代码

1. 模拟访问MySQL数据库

public class UserDao {

    public User findUserById(int id) {
        System.out.println("查询ID为" + id + "的用户...");
        return new User(id, "user", "123", null, null);
    }

    public void updateUser(User user) {
        System.out.println("修改ID为" + user.getId() + "的用户...");
    }

    public void deleteUser(int id) {
        System.out.println("删除ID为" + id + "的用户...");
    }
}

2. 模拟访问分布式缓存Redis

public class UserCache {

    private JedisPool jedisPool = JedisFactory.getInstance().getJedisPool();

    public void setUser(User user) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "user:" + user.getId();
            jedis.setex(key, 10, JSON.toJSONString(user));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public User getUser(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "user:" + userId;
            return JSON.parseObject(jedis.get(key), User.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public void delUser(int userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "user:" + userId;
            jedis.del(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. 业务Service代码

public class UserService {
    private UserCache userCache = new UserCache();

    private UserDao userDao = new UserDao();

    // 查询用户
    public User findUser(int userId) {
        User user = userCache.getUser(userId);
        if (user == null) {
            user = userDao.findUserById(userId);
            userCache.setUser(user);
        }
        return user;
    }

    // 修改用户
    public void modifyUser(User user) {
        userDao.updateUser(user);
        userCache.delUser(user.getId());
    }

    public static void main(String[] args) throws InterruptedException {
        UserService userService = new UserService();
        for (int i = 0; i < 5; i++) {
            // 第1次访问,访问1次Mysql数据库,后4次访问缓存
            User user = userService.findUser(1);
            System.out.println(user);
        }

        userService.modifyUser(userService.findUser(1));
        for (int i = 0; i < 5; i++) {
            // 因为修改过,缓存中的数据被删除
            // 第2次访问,访问1次Mysql数据库,后4次访问缓存
            User user = userService.findUser(1);
            System.out.println(user);
        }

        Thread.sleep(10000);
        for (int i = 0; i < 5; i++) {
            // 因为缓存过期,
            // 第3次访问,访问1次Mysql数据库,后4次访问缓存
            User user = userService.findUser(1);
            System.out.println(user);
        }
    }
}

image.png

16. 分布式缓存(二)——内存淘汰策略

16.1 数据过期策略

image.png

16.2 内存淘汰策略

image.png

16.3 LRU算法

image.png

16.4 LFU算法

image.png

17. 分布式缓存(三)——缓存与数据库的同步问题

17.1 四种同步策略

image.png

17.2 更新缓存还是删除缓存?

image.png

17.3 先操作数据库还是缓存?

image.png

  1. 先删除缓存成功,再更新数据库失败
    1). A先删除缓存;
    2). 然后A更新数据库失败;
    3). B此时从缓存中获取数据;
    4). 因为缓存中无数据,B从数据库中查询数据因为更新数据库操作失败因此查到的是旧数据;
    5). B再将旧数据写回到缓存中。
  2. 先更新数据库成功,再删除缓存失败
    1). A先更新数据库;
    2). 然后A删除缓存失败;
    3). B此时从缓存中获取数据,获取到的数据是旧数据。 image.png image.png
  3. 先删除缓存,再更新数据库
    1). A先删除缓存;
    2). 然后B从缓存中获取数据
    3). 因为缓存中没有数据,所以B从数据库中获取数据(旧数据);
    4). B获取到数据后再将数据写入到缓存中;
    5). 此时A再更新数据库。【缓存旧数据,数据库新数据】
  4. 先更新数据库,再删除缓存
    1). A先更新数据库;
    2). B从缓存中获取数据(旧数据)
    3). A再删除缓冲;【缓存无数据,数据库新数据】 image.png

17.4 最终结论

image.png

18. 分布式缓存(四)——缓存穿透、击穿、雪崩

18.1 缓存穿透

image.png

18.2 缓存击穿

image.png

18.3 缓存雪崩

image.png