Redis 简介
redis 是以 key-value 形式存储,和传统的关系型数据库不一样,不一定遵循传统数据库的一些基本要求。redis 是非关系型的,分布式的,开源的,水平可拓展的
优点:
- 对数据高并发读写(直接是内存中进行读写的)
- 对海量数据的高效率存储和访问
- 对数据的可拓展性和高可用性
- 单线程操作,每个操作都是原子操作,没有并发相关问题
缺点:
- 无法做太复杂的关系数据库模型
关系型数据库和非关系型数据库的区别
| 数据模型 | 表格结构,多个表之间有关联 | 灵活模型(文档、键值、图等) |
| 查询能力 | SQL标准,强一致性 | 多样化查询语法 |
| 事务支持 | 强事务 | 弱事务或有限支持 |
| 适用场景 | 数据结构稳定 | 高扩展需求、灵活模式或特殊数据结构 |
数据类型及常用命令
String 字符串
| set key value | 存入或修改键值对 |
| get key | 根据键取出值 |
| incr key | 自增 |
| decr key | 自减 |
| del key | 根据键删除值 |
| setex key timeout value | 存入或修改键值对,并设置过期时间 |
| ttl key | 查询 key 的过期时间,-1为无过期时间,-2为已失效 |
| setnx key value | 存入键值对,如果已存在,则不做操作 |
| incrby key num | 将当前的值增加 num |
| decrby key num | 将当前的值减少 num |
| mset k1 v1 k2 v2 … | 批量存入或修改键值对 |
| mget k1 k2 … | 批量获取键值对 |
| append key value | 尾部追加值 |
| setrange key index value | 在当前字符串的指定位置增加 |
Hash 表
| hset key hashkey hashvalue | 设置一个 hash 对象的键值对 |
| hget key hashkey | 根据 hash 对象的键获取值 |
| hexists key hashkey | 判断这个 hash 对象是否有这个键 |
| hdel key hashkey | 根据 hashkey 删除某个 hash 键值对 |
| hincrby key hashkey | 递增 hash 的值 |
| hlen key | 获取 hash 对象 key 的数量 |
| hkeys key | 获取 hash 对象的所有的键 |
| hvals key | 获取 hash 对象的所有的值 |
| hgetall key | 获取 hash 对象的所有数据 |
| hsetnx key hashkey hashvalue | 存入一个 hash 对象的键值对,如果有则不做操作 |
List 列表
| rpush/lpush key value | 往列表右/左边添加数据 |
| lrange key start end | 范围显示列表数据,全显示则设置0 -1 |
| lpop/rpop key | 弹出列表最左/右边的数据 |
| llen key | 获取列表长度 |
| linsert key before/after refVal value | 参考值之前/后插入数据 |
| lset key index value | 根据索引修改数据 |
| lrem key count value | 在列表中按照个数删除数据 |
| ltrim key start end | 范围截取列表 |
| lindex key index | 根据索引获取列表数据 |
Set 无序集合
| sadd key value | 往 set 集合中添加元素 |
| smembers key | 列出 set 集合中的元素 |
| srem key value | 删除 set 集合中的元素 |
| spop key count | 随机弹出集合中的元素 |
| sdiff key1 key2 | 返回 key1 中特有元素(差集) |
| sinter key1 key2 | 返回两个 set 集合的交集 |
| sunion key1 key2 | 返回两个 set 集合的并集 |
| sdiffstore/sinterstore/sunionstore var k1 k2 | 取交集/并集/差集后,将返回值放到另一个 set 里 |
| smove key1 key2 value | 把 key1 中的某元素移入 key2 中 |
| scard key | 返回set集合中元素个数 |
| sismember key value | 判断集合是否包含某个值 |
| srandmember key count | 随机获取 set 集合中元素 |
zSet 集合
| zadd key score value | 存入分数和名称 |
| zincrby key score column | 偏移名称对应的分数 |
| zrange key start end | 按照分数升序输出名称 |
| zrevrange key start end | 按照分数降序输出名称 |
| zrank key name | 升序返回排名 |
| zrevrank key name | 降序返回排名 |
| zcard key | 返回元素个数 |
| zrangebyscore key min max [withscores] | 按照分数范围升序输出名称 |
| zrevrangebyscore key max min [withscores] | 按照分数范围降序输出名称 |
| zrem key name | 删除名称和分数 |
| zremrangebyscore key min max [withscores] | 根据分数范围删除元素 |
| zremrangebyrank key start end | 根据排名删除元素 |
| zcount key min max | 按照分数范围统计个数 |
事务
| multi | 开启事务 |
| exec | 提交事务 |
| discard | 取消事物 |
其他高级命令
| keys name | 查询所有的 key 名,可以用 * 模糊查询 |
| exists key | 查询是否存在 key |
| expire key | 设置某个 key 的过期时间 |
| persist key | 取消 key 的过期时间 |
| flushdb/flushall | 清空当前库/清空所有库 |
| select number | 选择库(0~15) |
| move key index | 将 key 移动到第 index 个数据库 |
| randomkey | 随机返回数据库中的key |
| rename key newkey | 重命名 |
| dbsize | 查看数据库的key数量 |
| **info ** | 获取数据库信息 |
| **config get ** | 实时传储收到的请求(返回相关的配置信息) |
| **config get * ** | 返回所有配置 |
理论部分
选择数据类型的原则
如果确定使用redis, 此时需要考虑使用哪个数据类型
有些公司约定: 所有的 redis 的 key 跟 value 都使用字符串,如果使用排序,就用 zset,因为这样:
- 可以避免泛型的使用
- 方便转换字符串
Key 的设计
key的设计:
持久化机制
RDB
默认方式。将内存中以快照的方式写入到二进制文件中.默认为dump.rdb。可以配置设置自动做快照持久化方式。我们可以配置 redis 在 n 秒内如果超过 m 个 key 就修改自动做快照。
执行 save 命令,或 flushdb/flushalll 命令时,会直接触发 RDB
save 900 1 #900秒内如果超过1个Key被修改则发起快照保存
save 300 10
save 60 10000
AOF
aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到命令中,当redis重新启动时会重新执行文件中保存的写命令来在内存中重建这个数据库的内容.这个文件在bin目录下:appendonly.aof
appendonly yes //启动aof持久化方式有三种修改方式
#appendfsync always//收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化
#appendfsync everysec//每秒写入磁盘一次,在性能和持久化方面做了很好的折中
#appendfsync no //完全以依赖os 性能最好,持久化没保证
总结
- RDB 性能好,但是易丢失数据
- AOF 性能差,但是不易丢失数据
内存淘汰机制
常见的内存淘汰机制分为四大类:
1. LRU:LRU是Least recently used,最近最少使用的意思,简单的理解就是从数据库中删除最近最少访问的数据,该算法认为,你长期不用的数据,那么被再次访问的概率也就很小了,淘汰的数据为最长时间没有被使用,仅与时间相关。
2. LFU:LFU是Least Frequently Used,最不经常使用的意思,简单的理解就是淘汰一段时间内,使用次数最少的数据,这个与频次和时间相关。
3. TTL:Redis中,有的数据是设置了过期时间的,而设置了过期时间的这部分数据,就是该算法要解决的对象。如果你快过期了,不好意思,我内存现在不够了,反正你也要退休了,提前送你一程,把你干掉吧。
4. 随机淘汰:生死有命,富贵在天,是否被干掉,全凭天意了。
Key 删除策略
Redis中大家会对存入的数据设置过期时间,那么这些数据如果过期了,Redis是怎么样把他们消灭掉的呢?我们一起来探讨一下。下面介绍三种清除策略:
-
惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key如果长期不用,一直存在内存里,会造成内存浪费。
-
定时删除:设置键的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行对Key的删除操作,这种方式最不友好。
-
定期删除:隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法决定。举个例子方便大家理解:Redis每秒随机取100个数据进行过期检查,删除检查数据中所有已经过期的Key,如果过期的Key占比大于总数的25%,也就是超过25个,再重复上述检查操作。
集成 Java 应用
Jedis
导入依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
基本操作
// 创建Jedis连接池
JedisPool pool = new JedisPool("localhost", 6379);
// 从连接池中获取Jedis对象
Jedis jedis = pool.getResource();
jedis.auth("123456"); // 密码
// TODO: 执行逻辑
System.out.println(jedis);
// 关闭资源,销毁连接池
jedis.close();
pool.destroy();
细节配置
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
//最大连接数, 默认8个
config.setMaxTotal(100);
//最大空闲连接数, 默认8个
config.setMaxIdle(20);
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
config.setMaxWaitMillis(–1);
//在获取连接的时候检查有效性, 默认false
config.setTestOnBorrow(true);
JedisPool pool = new JedisPool(config,"192.168.122.128",6379,5000,"wolfcode");
Jedis j = pool.getResource();
String name = j.get("name");
System.out.println(name);
j.close();
pool.close();
pool.destroy();
之后调用的方法名同以上命令名
集成 SpringBoot
导入依赖:
<!– SpringBoot 父类 –>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.3.RELEASE</version>
</parent>
<!– SpringBoot 集成 redis –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!– SpringBoot 测试 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
password:
基本操作
@Autowired
private StringRedisTemplate redisTemplate;
@Test
public void testRedisTemplate() {
// 操作string
redisTemplate.opsForValue().set("name", "LTT");
// 操作hash
redisTemplate.opsForHash().put("user", "name", "LTT");
// 操作list
redisTemplate.opsForList().leftPush("hobby", "唱");
// 操作set
redisTemplate.opsForSet().add("颜色", "红", "黄", "蓝");
// 操作zset
redisTemplate.opsForZSet().add("名单", "小明", 100);
}




