SpringBoot 整合 Redis
Spring Boot Data(數據) Redis 中提供了 RedisTemplate 和 StringRedisTemplate;
StringRedisTemplate
是 RedisTemplate
的子類,兩個方法基本一致,不同之處在於 操作的數據類型不同:
RedisTemplate
兩個泛型都是 Object,意味着存儲的 key 和 value 都可以是一個對象StringRedisTemplate
兩個泛型都是 String,意味着存儲的 的 key 和 value 都只能是字符串。
注:使用 RedisTemplate
默認是將對象序列化到 Redis 中,所以 放入的對象必須實現對象序列化接口。
注:兩者的 數據是不共通的;也就是說 StringRedisTemplate
只能管理 StringRedisTemplate
裏面的數據,RedisTemplate
只能管理 RedisTemplate
中的數據。
環境準備
引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件
# 連接有redis服務的主機
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
StringRedisTemplate 基本使用
API 是學不完的,掌握一些基本操作,其他操作有需要再查詢即可!
StringRedisTemplate.opsForValue(); // 操作字符串
StringRedisTemplate.opsForHash(); // 操作hash
StringRedisTemplate.opsForList(); // 操作list
StringRedisTemplate.opsForSet(); // 操作set
StringRedisTemplate.opsForZSet(); // 操作有序set
通過@Autowired
註解的方式注入 StringRedisTemplate
對象:
@Autowired
private StringRedisTemplate stringRedisTemplate; // key, value 都是字符串
Key 常用操作
刪除一個 key:
stringRedisTemplate.delete("name"); // 刪除一個key
刪除當前 redis 庫中所有鍵值對:
// 刪除當前redis庫中所有鍵值對
Set<String> keys = stringRedisTemplate.keys("*"); // 查詢出所有的鍵
stringRedisTemplate.delete(keys);
判斷某個 key 是否存在,判斷 key 所對應值的類型:
Boolean hasKey = stringRedisTemplate.hasKey("name"); // 判斷某個key是否存在
DataType type = stringRedisTemplate.type("name"); // 判斷key對應的值的類型
獲取 key 超時時間(-1 永不超時,-2 key不存在,>=0 過期時間)
Long expire = stringRedisTemplate.getExpire("name");
在 redis 中隨機獲取一個 key:
String randomKey = stringRedisTemplate.randomKey();
修改 key 的名字,要求 key 必須存在,不存在則拋出異常:
stringRedisTemplate.rename("name", "newname");
// stringRedisTemplate.renameIfAbsent("age", "newname");
將指定 key 移動到 指定庫:
stringRedisTemplate.move("newname", 1);
String 常用操作
所有字符串的操作都是通過 StringRedisTemplate.opsForValue();
實現。
設置一個 key value:
stringRedisTemplate.opsForValue().set("name", "振宇"); // set 用來設置一個key value
獲取一個 key 對應 value:
String value = stringRedisTemplate.opsForValue().get("name");
設置一個 key 超時時間:
// key:code value:2537 超時時間:120s
stringRedisTemplate.opsForValue().set("code", "2537", 120, TimeUnit.SECONDS);
往指定鍵的值後面 追加 字符串:
stringRedisTemplate.opsForValue().append("name", "他是一個好人!");
List 常用操作
所有 List 的操作都是通過 StringRedisTemplate.opsForList();
實現。
從左邊往列表中放入一個元素:
stringRedisTemplate.opsForList().leftPush("lists", "振宇");
從左邊往列表中放入多個元素(兩種方法):
stringRedisTemplate.opsForList().leftPushAll("lists", "張三", "李四", "王五");
List<String> names = new ArrayList<>();
names.add("xiaoming");
names.add("xiaosan");
stringRedisTemplate.opsForList().leftPushAll("lists", names);
遍歷整個 List:
List<String> stringList = stringRedisTemplate.opsForList().range("lists", 0, -1);// 遍歷list
stringList.forEach(v -> System.out.println("value = " + v));
保留截取的指定區間的 List:
stringRedisTemplate.opsForList().trim("lists", 1, 3);
Set 常用操作
所有 Set 的操作都是通過 StringRedisTemplate.opsForSet();
實現。
創建 Set 並放入多個元素:
stringRedisTemplate.opsForSet().add("sets", "張三", "張三", "李四", "振宇"); // 創建set 並放入多個元素
查看 Set 中所有成員:
Set<String> sets = stringRedisTemplate.opsForSet().members("sets");
sets.forEach(value -> System.out.println("value = " + value));
獲取 Set 中元素個數:
Long size = stringRedisTemplate.opsForSet().size("sets");
ZSet 常用操作
所有 ZSet 的操作都是通過 StringRedisTemplate.opsForZSet();
實現。
創建 ZSet 並放入元素:
stringRedisTemplate.opsForZSet().add("zsets", "小黑", 20);
指定範圍進行查詢:
// 遍歷所有元素
Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);
zsets.forEach(value-> System.out.println(value));
獲取指定元素以及分數(可以指定分數範圍):
// 獲取分數範圍在 0 -1000 之間的元素 並排序
Set<ZSetOperations.TypedTuple<String>> zsets1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("zsets", 0, 1000);
zsets1.forEach(typedTuple ->{
System.out.println("value = " + typedTuple.getValue() + ", score = " + typedTuple.getScore());
});
Hash 常用操作
所有 Hash 的操作都是通過 StringRedisTemplate.opsForHash();
實現。
往指定 Hash 中放入一個 key,value:
stringRedisTemplate.opsForHash().put("maps", "name", "zhangsan");
往指定 Hash 中放入多個 key,value:
Map<String, String> map = new HashMap<>();
map.put("age", "12");
map.put("bir", "2012-12-12");
stringRedisTemplate.opsForHash().putAll("maps", map); // 放入多個key, value
獲取指定 Hash 中某個 key 的 value:
String value = (String) stringRedisTemplate.opsForHash().get("maps", "name");
獲取指定 Hash 中多個 key 的 value:
List<Object> values = stringRedisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age"));
values.forEach(value -> System.out.println(value));
獲取指定 Hash 中所有 key,獲取所有 value:
Set<Object> keys = stringRedisTemplate.opsForHash().keys("maps"); // 獲取所有keys
List<Object> vals = stringRedisTemplate.opsForHash().values("maps"); // 獲取所有values
Key 的綁定操作 Bound
Spring Data 爲了方便我們對 redis 進行更友好的操作,提供了 bound api 簡化操作。
如果日後對某一個 key 的操作極其頻繁,可以將這個 key 綁定到對應 redistemplate
中,可以簡化操作。
boundValueOps
用來對 String 值綁定 keyboundListOps
用來對 List 值綁定 keyboundSetOps
用來對 Set 值綁定 keyboundZSetOps
用來對 ZSet 值綁定 keyboundHashOps
用來對 Hash 值綁定 key
原本代碼可能需要這麼寫:
stringRedisTemplate.opsForValue().set("name", "zhangsan");
stringRedisTemplate.opsForValue().append("name", "是一個好人");
String s = stringRedisTemplate.opsForValue().get("name");
System.out.println(s);
綁定後只需要這麼寫:
BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name");
nameValueOperations.set("zhangsan");
nameValueOperations.append("是一個好人");
String name = nameValueOperations.get();
對 List 進行綁定:
BoundListOperations<String, String> listsOperations = stringRedisTemplate.boundListOps("lists");
listsOperations.leftPushAll("張三", "李四", "小陳");
List<String> lists = listsOperations.range(0, -1);
lists.forEach(list-> System.out.println(list));
redis 中每個數據類型都可以進行綁定,與上面同理。
RedisTemplate 基本使用
RedisTemplate
的用法和 StringRedisTemplate
基本一樣,我們關注他們的不同之處!
RedisTemplate
和 StringRedisTemplate
的區別主要在於他們使用的序列化類:
RedisTemplate
使用的是 JdkSerializationRedisSerializer,存入數據時,會將數據先序列化成字節數組,然後再存入 Redis 數據庫。;StringRedisTemplate
使用的是 StringRedisSerializer;
通過@Autowired
註解的方式注入 RedisTemplate
對象:
@Autowired
private RedisTemplate redisTemplate; //存儲對象
想要存入 redis 的對象必須實現序列化接口:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User implements Serializable { // 實現序列化接口
private String id;
private String name;
private Integer age;
private Date bir;
}
RedisTemplate 基本操作
往 redis 中存入一個 User 對象:
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); // 指定值使用對象序列化
// 往redis中存入一個User對象
redisTemplate.opsForValue().set("user", new User("21", "小黑", 23, new Date()));
// 根據值獲取存入的User對象
User user = (User) redisTemplate.opsForValue().get("user");
System.out.println(user);
需要注意的是,如果通過 redis 客戶端查看其中的數據,無法正常顯示 key 名,如下圖:
RedisTemplate
正常往 redis 中存入 String 數據與 StringRedisTemplate
用法幾乎一樣,但是如果存放的是 String 類型數據則更推薦 StringRedisTemplate
而不是 RedisTemplate
redisTemplate.opsForList().leftPushAll("lists", "hello", "world");
List lists = redisTemplate.opsForList().range("lists", 0, -1);
lists.forEach(list -> System.out.println(list));
RedisTemplate 與 StringRedisTemplate 數據互不相通
RedisTemplate 和 StringRedisTemplate 的數據是不相通的!
1、StringRedisTemplate
往 redis 中存入一個 String 類型的值,分別嘗試獲取值:
RedisTemplate
無法獲取到;StringRedisTemplate
可以獲取到;
stringRedisTemplate.opsForValue().set("name", "zhenyu");
Object name1 = redisTemplate.opsForValue().get("name");
System.out.println(name1); // null
String name2 = stringRedisTemplate.opsForValue().get("name");
System.out.println(name2); // zhenyu
注:如果是在客戶端中操作,視爲使用 StringRedisTemplate
。
2、RedisBuilder
往 redis 中存入一個 User 對象,分別嘗試獲取值:
RedisTemplate
可以獲取到;StringRedisTemplate
無法獲取到;
redisTemplate.opsForValue().set("user", new User("21", "zhenyu", 23, new Date()));
User user1 = (User) redisTemplate.opsForValue().get("user");
System.out.println(user1); // User(id=21, name=zhenyu, age=23, bir=Sat Jul 04 10:17:12 CST 2020)
String user2 = stringRedisTemplate.opsForValue().get("user");
System.out.println(user2); // null
3、RedisTemplate
往 redis 中存入一個 String 類型的值,分別嘗試獲取值:
RedisTemplate
可以獲取到;StringRedisTemplate
無法獲取到;
redisTemplate.opsForValue().set("name", "hello");
Object name1 = redisTemplate.opsForValue().get("name");
System.out.println(name1); // hello
String name2 = stringRedisTemplate.opsForValue().get("name");
System.out.println(name2); // null
Redis 應用場景
上面我們學習的只是 StringRedisTemplate
與 RedisTemplate
的基礎操作,Redis 真正實現的功能都是建立在這些基礎上的,企業中 Redis 的應用場景主要有:
- 利用 Redis 中字符串類型完成 手機驗證碼存儲 的實現;
- 利用 Redis 中字符串類型完成 具有失效性業務功能,例如淘寶的訂單失效時間…
- 利用 Redis 實現分佈式集羣系統中 Session共享;
- 利用 Redis 中 ZSet 類型(可排序的 Set 類型)實現 排行榜功能,
sales(zset) [商品id,商品銷量]
… - 利用 Redis 實現 分佈式緩存;
- 利用 Redis 存儲認證之後 token 信息,例如微信小程序開發中獲取的令牌可能會超時…
- 利用 Redis 解決分佈式集羣系統中分佈式鎖問題;
…