V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
JasonLaw
V2EX  ›  程序员

你们是怎么使用 change data capture 来实现缓存失效的?

  •  
  •   JasonLaw · 2020-10-23 22:11:52 +08:00 · 800 次点击
    这是一个创建于 1491 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我先说一下我是怎么使用change data capture来实现缓存失效的。

    比如我有UserRepo,为了避免每次调用方法都要去查询数据库,我使用了@AutoCache实现了“有缓存直接取缓存;没缓存的话,查询数据库,然后缓存结果”。为了实现缓存失效,我使用了@AutoCacheInvalidation

    public interface UserMapper {
    
        // select * from user
        @AutoCache(timeToLiveInSeconds = 60)
        // “将 primaryTable 设为"user"”代表“只要 user 表有变化,Redis 中的 key UserMapper.findAll()需要被清除”
        @AutoCacheInvalidation(primaryTable = "user", primaryTableColumns = {},
                joinTables = {}, joinTableColumns = {})
        List<Object> findAll();
    
        // select * from user where id = #{id}
        @AutoCache(timeToLiveInSeconds = 60)
        // “将 primaryTable 设为"user",primaryTableColumns 设为{"id"}”代表“如果 id 为 1 的 user 有变化,Redis 中的 key UserMapper.findById(1)需要被清除”
        @AutoCacheInvalidation(primaryTable = "user", primaryTableColumns = {"id"},
                joinTables = {}, joinTableColumns = {})
        Object findById(int id);
    
        // select * from user where name = #{name} and age = #{age}
        @AutoCache(timeToLiveInSeconds = 60)
        // “将 primaryTable 设为"user",primaryTableColumns 设为{"name", "age"}”代表“如果 name 为 jason 、age 为 18 的 user 有变化,Redis 中的 key UserMapper.findByNameAndAge(jason, 18)需要被清除”
        @AutoCacheInvalidation(primaryTable = "user", primaryTableColumns = {"name", "age"},
                joinTables = {}, joinTableColumns = {})
        List<Object> findByNameAndAge(String name, int age);
    }
    

    缓存失效服务会收集@AutoCacheInvalidation。缓存失效服务通过 change data capture 了解数据库的变化,然后清除相应的 Redis keys 。


    想问一下大家是怎么使用 change data capture 来实现缓存失效的,或者针对我现在的实现,给点建议,谢谢。

    我会在附言中说明我是怎么处理类似select * from user u join city c on u.city_id = c.id where u.id = 1这样的语句的,以及怎么处理“方法存在非数据库字段的参数”的(比如UserPostMapper.pageUserPosts(int userId, int offset, int limit))。

    第 1 条附言  ·  2020-10-23 22:44:17 +08:00

    处理类似select * from user u join city c on u.city_id = c.id where u.id = 1这样的语句时,我会利用到joinTablesjoinTableColumns,如下所示:

    public interface UserMapper {
    
        // select * from user u join city c on u.city_id = c.id where u.id = #{id}
        @AutoCache(timeToLiveInSeconds = 60)
        @AutoCacheInvalidation(primaryTable = "user", primaryTableColumns = {"id"},
                joinTables = {"city"}, joinTableColumns = {"id"})
        // “将primaryTable设为"user",primaryTableColumns设为{"id"}”代表“如果id为1的user有变化,Redis中的key UserMapper.findUserDetail(1)需要被清除”
        // “将joinTables设为{"city"},joinTableColumns设为{"id"}”代表"如果id为1的city有变化,Redis中的key UserMapper.findUserDetail(?)需要被清除",但是?代表什么呢?
        // id为1的city有变化,那么跟id为1的city有关联的用户都会受到影响,所以我使用了select id from user where city_id = 1来确定受影响的用户。
        // 假设select id from user where city_id = 1的结果为[1, 2, 3],那么Redis中的keys UserMapper.findUserDetail(1)、UserMapper.findUserDetail(2)、UserMapper.findUserDetail(3)都会被清除。
        Object findUserDetail(String id);
    }
    
    第 2 条附言  ·  2020-10-23 22:47:56 +08:00

    如果方法存在非数据库字段的参数时,我会利用到@NonTableColumn

    当方法存在非数据库字段的参数时,比如UserPostMapper.pageUserPosts(int userId, int offset, int limit),需要给offsetlimit加上@NonTableColumn

    这个时候会使用Redis Hashes缓存结果,而不是Strings。如果方法被调用时,userId1offset0limit5,那么key就是UserPostMapper.pageUserPosts(1, ?, ?),field为0, 5,value为postList

    UserPostMapper.pageUserPosts(int userId, @NonTableColumn int offset, @NonTableColumn int limit)对应的@AutoCacheInvalidation@AutoCacheInvalidation(primaryTable = "user_post", primaryTableColumns = {"user_id"}, joinTables = {}, joinTableColumns = {}),代表如果user_id1user_post有变化,Redis中的key UserPostMapper.pageUserPosts(1, ?, ?)会被删除。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2808 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 14:02 · PVG 22:02 · LAX 06:02 · JFK 09:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.