Redis五种常用数据结构
#redis-cli查看帮助命令
help @string
string 应用场景
//单值缓存
@Test
public void redisString() throws JsonProcessingException {
Jedis jedis = pool.getResource();
// for (String key : jedis.keys("*")) {
// System.out.println(key + " : " + jedis.get(key));
// }
//单值缓存 && 对象缓存
var users = new ArrayList<User>();
users.add(new User(125, "Blue1"));
users.add(new User(127, "Banana1"));
users.add(new User(128, "Yellow1"));
ObjectMapper mapper = new ObjectMapper();
List<String> keys = new ArrayList<>();
for (User user : users) {
String key = "user:" + user.getId();
keys.add(key);
var objStr = mapper.writeValueAsString(user);
String set = jedis.set(key, objStr);
System.out.println(set); //OK
}
String[] array = keys.toArray(new String[0]);
List<String> mget = jedis.mget(array);
for (String value : mget) {
User user = mapper.readValue(value, User.class);
System.out.println("id : " + user.getId() + " name:" + user.getName());
}
}
//分布式锁
private JedisPool pool= new JedisPool("localhost", 6379);
private String lockKey = "lock:product:10000";
@Test
public void redisLock() throws InterruptedException {
var work = new Runnable() {
@Override
public void run() {
long setnx = 0;
Jedis jedis = pool.getResource();
try {
setnx = jedis.setnx(lockKey, "1");
System.out.println(Thread.currentThread().getName() + " setnx " + setnx);
if (setnx > 0) {
System.out.println(Thread.currentThread().getName() + " do process...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} finally {
if (setnx > 0) {
long del = jedis.del(lockKey);
System.out.println(Thread.currentThread().getName() + " del result = " + del);
}
System.out.println(Thread.currentThread().getName() + " end...");
}
}
};
var t1 = new Thread(work, "t1");
var t2 = new Thread(work, "t2");
t1.start();
t2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
//计数器
@Test
public void counter(){
Jedis jedis = pool.getResource();
String key = "article:readCount:173745";
for (int i = 0; i < 5000; i++) {
jedis.incr(key);
}
System.out.println("article.counter:" + jedis.get(key));
}
//Web集群session共享
//分布式序列化 INCRBY orderId 1000 //redis批量生成序列号提升性能
@Test
public void generateNumber(){
Jedis jedis = pool.getResource();
String key = "sequenceNumber";
long number = jedis.incrBy(key, 1000);
for (int i = (int) (number - 1000 + 1); i <= number; i++) {
//generateRealNumber
System.out.printf("待使用的序列号:generateRealNumber(%d)\n", i);
}
}
hash
与 string 存储对象的优缺点
- 同类数据归类整合储存,方便数据管理
- 相比string操作消耗内存与cpu更小
- 相比string储存更节省空间
缺点
- 过期功能不能使用在field上,只能用在key上
- Redis集群架构下不适合大规模使用
//对象存储
@Test
public void objStore() {
Jedis jedis = pool.getResource();
var users = new ArrayList<User>();
users.add(new User(200, "Orange"));
users.add(new User(201, "Pink"));
users.add(new User(202, "Black"));
ObjectMapper mapper = new ObjectMapper();
List<String> keys = new ArrayList<>();
for (User user : users) {
Map<String, String> userMap = mapper.convertValue(user, Map.class);
String key = "user:" + user.getId();
keys.add(key);
jedis.hmset(key, userMap);
}
for (String key : keys) {
List<String> list = jedis.hmget(key, "Id", "Name", "id");
System.out.println(list);
}
}
//电商购物车
@Test
public void cart() {
// 购物车操作
int userId = 10086;
String cartKey = "cart:" + userId;
Jedis jedis = pool.getResource();
Map<String, Integer> map = new HashMap<>();
map.put("sku30742", 5);
map.put("sku30745", 1);
map.put("sku18764", 1);
map.forEach((String key, Integer value) -> {
for (int i = 0; i < value; i++) {
//增加数量
jedis.hincrBy(cartKey, key, 1);
//删除商品
if (new Random().nextInt(4) == 0) {
jedis.hdel(cartKey, key);
}
}
});
System.out.println("购物车商品总类:" + jedis.hlen(cartKey));
//获取购物车所有商品
Map<String, String> cartData = jedis.hgetAll(cartKey);
cartData.forEach((String key, String v) -> {
System.out.println("商品id:" + key + " 数量:" + v);
});
}
list
常用数据结构
- Stack(栈) = LPUSH + LPOP
- Queue(队列)= LPUSH + RPOP
- Blocking MQ(阻塞队列)= LPUSH + BRPOP
//List 应用场景.微博消息和微信公号消息
@Test
public void msgPool() {
Jedis jedis = pool.getResource();
int userId = 10086;
String msgKey = "msg:" + userId;
//关注用户a发消息
String aMsgId = "1400571";
jedis.lpush(msgKey, aMsgId);
//关注用户b发消息
String bMsgId = "1400856";
jedis.lpush(msgKey, bMsgId);
//关注用户c发消息
String cMsgId = "1401023";
jedis.lpush(msgKey, cMsgId);
System.out.println("未读消息条数:" + jedis.llen(msgKey));
//查看最新消息
List<String> list = jedis.lrange(msgKey, 0, 3);
for (String msgId : list) {
System.out.println("最新消息id:" + msgId);
}
}
set
//微信抽奖小程序
@Test
public void lottery() {
Jedis jedis = pool.getResource();
String lotteryKey = "lottery:20231020";
//查询参与人数
if (jedis.scard(lotteryKey) == 0) {
//参与抽奖的用户
String[] members = new String[50];
for (int i = 0; i < 50; i++) {
var userId = "userId:" + i + 10000;
members[i] = userId;
}
jedis.sadd(lotteryKey, members);
}
//抽取幸运奖
List<String> srandmember = jedis.srandmember(lotteryKey, 5);
System.out.println("幸运奖:" + srandmember);
//抽取n名中奖
for (int i = 1; i <= 3; i++) {
System.out.printf("%d等奖:%s\n", i, jedis.spop(lotteryKey, i));
}
//查看所有参与抽奖的用户
Set<String> smembers = jedis.smembers(lotteryKey);
System.out.printf("剩余用户(%d):%s%n", smembers.size(), smembers);
}
//微信微博点赞,收藏,标签
@Test
public void like() {
Jedis jedis = pool.getResource();
String likeKey = "like:7637471";
String[] users = new String[10];
for (int i = 0; i < 10; i++) {
var userId = "userId:" + i + 10000;
users[i] = userId;
//点赞
long sadd = jedis.sadd(likeKey, userId);
System.out.println(userId + "点赞结果:" + sadd);
//取消点赞
if (new Random().nextInt(3) == 0) {
jedis.srem(likeKey, userId);
}
}
//检查用户是否点过赞
for (String user : users) {
System.out.println(user + " 点赞状态:" + jedis.sismember(likeKey, user));
}
//获取点赞的用户列表
Set<String> smembers = jedis.smembers(likeKey);
//获取点赞用户数
System.out.printf("点赞用户(%d):%s%n", jedis.scard(likeKey), smembers);
}
//集合操作实现微博微信关注模型
@Test
public void friends() {
Jedis jedis = pool.getResource();
String[] users = new String[]{"John","Mark","Anne","Bob","Lucy","Kate","Tom","Paul","guojia"};
String[] users2 = new String[]{"Bob","Lily","Kate","Tom","Dave"};
String[] users3 = new String[]{"Emma","Mary","Anne","Bill","Lucy","Leah","Tom","Paul"};
//诸葛老师关注的人
String k1 = "followed:1305";
jedis.sadd(k1, users);
//杨过老师关注的人
String k2 = "followed:2573";
jedis.sadd(k2, users2);
//郭嘉老师关注的人
String k3 = "followed:4080";
jedis.sadd(k3, users3);
System.out.println("诸葛老师和杨过老师共同关注:" + jedis.sinter(k1, k2));
for (String user : users) {
//todo 获取用户的关注集合,找到对应的人
if (jedis.sismember(k1, "yangguo")) {
System.out.printf("我关注的人[%s]也关注他:\n", user);
}
}
System.out.println("访问郭嘉老师的主页,我可能认识的人:" + jedis.sdiff(k3, k1));
}
zset
//Zset集合操作实现排行榜
@Test
public void rank() {
Jedis jedis = pool.getResource();
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
//生成近七天新闻排行榜,
String[] news = new String[]{
"高燃!我们的光芒闪耀半边天",
"世界互联网大会国际组织会员工作成果",
"落马贪官吃早餐不舍得加鸡蛋",
"金融惠民助消费升温",
"Lisa疯马秀",
"网友晒图:扎心了,历史总是惊人的相似",
"为啥排骨焯水后又腥又柴",
"公办教师调入镇政府工作30年",
"因孩子未完成作业,老师在微信点名批评",
"两三年才换一次手机",
};
String[] dateKeys = new String[7];
for(int i=0; i<7; i++) {
cal.add(Calendar.DAY_OF_MONTH, -1);
Date date = cal.getTime();
String dateKey = "hotNews:" + sdf.format(date);
dateKeys[i] = dateKey;
//点击新闻
for (int j = 0; j < news.length; j++) {
jedis.zincrby(dateKey, new Random().nextInt(10000), news[j]);
}
}
//展示当日排行前十
for (String dateKey : dateKeys) {
System.out.println("===========" + dateKey.replace("hotNews:", "") + "新闻排行 ===========");
List<Tuple> list = jedis.zrevrangeWithScores(dateKey, 0, 9);
for (Tuple tuple : list) {
System.out.println(tuple.getElement() + " 点击数量:" + tuple.getScore());
}
}
//合并七天数据
String combineKey = "hotNews:combine";
long zunionstore = jedis.zunionstore(combineKey, dateKeys);
System.out.println("合并结果:" + zunionstore);
System.out.println("=========== 七日排行前十 ===========");
List<Tuple> tuples = jedis.zrevrangeWithScores(combineKey, 0, 9);
for (Tuple tuple : tuples) {
System.out.println(tuple.getElement() + " 点击数量:" + tuple.getScore());
}
}