认识Redis
认识Redis
- 键值型
- 单线程,每个命令具有原子性
- 低延迟,速度快(基于内存,IO多路复用)
- 支持数据持久化
- 主持主从集群
- 支持多语言客户端
- 默认最多16个库,名称已经给定了,可以设置库的数量
连接Redis
- redis-cli
- -h:指定ip
- -p:指定端口
- -a:指定密码
数据类型
String
"hello world"
Hash
{name: "hu", age: 21}
List
[a -> b -> c]
set
{a, b, c}
SortedSet
{A: 1, B: 2, C: 3}
GEO
{a: (120.3, 30.5)}
BitMap
0101001001010
HyperLog
0101010101
常见指令
help
查看命令的使用
help
select
select index
选择对应的数据库
select 0
选择0号数据库
set
set key value
设置键和键值
set age 21
setnx
setnx key value
当不存在key时存在
返回值1成功,0失败
setnx age 1
setex
setex key seconds value
设置一个键值对并指明过期时间
setex age 10 2
mset
mset k1 v1 k2 v2
批量的去添加键值对
mset age 1 name "jack"
get
get key
获取对应键值
get age
mget
mget k1 k2
获取多个键的值
mget age name
keys
keys pattern
获取,满足正则的键
keys a*
获取所有以a开头的key
del
del key [key1 key2]
删除对应的键值对
del k1 k2 k3
不存在不操作
返回值为真正删除的数量
exists
exists key [k1 k2 k3]
返回存在键存在的数量
expire
expire key seconds
设置一个键的存在秒数
expire age 2
ttl
ttl key
永久有效则返回-1,不存在存在-2
有时效则返回对应剩余时间
ttl age
String类型常见命令补充
incr
incr age
让一个整型的key值自增1
incr age
incrby
incrby age 2
指定步长
incrby age 2
incrbyfloat
让一个浮点型增长指定步长
incrbyfloat money 0.1
Hash
Hash结构
List
类似双向链表
$ LPUSH list el1 el2 el3
# 向左则依次插入el1 el2 el3
# 变成el3<->el2<->el1
Set
用于集合的交差并集等很好用
SortedSet
降序就是
ZREVRANK 这样就是降序了
key的层级结构
项目名:业务名:类型:id
规范就是用:隔开
set a:c:b '{a:1, b:2, c: 3}'
set a:c:d '{a:1, c:2, d: 3}'
在一些软件中这样的就会分层
Java中使用Redis
Jedis
先创建一个连接池
这里存放连接的,当需要连接的时候,如果这里有就从这里取
public class JedisFactory { private static final JedisPool jedisPool; static {// 这个好像叫静态代码块 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 下面是一些配置 jedisPoolConfig.setMaxIdle(10); jedisPoolConfig.setMaxTotal(10); jedisPoolConfig.setMaxWait(Duration.ofSeconds(5)); // 创建对应的连接池 jedisPool = new JedisPool(jedisPoolConfig, "localhost", 6379, 1000, null); } public static Jedis getJedis() { // 返回连接 return jedisPool.getResource(); } }
获取连接
jedis = JedisFactory.getJedis(); // 直接这样就ok了
SpringDataRedis
这就相当于mysql的mybatis了
准备工作
常见操作
连接实践
@Autowired
private RedisTemplate redisTemplate;
@Test
public void setRedisTemplate() {
Object a = redisTemplate.opsForValue().get("a");
// 这样直接获取的在原始操作中key不是a,因为从spring存入的会被对应的序列化器,进行序列化
System.out.println(a);
}
改用序列器
有多个自带的序列器,自行选用
添加下方这个配置类就行
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) throws Exception {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
}
一些小问题
当使用JSON序列化器时,会多存入信息
{"@class":"icu.slovej.springredis.POJO.User","name":"jack","age":20} // 但是要是不存又不能自动反序列化
- 解决方法
2. spring老大哥直接给你整好了
@Test
public void setRedisTemplate() throws JsonProcessingException {
User user1 = new User("jack", 20);
// 手动序列化
String json = jacksonObjectMapper.writeValueAsString(user1);
// 写入数据
redisTemplate.opsForValue().set("user:1", json);
String s = stringRedisTemplate.opsForValue().get("user:1");
// 手动反序列化
User user2 = jacksonObjectMapper.readValue(s, User.class);
System.out.println(user2);
}
// 这样手动进行的就不需要存入额外的内容
实战
短信登陆
添加Redis缓存
缓存三剑客
秒杀
进一步改进乐观锁就是改成判断库存>0就行,这种情况可以这样做
一人一单
加锁
分布式锁
释放锁存在问题,下面解决方案