Redis中StringRedisTemplate中HashOperations的使用詳解
更新時(shí)間:2026年03月12日 14:13:02 作者:蘭舟輕帆
文章介紹了Spring Boot 2中使用Lettuce框架訪問Redis的基本步驟和常用操作,包括添加依賴、注入`StringRedisTemplate`實(shí)例以及進(jìn)行字符串、哈希、集合、列表和有序集合的基本操作,文章還提供了一個(gè)登錄案例,并總結(jié)了個(gè)人經(jīng)驗(yàn),鼓勵(lì)讀者參考和支持
Springboot2默認(rèn)情況下使用lettuce框架訪問Redis
只需要在pom.xml文件添加以下依賴即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency> 在需要訪問Redis的類中注入StringRedisTemplate實(shí)例
@Autowired StringRedisTemplate stringRedisTemplate;
基本用法
// 獲取HashOperations
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
//add
hashOperations.put("user_hash","zhangfei","black face");
//update put會(huì)覆蓋,相當(dāng)于update
hashOperations.put("user_hash","zhangfei","mangfu");
//list 這里感覺叫l(wèi)ist不好叫all吧
Map<String, String> userMap = hashOperations.entries("user_hash"); // entries
Set<String> userKeys = hashOperations.keys("user_hash");// keys
List<String> userValues = hashOperations.values("user_hash"); // values
//delete
hashOperations.delete("user_hash","zhangfei3");
//是否存在
Boolean aBoolean = hashOperations.hasKey("user_hash", "zhangfei"); // 是否存在
簡化String操作方式
@Controller
@RequestMapping("hash")
public class HashController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@ResponseBody
@RequestMapping("/add")
public Map<String,String> add(){
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
hashOperations.put("user_hash","zhangfei","black face"); // put相當(dāng)于添加
hashOperations.put("user_hash","guanyu","red face");
return getAll();
}
@ResponseBody
@RequestMapping("/update")
public Map<String,String> update(){
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
Boolean aBoolean = hashOperations.hasKey("user_hash", "zhangfei"); // 是否存在
System.out.println(aBoolean);
hashOperations.put("user_hash","zhangfei","mangfu"); //put 會(huì)重置,相當(dāng)于update
return getAll();
}
@ResponseBody
@RequestMapping("/all")
public Map<String,String> all(){
return getAll();
}
@ResponseBody
@RequestMapping("/delete")
public Map<String,String> delete(){
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
hashOperations.delete("user_hash","zhangfei3");
return getAll();
}
public Map<String,String> getAll(){
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
Map<String, String> userMap = hashOperations.entries("user_hash"); // entries
final Set<String> userKeys = hashOperations.keys("user_hash"); // keys
List<String> userValues = hashOperations.values("user_hash"); // values
return userMap;
}
}
String(字符串)
private void testValue(){
ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
value.getOperations().delete("aaa"); //刪除
value.getOperations().delete("bbb");
value.set("aaa", "123"); //set
System.out.println(value.setIfAbsent("aaa", "123")); //沒有才set
System.out.println(value.size("aaa")); //長度
System.out.println(value.get("aaa")); //獲取值
value.append("aaa", "456"); //追加
System.out.println(value.get("aaa"));
value.increment("bbb", 1); //數(shù)值自增
System.out.println(value.get("bbb"));
value.multiGet(Arrays.asList("aaa", "bbb", "ccc"))
.stream().forEach(System.out::println);
} Hash(散列)
private void testHash(){
HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
hash.getOperations().delete("hash1");
hash.put("hash1", "aaa", "111"); //put
hash.put("hash1", "bbb", "222");
hash.put("hash1", "ccc", "333");
System.out.println(hash.size("hash1")); //長度
hash.entries("hash1").forEach((k,v) -> { //顯示所有的key和value
System.out.println(k + "=" + v);
});
hash.keys("hash1").stream().forEach(System.out::println); //顯示所有的key
hash.values("hash1").stream().forEach(System.out::println); //顯示所有的value
System.out.println(hash.putIfAbsent("hash1", "aaa", "aaa")); //沒有key才put
hash.increment("hash1", "count", 1); //數(shù)值自增
System.out.println(hash.get("hash1", "count"));
hash.increment("hash1", "count", 1);
System.out.println(hash.get("hash1", "count"));
hash.increment("hash1", "count", -1);
System.out.println(hash.get("hash1", "count"));
System.out.println(hash.hasKey("hash1", "amount")); //判斷key是否存在
System.out.println(hash.get("hash1", "count"));
hash.delete("hash1", "count"); //刪除
} Set(集合)
private void testSet(){
SetOperations<String, String> set = stringRedisTemplate.opsForSet();
set.getOperations().delete("set1");
set.getOperations().delete("set2");
set.add("set1", "111", "222", "333", "111");
set.add("set2", "222", "333", "444");
System.out.println(set.size("set1")); //長度
System.out.println(set.members("set1")); //獲取所有值
System.out.println(set.members("set2"));
System.out.println(set.difference("set1", "set2")); //從前者取得與后者不一樣的元素
System.out.println(set.intersect("set1", "set2")); //交集
System.out.println(set.union("set1", "set2")); //并集
set.remove("set1", "111"); //刪除一個(gè)元素
System.out.println(set.pop("set1")); //彈出一個(gè)元素
System.out.println(set.randomMember("set2")); //隨機(jī)取一個(gè)元素
System.out.println(set.isMember("set2", "444")); //給定元素是否是成員
set.move("set2", "444", "set1"); //移動(dòng)
System.out.println(set.members("set1"));
} List(列表)
private void testList() {
ListOperations<String, String> list = stringRedisTemplate.opsForList();
list.getOperations().delete("list"); //清空
list.leftPush("list", "111"); //push 放到list中
list.leftPushIfPresent("list", "222");
list.rightPush("list", "333");
list.rightPushIfPresent("list", "444");
System.out.println(list.index("list", 0));
System.out.println(list.range("list", 0, -1));
list.trim("list", 0, 2); //截取
System.out.println(list.range("list", 0, -1));
System.out.println(list.leftPop("list")); //pop 取出消費(fèi)掉
System.out.println(list.rightPop("list"));
} Zset(有序集合)
private void testZSet(){
ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
zset.getOperations().delete("zset1");
zset.getOperations().delete("zset2");
zset.add("zset1", "aaa", 1);
zset.add("zset1", "bbb", 1);
zset.add("zset1", "ccc", 1);
zset.add("zset2", "bbb", 1);
zset.add("zset2", "ccc", 1);
zset.add("zset2", "ddd", 1);
System.out.println(zset.size("zset1")); //長度
System.out.println(zset.range("zset1", 0, -1)); //取所有元素
zset.incrementScore("zset1", "bbb", 1); //增加分?jǐn)?shù)score
zset.incrementScore("zset1", "aaa", 2);
System.out.println(zset.range("zset1", 0, -1)); //分?jǐn)?shù)遞增排序
zset.rangeWithScores("zset1", 0, -1).stream().forEach(t -> {
System.out.println(t.getValue() + "-" + t.getScore());
});
System.out.println(zset.reverseRange("zset1", 0, -1)); //分?jǐn)?shù)遞減排序
zset.reverseRangeWithScores("zset1", 0, -1).stream().forEach(t -> {
System.out.println(t.getValue() + "-" + t.getScore());
});
System.out.println(zset.rank("zset1", "ccc")); //分?jǐn)?shù)遞增排序,取元素的索引
System.out.println(zset.reverseRank("zset1", "ccc")); //分?jǐn)?shù)遞減排序,取元素的索引
System.out.println(zset.score("zset1", "bbb")); //取元素的分?jǐn)?shù)
zset.remove("zset2", "bbb"); //刪除元素
System.out.println(zset.range("zset2", 0, -1));
} 登錄案列
package com.cjs.example.controller;
import com.cjs.example.ResponseResult;
import com.cjs.example.domain.LoginRequest;
import com.cjs.example.domain.LoginResponse;
import com.cjs.example.domain.RefreshRequest;
import com.cjs.example.enums.ResponseCodeEnum;
import com.cjs.example.utils.JWTUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
public class LoginController {
/**
* Apollo 或 Nacos
*/
@Value("${secretKey:123456}")
private String secretKey;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 登錄
*/
@PostMapping("/login")
public ResponseResult login(@RequestBody @Validated LoginRequest request, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return ResponseResult.error(ResponseCodeEnum.PARAMETER_ILLEGAL.getCode(), ResponseCodeEnum.PARAMETER_ILLEGAL.getMessage());
}
String username = request.getUsername();
String password = request.getPassword();
// 假設(shè)查詢到用戶ID是01
String userId = "01";
if ("hello".equals(username) && "world".equals(password)) {
// 生成Token
String token = JWTUtil.generateToken(userId, secretKey);
// 生成刷新Token
String refreshToken = UUID.randomUUID().toString().replace("-", "");
// 放入緩存
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
// hashOperations.put(refreshToken, "token", token);
// hashOperations.put(refreshToken, "user", username);
// stringRedisTemplate.expire(refreshToken, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
/**
* 如果可以允許用戶退出后token如果在有效期內(nèi)仍然可以使用的話,那么就不需要存Redis
* 因?yàn)?,token要跟用戶做關(guān)聯(lián)的話,就必須得每次都帶一個(gè)用戶標(biāo)識(shí),
* 那么校驗(yàn)token實(shí)際上就變成了校驗(yàn)token和用戶標(biāo)識(shí)的關(guān)聯(lián)關(guān)系是否正確,且token是否有效
*/
// String key = MD5Encoder.encode(userId.getBytes());
String key = userId;
hashOperations.put(key, "token", token);
hashOperations.put(key, "refreshToken", refreshToken);
stringRedisTemplate.expire(key, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
LoginResponse loginResponse = new LoginResponse();
loginResponse.setToken(token);
loginResponse.setRefreshToken(refreshToken);
loginResponse.setUsername(userId);
return ResponseResult.success(loginResponse);
}
return ResponseResult.error(ResponseCodeEnum.LOGIN_ERROR.getCode(), ResponseCodeEnum.LOGIN_ERROR.getMessage());
}
/**
* 退出
*/
@GetMapping("/logout")
public ResponseResult logout(@RequestParam("userId") String userId) {
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
String key = userId;
hashOperations.delete(key);
return ResponseResult.success();
}
/**
* 刷新Token
*/
@PostMapping("/refreshToken")
public ResponseResult refreshToken(@RequestBody @Validated RefreshRequest request, BindingResult bindingResult) {
String userId = request.getUserId();
String refreshToken = request.getRefreshToken();
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
String key = userId;
String originalRefreshToken = hashOperations.get(key, "refreshToken");
if (StringUtils.isBlank(originalRefreshToken) || !originalRefreshToken.equals(refreshToken)) {
return ResponseResult.error(ResponseCodeEnum.REFRESH_TOKEN_INVALID.getCode(), ResponseCodeEnum.REFRESH_TOKEN_INVALID.getMessage());
}
// 生成新token
String newToken = JWTUtil.generateToken(userId, secretKey);
hashOperations.put(key, "token", newToken);
stringRedisTemplate.expire(userId, JWTUtil.TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);
return ResponseResult.success(newToken);
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
您可能感興趣的文章:
- StringRedisTemplate操作hash實(shí)現(xiàn)過程
- 解決Unboxing of'stringRedisTemplate.hasKey(xx)'may produce 'NullPointerException' 警告問題
- SpringBoot3.4.0無法找到StringRedisTemplate?bean的問題Consider?defining?a?bean?of?type?‘org.springframework
- SpringBoot混合使用StringRedisTemplate和RedisTemplate的坑及解決
- 使用StringRedisTemplate操作Redis方法詳解
- Java中StringRedisTemplate和RedisTemplate的區(qū)別及使用方法
- SpringBoot整合Redis使用RedisTemplate和StringRedisTemplate
- 淺談RedisTemplate和StringRedisTemplate的區(qū)別
相關(guān)文章
React實(shí)現(xiàn)組件之間通信的幾種常用方法
在?React?中,組件之間的通信是構(gòu)建復(fù)雜應(yīng)用程序的核心部分,良好的組件間通信能夠提高代碼的可維護(hù)性和可讀性,同時(shí)能夠高效地管理應(yīng)用狀態(tài),在這篇博客中,我們將探討?React中幾種常用的組件通信方法,并提供示例代碼來幫助你理解,需要的朋友可以參考下2025-02-02
Redis事務(wù),Redis實(shí)現(xiàn)悲觀鎖,樂觀鎖方式
文章介紹了Redis事務(wù)的概念、特點(diǎn)和執(zhí)行過程,區(qū)別于MySQL事務(wù)的ACID特性,詳細(xì)講解了未授權(quán)讀取、授權(quán)讀取、重復(fù)讀取和串行化四種隔離級(jí)別,并解析了悲觀鎖和樂觀鎖的定義與應(yīng)用場景,最后闡述了Redis通過版本號(hào)實(shí)現(xiàn)樂觀鎖的機(jī)制2026-05-05
Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐
實(shí)時(shí)統(tǒng)計(jì)和展示熱門內(nèi)容是一種常見的需求,本文主要介紹了Redis實(shí)現(xiàn)每周熱評的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
Redis?中ZSET數(shù)據(jù)類型命令使用及對應(yīng)場景總結(jié)(案例詳解)
這篇文章主要介紹了Redis?中ZSET數(shù)據(jù)類型命令使用及對應(yīng)場景總結(jié),本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-01-01
Redis實(shí)戰(zhàn)之Redis實(shí)現(xiàn)異步秒殺優(yōu)化詳解
這篇文章主要給大家介紹了Redis實(shí)戰(zhàn)之Redis實(shí)現(xiàn)異步秒殺優(yōu)化方法,文章通過圖片和代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,感興趣的同學(xué)可以自己動(dòng)手試一下2023-09-09
Redis基本數(shù)據(jù)類型Zset有序集合常用操作
這篇文章主要為大家介紹了redis基本數(shù)據(jù)類型Zset有序集合常用操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
redis和redission分布式鎖原理及區(qū)別說明
文章對比了synchronized、樂觀鎖、Redis分布式鎖及Redission鎖的原理與區(qū)別,指出在集群環(huán)境下synchronized失效,樂觀鎖存在數(shù)據(jù)庫性能瓶頸,而Redission通過watchdog自動(dòng)續(xù)期和Lua原子操作解決Redis鎖的超時(shí)問題,推薦其在高并發(fā)場景下的可靠性與易用性2025-08-08

