我先说一下我是怎么使用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)
)。
处理类似select * from user u join city c on u.city_id = c.id where u.id = 1
这样的语句时,我会利用到joinTables
和joinTableColumns
,如下所示:
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);
}
如果方法存在非数据库字段的参数时,我会利用到@NonTableColumn
。
当方法存在非数据库字段的参数时,比如UserPostMapper.pageUserPosts(int userId, int offset, int limit)
,需要给offset
和limit
加上@NonTableColumn
。
这个时候会使用Redis Hashes缓存结果,而不是Strings。如果方法被调用时,userId
为1
、offset
为0
、limit
为5
,那么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_id
为1
的user_post
有变化,Redis中的key UserPostMapper.pageUserPosts(1, ?, ?)
会被删除。