Redis牛客网学习笔记(二)

·  阅读 92

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

  1. 先删除缓存,再更新数据库
    1). A先删除缓存;
    2). 然后B从缓存中获取数据
    3). 因为缓存中没有数据,所以B从数据库中获取数据(旧数据);
    4). B获取到数据后再将数据写入到缓存中;
    5). 此时A再更新数据库。【缓存旧数据,数据库新数据】
  2. 先更新数据库,再删除缓存
    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

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改