RedisTemplate 实现 scan 方法(最新版 spring-redis-data 已于 2022.02.23 支持了 scan 方法)

RedisTemplate 实现 scan 方法

问题来源: 工作中遇到一个问题,需要清理大量的 key ,由于数量过于大,用 keys 获取时可能会造成 redis 的阻塞,所以就想到用 scan 命令。scan 命令对于集群来说只能获取到单台机器的数据,所以对集群上的所有机器都执行 scan 命令。公司用的 spring-boot 所依赖的 spring-redis-data 中 RedisTemplate 并没有 scan 方法,也在网上查了一些实现,不是只获取了单台机器的数据,就是无法正常返回数据,实现起来也并不简单。

解决思路: redis 的命令并不只有 scan 命令只能在单台机器上执行,keys 其实也是只能在单台机器上执行,解决思路就清晰了,直接去看一下 RedisTemlate 中 keys 方法是如何实现的,仿写一下就好了。

	// spring-redis-data version: 2.2.x
	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisOperations#keys(java.lang.Object)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Set<K> keys(K pattern) {

		byte[] rawKey = rawKey(pattern);
		Set<byte[]> rawKeys = execute(connection -> connection.keys(rawKey), true);

		return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : (Set<K>) rawKeys;
	}

于是产生了如下代码:

	/*
	* @Resource
	* RedisTemplate redisTemplate;
	*/
	public Set<String> scan (String pattern, int count) {
		Set<String> keys = new HashSet<>();
		RedisSerializer serializer = redisTemplate.getKeySerializer();
		ScanOptions scanOptions = ScanOptions.scanOptions().match(pattern).count(count).build();
		Cursor<byte[]> cursor = redisTemplate.execute(connection -> connection.scan(scanOptions), true);
		while (cursor.hasNext()) {
			keys.add(String.valueOf(serializer.deserialize(cursor.next())));
		}
		return keys;
	}

测试过后跟通过 keys 方法得到的结果集对比,发现是一样的,说明这样写是可行的。可通过调节 count 的大小来控制单次 scan 命令扫描的数据量,redis 中默认是 10 。注意:不要把 count 的值设成 Integer.MAX_VALUE 或过大,否则会产生和 keys 命令类似的效果,可能会阻塞 redis。

最后放上最新版 spring-redis-data 中的 scan 方法实现(不禁发出感叹,如果早四个月,没准就是我贡献了这部分代码了,哈哈哈)

	@Override
	public Cursor<K> scan(ScanOptions options) {
		Assert.notNull(options, "ScanOptions must not be null");

		return executeWithStickyConnection(
				(RedisCallback<Cursor<K>>) connection -> new ConvertingCursor<>(connection.scan(options),
						this::deserializeKey));
	}

	@SuppressWarnings("unchecked")
	private K deserializeKey(byte[] value) {
		return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value;
	}
  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
To define a bean of type 'redis.RedisUtil' in your configuration, you can follow these steps: 1. Make sure you have the necessary dependencies added to your project. Typically, for Redis-related operations, you will need the 'spring-boot-starter-data-redis' dependency. 2. Create a RedisUtil class that provides the necessary operations and functionalities related to Redis. This class should have methods for connecting to Redis, performing CRUD operations, and any other Redis-specific operations you require. 3. Annotate the RedisUtil class with the '@Component' annotation to make it a Spring bean. This annotation tells Spring to manage the lifecycle of this class and make it available for autowiring. 4. In your application configuration class (usually annotated with '@SpringBootApplication'), use the '@ComponentScan' annotation to scan for the RedisUtil class. This ensures that Spring discovers the RedisUtil bean and makes it available for injection. Here is an example: ```java import org.springframework.stereotype.Component; @Component public class RedisUtil { // Your RedisUtil implementation here } ``` ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan(basePackages = "com.yourpackage") public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } } ``` Make sure to replace "com.yourpackage" with the actual package where your RedisUtil class resides. With these steps, you should be able to define a bean of type 'redis.RedisUtil' in your configuration.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值