方案一:lua脚本
考虑到多条命令的原子性,可以用lua脚本进行操作.通过lpush添加到队列头部,再对list进行ltrim操作,只保留前10个元素,其他内容丢弃.这样就实现了一个定长为10的队列.
@Component
public class MyTest {
public static final String APP_INFO_KEY = "bszn:app";
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* redis lua脚本:维护一个定长队列(长度10),每次新数据加到队列头部,超过长度部分丢弃
*/
private static final String FIXED_LENGTH_QUEUE_LUA_SCRIPT =
"local key = KEYS[1] " +
"redis.call('lpush',key,unpack(ARGV))" +
"redis.call('ltrim',key,0,9)";
/**
* 推送数据到redis
* @param deviceList 设备信息
*/
public void pushDeviceRegInfo(List<Device> deviceList) {
// lua脚本
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(FIXED_LENGTH_QUEUE_LUA_SCRIPT);
String[] regInfoJsons = deviceList.stream().map(JSON::toJSONString).toArray(String[]::new);
// 执行lua脚本
redisTemplate.execute(redisScript, Collections.singletonList(APP_INFO_KEY), regInfoJsons);
}
/**
* 从redis中取出设备信息
*/
public List<Device> getDeviceInfoList() {
return Optional.ofNullable(redisTemplate.opsForList().range(APP_INFO_KEY, 0, -1))
.orElseGet(ArrayList::new)
.stream()
// str转实体
.map(s -> JSON.parseObject(s, Device.class))
// 时间倒叙排序列表
.sorted(Comparator.comparing(Device::getCreateTime).reversed())
// 只取10条
.limit(10)
.collect(Collectors.toList());
}
}
方案二:multi+exec
redis通过MULTI、EXEC、WATCH等命令来实现事务(transaction)功能。redis的事务提供了一种将多个命令请求打包、一次性、按顺序地执行多个命令的机制。在事务执行期间,服务器不会中断事务而去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。redis事务不支持回滚机制,如果事务中的某条命令在执行期间出现了错误,事务后续其他命令都不会执行,已经执行的命令都不会收到任何影响,不进行回滚。
@Component
public class MyTest {
public static final String APP_INFO_KEY = "bszn:app";
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 推送数据到redis
* @param deviceList 设备信息list
*/
public void pushDeviceInfo(List<Device> deviceList) {
SessionCallback sessionCallback = new SessionCallback() {
@Override
public Object execute(RedisOperations redisOperations) throws DataAccessException {
redisOperations.multi();
String[] deviceInfoJsons = deviceList.stream().map(JSON::toJSONString).toArray(String[]::new);
ListOperations listOperations = redisOperations.opsForList();
listOperations.leftPushAll(APP_INFO_KEY, deviceInfoJsons);
listOperations.trim(APP_INFO_KEY, 0, 9);
return redisOperations.exec();
}
};
redisTemplate.execute(sessionCallback);
}
}