介绍redis
Redis是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息代理。一般主要使用五大数据类型:字符串(Strings)、列表(Lists)、集合(Sets)、有序集合(Sorted sets)和哈希表(Hashes)。redis还有其它数据结构,如:位图(Bitmaps)、超日志(HyperLogLogs)和地理空间索引半径查询(Geospatial indexes with radius queries)。
特性和使用情况就不过多叙述了
SpringBoot整合redis
导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置
redis:
# Redis服务器地址
host: localhost
# Redis服务器端口号
port: 6379
# 使用的数据库索引,默认是0
database: 0
# 连接超时时间
timeout: 1800000
# 设置密码 默认空
password: ""
lettuce:
pool:
# 最大阻塞等待时间,负数表示没有限制
max-wait: -1
# 连接池中的最大空闲连接
max-idle: 5
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中最大连接数,负数表示没有限制
max-active: 20
模板类 StringRedisTemplate和RedisTemplate
StringRedisTemplate和RedisTemplate都是Spring Data Redis提供的用于操作Redis的模板类。它们都提供了一系列的方法来操作Redis,例如opsForValue()、opsForList()、opsForSet()等。
RedistTemplate自定义序列化
为什么要自定义序列化?
- 效率低:Java的序列化效率相对较低,如果你需要存储大量的数据,或者需要频繁地读写数据,使用Java的序列化可能会成为性能瓶颈。
- 数据不易阅读:Java的序列化结果是二进制数据,这使得在Redis客户端查看数据时很不方便。
- 不支持跨语言:Java的序列化结果只有Java应用才能理解,如果你的Redis需要被其他语言的应用访问,这种序列化方式就不适合。
不使用自定义序列化也可以在java类实现Serializable接口,会被RedisTemplate的默认序列化器JdkSerializationRedisSerializer序列化。或者可显式地配置序列化器,如下代码:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
// 创建模板
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置GenericJackson2JsonRedisSerializer序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// key和 hashKey采用 string序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
// value和 hashValue采用 JSON序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
}
使用RedisTemplate
每种方法的简单例子如下:
public class RedisExample {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// String
public void stringExample() {
// 插入
redisTemplate.opsForValue().set("stringKey", "stringValue");
// 查询
Object value = redisTemplate.opsForValue().get("stringKey");
System.out.println("String value: " + value);
}
// List
public void listExample() {
// 插入
redisTemplate.opsForList().rightPush("listKey", "listValue1");
redisTemplate.opsForList().rightPush("listKey", "listValue2");
// 查询
List<Object> list = redisTemplate.opsForList().range("listKey", 0, -1);
System.out.println("List value: " + list);
}
// Set
public void setExample() {
// 插入
redisTemplate.opsForSet().add("setKey", "setValue1", "setValue2");
// 查询
Set<Object> set = redisTemplate.opsForSet().members("setKey");
System.out.println("Set value: " + set);
}
// Hash
public void hashExample() {
// 插入
redisTemplate.opsForHash().put("hashKey", "field1", "hashValue1");
redisTemplate.opsForHash().put("hashKey", "field2", "hashValue2");
// 查询
Object hashValue1 = redisTemplate.opsForHash().get("hashKey", "field1");
Object hashValue2 = redisTemplate.opsForHash().get("hashKey", "field2");
System.out.println("Hash value1: " + hashValue1);
System.out.println("Hash value2: " + hashValue2);
}
// ZSet
public void zsetExample() {
// 插入
redisTemplate.opsForZSet().add("zsetKey", "zsetValue1", 1);
redisTemplate.opsForZSet().add("zsetKey", "zsetValue2", 2);
// 查询
Set<Object> zset = redisTemplate.opsForZSet().range("zsetKey", 0, -1);
System.out.println("ZSet value: " + zset);
}
}
redis每种数据类型的使用场景
- String(字符串):这是最简单的类型,可以存储字符串、整数或浮点数。常用于存储单个值,如配置项、计数器、验证码、会话数据等。
- List(列表):这是一个字符串列表,按插入顺序排序。常用于实现队列(通过LPUSH/RPOP或RPUSH/LPOP命令)、堆栈(通过LPUSH/LPOP命令)、最近使用列表等。
- Set(集合):这是一个无序的字符串集合。常用于存储无序的唯一元素,如标签、好友关系等。
- Hash(哈希):这是一个键值对集合,适用于存储对象。常用于存储、读取、修改对象属性。
- ZSet(有序集合):这是一个字符串集合,每个元素都关联着一个浮点数分数,元素按分数排序。常用于实现排行榜、带权重的队列等。
以下是使用Redis的五种数据类型(String、List、Set、Hash、ZSet)在特定场景中的使用示例:
- String(字符串):存储登录凭证
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void storeLoginToken(String userId, String token) {
stringRedisTemplate.opsForValue().set("loginToken:" + userId, token);
}
public String getLoginToken(String userId) {
return stringRedisTemplate.opsForValue().get("loginToken:" + userId);
}
- List(列表):实现一个简单的消息队列
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void enqueueMessage(String message) {
redisTemplate.opsForList().rightPush("messageQueue", message);
}
public Object dequeueMessage() {
return redisTemplate.opsForList().leftPop("messageQueue");
}
- Set(集合):存储用户的标签
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void addUserTag(String userId, String tag) {
redisTemplate.opsForSet().add("userTags:" + userId, tag);
}
public Set<Object> getUserTags(String userId) {
return redisTemplate.opsForSet().members("userTags:" + userId);
}
- Hash(哈希):存储用户的属性
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void setUserAttribute(String userId, String attribute, String value) {
redisTemplate.opsForHash().put("user:" + userId, attribute, value);
}
public Object getUserAttribute(String userId, String attribute) {
return redisTemplate.opsForHash().get("user:" + userId, attribute);
}
- ZSet(有序集合):实现一个排行榜
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void addUserScore(String userId, double score) {
redisTemplate.opsForZSet().add("leaderboard", userId, score);
}
public Set<Object> getTopUsers(int topN) {
return redisTemplate.opsForZSet().reverseRange("leaderboard", 0, topN - 1);
}
6.简单分布式锁
public class RedisLock {
private final StringRedisTemplate redisTemplate;
public RedisLock(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 获取锁
* @param key 锁的key
* @param timeout 锁的超时时间
* @return 是否获取成功
*/
public boolean lock(String key, long timeout) {
ValueOperations<String, String> ops = redisTemplate.opsForValue();
Boolean success = ops.setIfAbsent(key, "lock", timeout, TimeUnit.SECONDS);
return success != null && success;
}
/**
* 释放锁
* @param key 锁的key
*/
public void unlock(String key) {
redisTemplate.delete(key);
}
}