BitSet是Redis中提供的一种二进制数组的数据结构, 利用这种特殊的数据结构可以实现一些特定的场景.
BitSet的数据长这样: [01010010], 存放的是boolean, 且长度为8的倍数 也就是byte的长度. 且只存true, false会自动填充.
Redisson提供的RBitSet还额外提供了 与 或 非 等api.
现需要记录一个24小时的状态图, 状态可以是: 打开/关闭; 在家/离家; 等等
每15分钟记一次状态, 也可以是10分钟, 30分钟
value格式:00010100,以每15分钟的统计结果作为1bit
不足8位会自动补0

写入和读取分离, 缓存实时维护, 查询也只查缓存, 不查数据源
比如说 00:16 和 01:27 检测到状态为打开, 其余时间段为关闭
那么预期的二进制数据为: 01000100
redisson提供了相关的api:
RBitSet bitSet = redissonClient.getBitSet(key);
bitSet.set(index);
bitSet.expire(7, TimeUnit.DAYS);
对应的数组索引为1和6 , 这里就是set(1), set(6). 0(false)会自动填充
/*** Redis位图工具类* @author Lynn* @date 2023/3/13 19:38*/
@Component
public class BitMapUtil {private static RedissonClient redissonClient;@Autowiredpublic void setRedissonClient(RedissonClient redissonClient) {BitMapUtil.redissonClient = redissonClient;}private static DeviceConfigService deviceConfigService;@Autowiredpublic void setDeviceConfigService(DeviceConfigService deviceConfigService) {BitMapUtil.deviceConfigService = deviceConfigService;}public static RBitSet getBitSet(String key) {return redissonClient.getBitSet(key);}public static void mergeList(List result, RBitSet bitSet, long i) {if (i <= bitSet.size() - 1) {if (bitSet.get(i)) {StatusBo bo = StatusBo.builder().startTime(BitMapUtil.mapIndexToStartDate(i)).endTime(BitMapUtil.mapIndexToEndDate(i)).build();result.add(bo);while (i < bitSet.size() - 1 && bitSet.get(i + 1)) {bo.setEndTime(BitMapUtil.mapIndexToEndDate(i + 1));i++;}}i++;mergeList(result, bitSet, i);}}private static Date mapIndexToStartDate(long index) {Map globalConfig =deviceConfigService.queryBaseConfig(new DeviceConfigDto(), DeviceConfigDimensionEnum.GLOBAL.getCode());String config = globalConfig.get(WHOLE_DAY_PROTECT_INTERVAL);int step = StringUtils.isNoBlank(config) ? Integer.parseInt(config) / 60000 : 15;int minute = (int) (index * step);Date now = new Date();return new Date(now.getYear(), now.getMonth(), now.getDate(), minute / 60, minute % 60, 0);}private static Date mapIndexToEndDate(long index) {Map globalConfig =deviceConfigService.queryBaseConfig(new DeviceConfigDto(), DeviceConfigDimensionEnum.GLOBAL.getCode());String config = globalConfig.get(WHOLE_DAY_PROTECT_INTERVAL);int step = StringUtils.isNoBlank(config) ? Integer.parseInt(config) / 60000 : 15;int minute = (int) ((index + 1) * step);Date now = new Date();return new Date(now.getYear(), now.getMonth(), now.getDate(), minute / 60 < 24 ? minute / 60 : 23,minute / 60 < 24 ? minute % 60 : 59, 0);}public static long mapDateToIndex(Date date) {Map globalConfig =deviceConfigService.queryBaseConfig(new DeviceConfigDto(), DeviceConfigDimensionEnum.GLOBAL.getCode());String config = globalConfig.get(WHOLE_DAY_PROTECT_INTERVAL);int step = StringUtils.isNoBlank(config) ? Integer.parseInt(config) / 60000 : 15;return (date.getHours() * 60 + date.getMinutes()) / step;}
}
下一篇:迟到1分钟算教学事故是否太苛刻?