import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BooleanSupplier;
@Component
public class LabCounterUtil {
private final RedisTemplate<String, Object> redisTemplate;
// Lua脚本:条件满足时INCR,不满足时DEL
private static final RedisScript<Long> COUNTER_SCRIPT = new DefaultRedisScript<>(
"if ARGV[1] == 'true' then " +
" return redis.call('INCR', KEYS[1]) " +
"else " +
" return redis.call('DEL', KEYS[1]) " +
"end",
Long.class
);
public LabCounterUtil(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 对匹配的Redis Key执行条件计数或删除操作
* @param keyPattern 键匹配模式(如"lab:*")
* @param conditionSupplier 条件判断函数
*/
public void processLabCounters(String keyPattern, BooleanSupplier conditionSupplier) {
// 使用SCAN命令避免阻塞Redis
List<String> matchingKeys = scanKeys(keyPattern);
// 并行处理每个Key(根据实际情况调整)
matchingKeys.parallelStream().forEach(key -> {
boolean conditionMet = conditionSupplier.getAsBoolean();
executeCounterScript(key, conditionMet);
});
}
/**
* 使用SCAN命令获取匹配的Key列表
*/
private List<String> scanKeys(String pattern) {
return redisTemplate.execute((RedisCallback<List<String>>) connection -> {
List<String> keys = new ArrayList<>();
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(pattern).count(1000).build());
while (cursor.hasNext()) {
keys.add(new String(cursor.next()));
}
cursor.close();
return keys;
});
}
/**
* 执行Lua脚本实现原子操作
*/
private void executeCounterScript(String key, boolean conditionMet) {
redisTemplate.execute(
COUNTER_SCRIPT,
Collections.singletonList(key),
String.valueOf(conditionMet)
);
}
// Lua脚本:查询key的值,大于3返回1,否则返回0
private static final RedisScript<Long> CHECK_VALUE_SCRIPT = new DefaultRedisScript<>(
"local value = redis.call('GET', KEYS[1]) " +
"if value and tonumber(value) > 3 then " +
" return 1 " +
"else " +
" return 0 " +
"end",
Long.class
);
/**
* 查询key的值,若大于3则返回true,否则返回false
*/
public boolean checkValueGreaterThanThree(String key) {
// 执行Lua脚本
Long result = redisTemplate.execute(
CHECK_VALUE_SCRIPT,
java.util.Collections.singletonList(key)
);
// 将结果转换为布尔值
return result != null && result == 1L;
}
}
Redis查询键值并条件判断的Java实现
于 2025-06-17 10:35:52 首次发布