需求
在redis客户端中可以直接使用bitMap的全部命令,但是redisTemplate中却没有BitCount命令,就无法用于统计,因此需要自己封装一个BitMapUtil
最开始思路是直接在一个Util中注入redisFactory中取一个conn,虽然可以直接使用,但是却有一个致命的问题,不属于连接池管理,因此在性能方面不可靠。后来还是找到方法在redisTemplate中exec封装执行。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @Author Diuut
* @Date 2020/6/9 11:18
*/
@Component
public class BitMapUtils {
private static RedisTemplate<String,String> redisTemplate;
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
BitMapUtils.redisTemplate = redisTemplate;
}
/**
* 设置key字段第offset位bit数值
*
* @param key 字段
* @param offset 位置
* @param value 数值
*/
public static void setBit(String key, long offset, boolean value) {
redisTemplate.execute((RedisCallback) con -> con.setBit(key.getBytes(), offset, value));
}
/**
* 判断该key字段offset位否为1
*
* @param key 字段
* @param offset 位置
* @return 结果
*/
public static boolean getBit(String key, long offset) {
return (boolean) redisTemplate.execute((RedisCallback) con -> con.getBit(key.getBytes(), offset));
}
/**
* 统计key字段value为1的总数
*
* @param key 字段
* @return 总数
*/
public static Long bitCount(String key) {
return (Long) redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes()));
}
/**
* 统计key字段value为1的总数,从start开始到end结束
*
* @param key 字段
* @param start 起始
* @param end 结束
* @return 总数
*/
public static Long bitCount(String key, Long start, Long end) {
return (Long) redisTemplate.execute((RedisCallback) con -> con.bitCount(key.getBytes(), start, end));
}
/**
* 取多个key并集并计算总数
*
* @param key key
* @return 总数
*/
public static Long OpOrCount(String... key) {
byte[][] keys = new byte[key.length][];
for (int i = 0; i < key.length; i++) {
keys[i] = key[i].getBytes();
}
redisTemplate.execute((RedisCallback) con -> con.bitOp(RedisStringCommands.BitOperation.OR, (key[0] + "To" + key[key.length - 1]).getBytes(), keys));
redisTemplate.expire(key[0] + "To" + key[key.length - 1], 10, TimeUnit.SECONDS);
return BitMapUtils.bitCount(key[0] + "To" + key[key.length - 1]);
}
/**
* 取多个key的交集并计算总数
*
* @param key key
* @return 总数
*/
public static Long OpAndCount(String... key) {
byte[][] keys = new byte[key.length][];
for (int i = 0; i < key.length; i++) {
keys[i] = key[i].getBytes();
}
redisTemplate.execute((RedisCallback) con -> con.bitOp(RedisStringCommands.BitOperation.AND, (key[0] + "To" + key[key.length - 1]).getBytes(), keys));
redisTemplate.expire(key[0] + "To" + key[key.length - 1], 10, TimeUnit.SECONDS);
return BitMapUtils.bitCount(key[0] + "To" + key[key.length - 1]);
}
/**
* 取多个key的补集并计算总数
*
* @param key key
* @return 总数
*/
public static Long OpXorCount(String... key) {
byte[][] keys = new byte[key.length][];
for (int i = 0; i < key.length; i++) {
keys[i] = key[i].getBytes();
}
redisTemplate.execute((RedisCallback) con -> con.bitOp(RedisStringCommands.BitOperation.XOR, (key[0] + "To" + key[key.length - 1]).getBytes(), keys));
redisTemplate.expire(key[0] + "To" + key[key.length - 1], 10, TimeUnit.SECONDS);
return BitMapUtils.bitCount(key[0] + "To" + key[key.length - 1]);
}
/**
* 取多个key的否集并计算总数
*
* @param key key
* @return 总数
*/
public static Long OpNotCount(String... key) {
byte[][] keys = new byte[key.length][];
for (int i = 0; i < key.length; i++) {
keys[i] = key[i].getBytes();
}
redisTemplate.execute((RedisCallback) con -> con.bitOp(RedisStringCommands.BitOperation.NOT, (key[0] + "To" + key[key.length - 1]).getBytes(), keys));
redisTemplate.expire(key[0] + "To" + key[key.length - 1], 10, TimeUnit.SECONDS);
return BitMapUtils.bitCount(key[0] + "To" + key[key.length - 1]);
}
}
查了一下,好像redisTemplate有方法可以执行对bitmap的一些命令,API是redisTemplate.opsForValue().setBit()和redisTemplate.opsForValue().getBit()。不过其他的还是得用execute()来使用