在业务开发中,经常需要维护缓存和快照的数据最终一致性;
备忘录模式: 保存一个对象的某个状态,以便在适当的时候恢复对象。
直接上代码吧!!!
1.缓存相关接口
CacheService.class 缓存接口定义
public interface CacheService<T extends Version> {
/**
* 存redis缓存和版本号
*
* @param t
*/
void saveCache(T t);
/**
* 存redis缓存和版本号
*
* @param dataList
*/
void saveCacheList(List<T> dataList);
Map<Integer, Long> idVersionCacheMap();
}
ConsistencyService.class 数据一致性接口定义
public interface ConsistencyService {
/**
* 数据一致性维护
*/
void keepConsistency();
}
AbstractCacheService.class 定义cache的基础接口和实现数据一致性的模板方法
public abstract class AbstractCacheService<T extends Version> implements ConsistencyService, CacheService<T> {
@Autowired
private SnapshotService<T> snapshotService;
/**
* 保存数据
*
* @param t
*/
public void save(T t) {
// 先存快照
snapshotService.save(t);
// 再存redis
saveCache(t);
}
List<T> check() {
// 获取redis的版本map
Map<Integer, Long> idVersionCacheMap = idVersionCacheMap();
// 获取快照的版本
Map<Integer, Long> idVersionSnapshotMap = snapshotService.idVersionMap();
// 需要修复的数据
List<Integer> needFixIds = new ArrayList<>();
idVersionSnapshotMap.forEach((id, versionCache) -> {
Long versionSnapshot = idVersionCacheMap.get(id);
if (Objects.isNull(versionSnapshot)) {
// 快照为null,跳出本次循环;
// 理论上可以加上无版本删除逻辑
return;
}
// redis的版本>数据库的版本;需要修复数据
if (versionCache.compareTo(versionSnapshot) > 0) {
needFixIds.add(id);
}
});
// 需要修复的数据集合
return snapshotService.list(needFixIds);
}
/**
* 保持数据一致性
*/
public void keepConsistency() {
List<T> dataList = check();
if (CollectionUtils.isEmpty(dataList)) {
return;
}
// 保存redis数据
saveCacheList(dataList);
}
}
MenuCacheService.class 菜单缓存接口
@Service
public class MenuCacheService extends AbstractCacheService<MenuData> {
@Override
public void saveCacheList(List dataList) {
// 保存redis
// 保存版本号
}
@Override
public void saveCache(MenuData t) {
// 保存redis
// 保存版本号
}
@Override
public Map<Integer, Long> idVersionCacheMap() {
return null;
}
}
2.快照相关接口
SnapshotService.class 快照接口定义
public interface SnapshotService<T extends Version> {
Map<Integer, Long> idVersionMap();
void save(T t);
List<T> list(List<Integer> ids);
}
MenuSnapshotMenuService.class 菜单快照接口
@Service
public class MenuSnapshotMenuService implements SnapshotService<MenuData> {
@Override
public Map<Integer, Long> idVersionMap() {
// 数据库查询版本的map
return null;
}
@Override
public void save(MenuData o) {
// 保存快照到数据库
}
@Override
public List<MenuData> list(List<Integer> ids) {
// 查询指定的快照
return null;
}
}
3.监控
VersionMonitor.class 版本监控,维护数据一致性
@Component
public class VersionMonitor {
@Autowired
List<ConsistencyService> consistencyServices;
public void start() {
consistencyServices.forEach(ConsistencyService::keepConsistency);
}
}
4.实体
Version.class 版本实体
@Data
public class Version {
private Long version;
}
MenuData.class 菜单实体
@Data
public class MenuData extends Version {
}
QQ交流群: 132312549