開發工具:
- Redis3.2;
- IDEA;
- JDK11;
- Gradle4.8;
使用數據結構常用命令:
1.創建項目,開啓Redis服務端,導入相關座標;
重要座標如下:
implementation('org.springframework.boot:spring-boot-starter-data-redis')
// Redis客戶端,用於執行數據結構常用命令
implementation('redis.clients:jedis:2.9.0')
2.添加配置類(SpringBoot默認自動配置,沒有特殊需求則可以省略);
配置類代碼如下:
package com.lsm1998.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
* 作者:劉時明
* 日期:2018/11/12
* 時間:21:13
* 說明:
*/
@Configuration
public class RedisConfig
{
@Bean
public RedisTemplate initRedisTemplate()
{
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 最大空閒數
poolConfig.setMaxIdle(5);
// 最大連接數
poolConfig.setMaxTotal(30);
// 最大等待毫秒數
poolConfig.setMaxWaitMillis(1000 * 20);
// 連接工廠
JedisConnectionFactory factory=new JedisConnectionFactory(poolConfig);
// 後初始化方法
factory.afterPropertiesSet();
// 序列化器
//RedisSerializer jdkSerializer=new JdkSerializationRedisSerializer();
RedisSerializer stringSerializer=new StringRedisSerializer();
// 定義RedisTemplate,設置連接工廠
RedisTemplate redisTemplate=new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
// 設置序列化器
redisTemplate.setDefaultSerializer(stringSerializer);
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
return redisTemplate;
}
}
3.具體程序如下:
package com.lsm1998.redis.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 作者:劉時明
* 日期:2018/11/12
* 時間:21:49
* 說明:Redis基本數據類型
*/
@RestController
public class TestController
{
@Autowired
private RedisTemplate redisTemplate;
/**
* 字符數據的常用命令
*
* @return
*/
@GetMapping("test1")
public Object test1()
{
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 設置鍵值對
jedis.set("str_1", "新恆結衣");
// 返回值的字符長度
System.out.println("值的長度=" + jedis.strlen("str_1"));
// 獲取值
System.out.println("str_1=" + jedis.get("str_1"));
// 刪除鍵值對
//jedis.del("str_1");
// 修改值,並返回新值
String str = jedis.getSet("str_1", "泰勒斯威夫特");
System.out.println("str_1舊值=" + str);
System.out.println("str_1新值=" + jedis.get("str_1"));
// 獲取子串
System.out.println("str_1子串=" + jedis.getrange("str_1", 0, jedis.strlen("str_1") / 2));
// 追加字符,只支持末尾追加
jedis.append("str_1", "-Red");
System.out.println("str_1=" + jedis.get("str_1"));
// 字節數組組成的鍵值對
jedis.getSet("str_2".getBytes(), "新恆結衣".getBytes());
System.out.println("str_2=" + jedis.get("str_2".getBytes()));
// 關閉連接
jedis.close();
return "ok";
}
/**
* 字符數據的計算命令
*
* @return
*/
@GetMapping("test2")
public Object test2()
{
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.set("num", "0");
System.out.println("num=" + jedis.get("num"));
// 指定key值自增
jedis.incr("num");
System.out.println("num=" + jedis.get("num"));
// 指定增加
jedis.incrBy("num", 10L);
System.out.println("num=" + jedis.get("num"));
// 指定key值自減
jedis.decr("num");
System.out.println("num=" + jedis.get("num"));
// 指定減少
jedis.decrBy("num", 5L);
System.out.println("num=" + jedis.get("num"));
// 操作浮點數,此方法沒有對應的decrByFloat方法,只需加一個負號即可取得相同效果
jedis.incrByFloat("num", 3.14);
System.out.println("num=" + jedis.get("num"));
jedis.incrByFloat("num", -3.14);
System.out.println("num=" + jedis.get("num"));
// 關閉連接
jedis.close();
return "ok";
}
/**
* 哈希結構的常用命令
*
* @return
*/
@GetMapping("test3")
public Object test3()
{
HashOperations hashOperations = redisTemplate.opsForHash();
// 指定一個key
String key = "hash";
// 一個key下保存多個鍵值對
hashOperations.put(key, "k1", "新恆結衣");
hashOperations.put(key, "k2", new byte[1024]);
try
{
// 此處會拋出異常
hashOperations.put(key, "k3", new Object());
} catch (Exception e)
{
System.err.println("該對象不可以被序列化");
}
// Jedis操作哈希數據結構,與HashOperations有一定區別
Jedis jedis = new Jedis("127.0.0.1", 6379);
// jedis.hset保存的是field+value,而與HashOperations則是hashKey+value
jedis.hset(key, "j1", "泰勒斯威夫特");
// 編譯錯誤,只支持字符串類型
//jedis.hset(key, "j2", new ArrayList<>());
System.out.println("當前大小=" + hashOperations.size(key));
// 通過遍歷key來輸出所有的鍵值對
hashOperations.keys(key).forEach(k -> System.out.println("key=" + k + ",value=" + hashOperations.get(key, k)));
return hashOperations.get(key, "k1");
}
/**
* 有序集合結構的常用命令
*
* @return
*/
@GetMapping("test4")
public Object test4()
{
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
String key = "key";
// 添加元素,key-value-score形式,score代表分數,用於排序
zSetOperations.add(key, 59, 2.5);
zSetOperations.add(key, new String("新恆結衣"), 3.0);
ZSetOperations.TypedTuple<Object> typedTuple1 = new DefaultTypedTuple<>("牛頓", 100.0);
ZSetOperations.TypedTuple<Object> typedTuple2 = new DefaultTypedTuple<>("伯努利", 98.0);
Set<ZSetOperations.TypedTuple<Object>> typedTupleSet = new HashSet<>();
typedTupleSet.add(typedTuple1);
typedTupleSet.add(typedTuple2);
// 添加元素,key-Set形式
zSetOperations.add(key, typedTupleSet);
long size = zSetOperations.zCard(key);
// 此時應該有4個元素,因爲key-Set其底層會拆爲key-value-score形式
System.out.println("元素個數=" + size);
// 獲取所有元素
Set temp = zSetOperations.range(key, 0, size - 1);
long count = zSetOperations.count(key, 80, 100);
System.out.println("分數80到100之間元素個數=" + count);
// 返回分數80到100之間的元素集合
// Set temp = zSetOperations.rangeByScore(key, 80, 100);
// 刪除元素,可以同時傳入多個值
zSetOperations.remove(key, 59);
// 根據分數範圍進行刪除
// zSetOperations.removeRangeByScore(key,80,100);
temp.forEach(e -> System.out.println(e));
// Jedis操作ZSet類型
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.zadd(key, -10.0, "hello");
Set temp2 = jedis.zrevrange(key, 0, jedis.zcard(key) - 1);
System.out.println("**********華麗的分隔線**********");
// 此時長度爲1
// 與HashOperations相似,Jedis操作的ZSet和ZSetOperations操作的ZSet是有區別的,二者不能混用
System.out.println("長度=" + jedis.zcard(key));
temp2.forEach(e -> System.out.println(e));
// 計算多個有序集合的並集
String destKey = "dest_key";
// 添加一個同value同score的元素
redisTemplate.opsForZSet().add(destKey, "新恆結衣", 3.0);
// 添加一個同value但不同score的元素
redisTemplate.opsForZSet().add(destKey, "新恆結衣", 3.1);
// 此處結果與unionAndStore(key, key, destKey)一致,結果返回3,代表有3個value相同的元素
long l = zSetOperations.unionAndStore(key, destKey, destKey);
System.out.println("相同value元素數量=" + l);
return "ok";
}
/**
* 鏈表結構
*
* @return
*/
@GetMapping("test5")
public Object test5()
{
/**
* Jedis操作鏈表
*/
Jedis jedis = new Jedis("127.0.0.1", 6379);
String key = "j_key";
// 左端插入
jedis.lpush(key, "左一", "左二", "左三");
// 右端插入
jedis.rpush(key, "右一", "右二", "右三");
// 下標獲取
System.out.println("鏈表頭部元素=" + jedis.lindex(key, 0));
// 最右側刪除
jedis.rpop(key);
// 最左側刪除
jedis.lpop(key);
// 更新元素
jedis.lset(key, 1, "新值");
// 嘗試最左側插入,如果key不存在則失敗,返回0
long result = jedis.lpushx(key + "007", "嘗試");
System.out.println("result=" + result);
// 從左到右刪除1個value爲‘右二’的元素,0則代表所有
jedis.lrem(key, 1, "右二");
// 元素插入,指定BEFORE或者AFTER和元素
jedis.linsert(key, BinaryClient.LIST_POSITION.AFTER, "新值", "插隊元素");
// 鏈表裁剪,只保留下標0到5的,裁剪後長度必爲end-strrt+1,如果少了則循環補值
jedis.ltrim(key, 0, 5);
// 打印0到5的節點值,此時數據爲[左二, 新值, 插隊元素, 新值, 插隊元素, 新值],奇怪的是頭元素不會補值
System.out.println(jedis.lrange(key, 0, 5));
System.out.println("jedis鏈表長度=" + jedis.llen(key));
// 阻塞命令,試圖刪除最左側元素,如果沒有則等待,直到刪除成功或者超時,並返回key和被刪除的元素
List<String> list = jedis.blpop(10 * 1000, key);
System.out.println("list=" + list);
/**
* ListOperations操作鏈表
* 寫多了就會發現redisTemplate包裝類和jedis操作的功能大體一致,但效果不互通
*/
ListOperations listOperations = redisTemplate.opsForList();
// 刪除前兩個‘hello’
listOperations.remove(key, 2, "hello");
System.out.println("redisTemplate包裝類鏈表長度=" + listOperations.size(key));
return "ok";
}
/**
* Set結構
*
* @return
*/
@GetMapping("test6")
public Object test6()
{
Jedis jedis = new Jedis("127.0.0.1", 6379);
String key = "j_key";
// 插入元素,由於是散列結構,重複元素會覆蓋
jedis.sadd(key, "新恆結衣", "Aragaki", "新恆結衣");
// 統計個數
System.out.println("元素個數=" + jedis.scard(key));
// 判斷元素是否存在
System.out.println("一個元素是否存在?" + jedis.sismember(key, "新恆結衣"));
// 獲取所有鍵
Set<String> keys = jedis.keys(key);
keys.forEach(e -> System.out.println(e));
// 獲取所有值
jedis.smembers(key).forEach(e -> System.out.println(e));
// 隨機彈出一個元素
System.out.println(jedis.spop(key));
SetOperations setOperations = redisTemplate.opsForSet();
setOperations.add("key_1", "e1", "e2", "e3");
setOperations.add("key_2", "e0", "e1", "e2");
// 求差集
setOperations.difference("key_1", "key_2").forEach(e -> System.out.println(e));
// 求並集
setOperations.intersect("key_1", "key_2").forEach(e -> System.out.println(e));
return "ok";
}
/**
* 基數結構
*
* @return
*/
@GetMapping("test7")
public Object test7()
{
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 添加一個元素
jedis.pfadd("key", "新恆結衣");
// 返回基數值
System.out.println("基數值=" + jedis.pfcount("key"));
// 保存多個基數值
jedis.pfmerge("key2", "新恆結衣", "Aragaki");
HyperLogLogOperations hyperLogLogOperations = redisTemplate.opsForHyperLogLog();
hyperLogLogOperations.add("key", "新恆結衣");
hyperLogLogOperations.size("key");
hyperLogLogOperations.delete("key");
return "ok";
}
}
Redis的6種數據結構總結:
- 有兩種不同的方式可以操作數據,Jedis客戶端執行與redisTemplate包裝類均有類似的操作方法,但操作的數據不互通;
- 都可以實現基本的增刪改查;
- 除了Hash結構和鏈表結構外,其餘結構都具有一定的運算支持,自增或者求並集等;
- 基數類型是最晦澀難懂的,他的原理是壓縮數據,將重複的數據轉爲不重複的基數,減少內存佔用;