Redis学习记录
一、五种数据类型及基本操作
1.STRING
1 127.0.0.1:6379> keys * // 查看当前数据库内所有的键 2 (empty list or set) 3 127.0.0.1:6379> set name java // 设置键值对 4 OK 5 127.0.0.1:6379> set age 30 6 OK 7 127.0.0.1:6379> get name // 查询键对应的值 8 "java" 9 127.0.0.1:6379> expire name 20 // 设置键值对的存活时间为20秒 10 127.0.0.1:6379> ttl name // 查询键值对剩余存活时间 11 (integer) 15 12 127.0.0.1:6379> ttl name 13 (integer) 12 14 127.0.0.1:6379> ttl name // 结果为负数,说明键值对已经被删除 15 (integer) -2 16 127.0.0.1:6379> exists name // 查询数据库中是否存在某个键,存在为1,不存在为0 17 (integer) 0 18 127.0.0.1:6379> exists age 19 (integer) 1 20 127.0.0.1:6379> move age 5 // 将键值对移动到编号为5的数据库(Redis默认使用16个数据库,编号0-15) 21 (integer) 1 22 127.0.0.1:6379> exists age // 移动之后,当前数据库已经不存在age 23 (integer) 0 24 127.0.0.1:6379> select 5 // 切换到编号为5的数据库 25 OK 26 127.0.0.1:6379[5]> keys * // age被移动到数据库5中 27 1) "age" 28 127.0.0.1:6379[5]> select 0 29 OK 30 127.0.0.1:6379> set name java 31 OK 32 127.0.0.1:6379> set age 30 33 OK 34 127.0.0.1:6379> type name // 查看key的类型 35 string 36 127.0.0.1:6379> del age // 删除键值对 37 (integer) 1 38 127.0.0.1:6379> flushdb // 删除当前数据库的所有键值对 39 OK 40 127.0.0.1:6379> flushall // 删除所有数据库的所有键值对 41 OK
1 127.0.0.1:6379> set name hello 2 OK 3 127.0.0.1:6379> get name 4 "hello" 5 127.0.0.1:6379> append name java // 在值后边追加字符串 6 (integer) 9 7 127.0.0.1:6379> get name 8 "hellojava" 9 127.0.0.1:6379> strlen name // 查询字符串的长度 10 (integer) 9 11 127.0.0.1:6379> incr age // 自增 12 (integer) 31 13 127.0.0.1:6379> decr age // 自减 14 (integer) 30 15 127.0.0.1:6379> incrby age 10 // 增加任一值 16 (integer) 40 17 127.0.0.1:6379> decrby age 10 // 减小任一值 18 (integer) 30 19 127.0.0.1:6379> getrange name 0 3 // 查询指定位置的子字符串 20 "hell" 21 127.0.0.1:6379> setrange name 1 aaa // 替换指定位置的子字符串 22 (integer) 9 23 127.0.0.1:6379> get name 24 "haaaojava" 25 127.0.0.1:6379> setex name2 10 jackson // 在创建键值对的同时设置存活时间 26 OK 27 127.0.0.1:6379> setnx age 100 // 如果不存在同名键,则创建键值对 28 (integer) 0 29 127.0.0.1:6379> get age // 由于原来存在age=30,所以没有创建成功 30 "30" 31 127.0.0.1:6379> mset name4 aa name5 bb name6 cc // 同时创建多个键值对 32 OK 33 127.0.0.1:6379> msetnx name4 ee name6 ff // 如果原来不存在,创建多个键值对,符合原子性,全都成功或全都失败 34 (integer) 0
2.LIST
127.0.0.1:6379> rpush key1 val1 // 在尾部插入值 (integer) 1 127.0.0.1:6379> rpush key1 val2 (integer) 2 127.0.0.1:6379> rpush key1 val3 (integer) 3 127.0.0.1:6379> rpush key1 val4 (integer) 4 127.0.0.1:6379> lrange key1 0 -1 // 根据下标范围查看值 1) "val1" 2) "val2" 3) "val3" 4) "val4" 127.0.0.1:6379> lpush key1 val5 // 在头部插入值 (integer) 5 127.0.0.1:6379> lrange key1 0 -1 1) "val5" 2) "val1" 3) "val2" 4) "val3" 5) "val4" 127.0.0.1:6379> lpop key1 // 从头部弹出 "val5" 127.0.0.1:6379> rpop key1 // 从尾部弹出 "val4" 127.0.0.1:6379> lindex key1 0 // 根据下标查看值 "val1" 127.0.0.1:6379> lindex key1 1 "val2" 127.0.0.1:6379> lindex key1 2 "val3" 127.0.0.1:6379> llen key1 // 查看列表长度 (integer) 3
3.SET
127.0.0.1:6379> sadd set1 java // 向集合中添加元素 (integer) 1 127.0.0.1:6379> sadd set1 redis (integer) 1 127.0.0.1:6379> sadd set1 mysql (integer) 1 127.0.0.1:6379> SISMEMBER set1 java // 查看成员是否是集合中的变量,存在返回1.不存在返回0 (integer) 1 127.0.0.1:6379> SISMEMBER set1 oracle (integer) 0 127.0.0.1:6379> SMEMBERS set1 // 查看集合中全部成员 1) "mysql" 2) "redis" 3) "java" 127.0.0.1:6379> SREM set1 mysql // 从集合中删除成员 (integer) 1 127.0.0.1:6379> SRANDMEMBER set1 // 从集合中随机得到一个成员 "redis" 127.0.0.1:6379> SPOP set1 1 // 随机弹出1个成员 1) "java" 127.0.0.1:6379> SMOVE set1 set3 redis // 将set1指定成员移动到set3 (integer) 1 127.0.0.1:6379> sadd set1 1 (integer) 1 127.0.0.1:6379> sadd set1 2 (integer) 1 127.0.0.1:6379> sadd set1 3 (integer) 1 127.0.0.1:6379> sadd set3 2 (integer) 1 127.0.0.1:6379> sadd set3 3 (integer) 1 127.0.0.1:6379> sadd set3 4 (integer) 1 127.0.0.1:6379> sdiff set1 set3 // 求set1相对于set3的差集 1) "1" 127.0.0.1:6379> sinter set1 set3 // 求交集 1) "2" 2) "3" 127.0.0.1:6379> sunion set1 set3 // 求并集 1) "redis" 2) "2" 3) "4" 4) "1" 5) "3"
4.HASH
127.0.0.1:6379> hset hash key1 val1 // 在集合中添加键值对 (integer) 1 127.0.0.1:6379> hset hash key2 val2 (integer) 1 127.0.0.1:6379> hget hash key1 // 根据键返回值 "val1" 127.0.0.1:6379> hdel hash key1 // 删除键值对 (integer) 1 127.0.0.1:6379> hgetall hash // 查看所有键值对 1) "key2" 2) "val2"
5.ZSET
与SET相比,ZSET是有序集合,在创建时指定一个score,根据这个score排序
127.0.0.1:6379> zadd zset 10 java // 向集合添加值,score为10 (integer) 1 127.0.0.1:6379> zadd zset 20 mysql (integer) 1 127.0.0.1:6379> zadd zset 30 oracle (integer) 1 127.0.0.1:6379> zrange zset 0 100 // 查看指定范围的值 1) "java" 2) "mysql" 3) "oracle" 127.0.0.1:6379> ZRANGEBYSCORE zset -inf +inf // 对指定范围的值升序排列 1) "java" 2) "mysql" 3) "oracle" 127.0.0.1:6379> ZREVRANGEBYSCORE zset +inf -inf // 降序排列 1) "oracle" 2) "mysql" 3) "java" 127.0.0.1:6379> ZCARD zset // 集合的大小 (integer) 3 127.0.0.1:6379> zrem zset java // 删除集合中的值 (integer) 1
二、事务
事务是指满足ACID原则的一系列操作,包含多个命令,服务器在执行事务期间不会执行其他客户端请求。Redis事务的本质是一组命令的集合,需要注意的是Redis事务不保证原子性,也没有隔离级别。
使用Redis事务包括3步:1.开启事务(multi)2.命令入队 3.执行事务(exec)。事务被执行后就结束了,使用时需要重新开启。如果事务在执行前就结束了(discard), 则事务中的所有命令都不会成功。
127.0.0.1:6379> multi // 开启事务 OK 127.0.0.1:6379> set k1 v1 QUEUED // 命令入队 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> exec // 执行事务 1) OK 2) OK 127.0.0.1:6379> multi // 再次开启事务 OK 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> set k4 v4 QUEUED 127.0.0.1:6379> discard // 废弃事务 OK 127.0.0.1:6379> get k3 // 由于事务被废弃,set k3没有执行,自然get不到 (nil)
需要注意的是,Redis事务不满足原子性,因为它对编译时错误会报错,但是对运行时错误不会,只是抛出相关异常,但是不影响其他语句执行
127.0.0.1:6379> multi OK 127.0.0.1:6379> set k5 v5 // 正常命令 QUEUED 127.0.0.1:6379> sett k6 v6 // sett命令不存在,产生编译时错误 (error) ERR unknown command `sett`, with args beginning with: `k6`, `v6`, 127.0.0.1:6379> exec // 事务无法执行 (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> multi OK 127.0.0.1:6379> set k5 v5 QUEUED 127.0.0.1:6379> incr v5 // 符合语法规则,但是不能对字符串自加,虽然产生运行时错误,但是能正常入队 QUEUED 127.0.0.1:6379> exec // 事务可以执行,而且其他指令正常执行 1) OK 2) (error) ERR value is not an integer or out of range
三、持久化
Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上
1.RDB持久化(默认方式)
在一定时间间隔内将内存中的数据写入到硬盘(snapshot快照),恢复时将快照文件写入到内存。
RDB持久化的触发条件是:1.达到写入次数(在配置文件中设置)2.服务被shutdown 3.使用了flushall命令
触发后在redis启动目录生成一个dump.rdb文件,Redis启东时如果存在这个文件,就恢复其中的数据

具体的过程是:redis创建一个子进程,将数据存入临时文件,写入完成后,替换之前的快照文件
Redis配置文件中对RDB持久化的设置:
触发条件:
分别为900秒后修改1次,300秒后修改10次,60秒后修改10000次
快照文件名:
优点:1.适合大规模的数据存储 2.对数据完整性要求不高
缺点:保存数据需要时间间隔,如果redis发生故障,会丢失最后一次修改过的数据
2.AOF持久化
把每次对数据库的写操作都添加到AOF文件的末尾,通过执行这些命令恢复数据
配置文件对AOF持久化的设置:

always:每个写命令都同步,会严重减低服务器的性能
everysec:每秒同步一次,比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响
no:系统自己决定,不能给服务器性能带来多大的提升,而且也会增加系统崩溃时数据丢失的数量
随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
优点:可以每秒保存一次,减少数据丢失的风险
缺点:速度比rdb慢
四、Jedis连接远程redis
配置文件设置:
1.注释到bind 127.0.0.1, 用来监听所有ip
2.deamonize yes,开启后台运行
3.protected-mode no
4.查看防火墙是否开放了6379端口:firewall-cmd --query-port=6379/tcp,如果结果是no,通过firewall-cmd --add-port=6379/tcp --permanent开放端口
public static void main(String[] args){ Jedis jedis = new Jedis("服务器公网ip", 6379); // 连接服务器 jedis.flushDB(); jedis.set("name","30"); // 用法和之前一样,都在jedis的方法里 System.out.println(jedis.get("name")); }
五、springboot使用redis
1.导入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.在自动配置类里找到redis的自动配置类,查看redis需要配什么



在RedisRroperties里需要配的也就是host和密码(如果设了的话)
public class RedisProperties { /** * Database index used by the connection factory. */ private int database = 0; /** * Connection URL. Overrides host, port, and password. User is ignored. Example: * redis://user:password@example.com:6379 */ private String url; /** * Redis server host. */ private String host = "localhost"; /** * Login password of the redis server. */ private String password; /** * Redis server port. */ private int port = 6379; /** * Whether to enable SSL support. */ private boolean ssl; /** * Connection timeout. */ private Duration timeout; /** * Client name to be set on connections with CLIENT SETNAME. */ private String clientName; private Sentinel sentinel; private Cluster cluster; ........... }
于是在配置文件中配置
spring.redis.host=外网ip
简单配置之后就可以用了,简单测试一下
@SpringBootTest class Redis02SpringbootApplicationTests { @Autowired RedisTemplate redisTemplate; @Test void contextLoads() { redisTemplate.opsForValue().set("username","张三"); System.out.println(redisTemplate.opsForValue().get("username")); } }
可以得到结果,但是在redis中查看已有的键,发现key的名字不对,原因在于没有序列化

没有序列化的原因是RedisTemplate中没有设置序列化:

所以需要重新写一个 RedisTemplate替换原来的,并注入spring容器
@Configuration public class RedisConfig { @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
为什么注入spring容器之后就可以替换掉原来的RedisTemplate呢,因为在RedisAutoConfiguration中规定了如果容器中没有RedisTemplate类,默认的RedisTemplate才生效

六、主从复制
设置一个主服务器并连接多个从服务器,主服务器可写可读,从服务器只能读
为了做实验建立端口为6379,6380,6381的三个redis服务器,6379为主服务器,剩下两个为从服务器。
在建立主从关系之前,所有服务器都是主服务器。
建立主从关系的方式:
1.通过slaveof host port命令
将6380设为6379的从机
![]()
将6381设为6379的从机
![]()
可以通过info replication查看服务器的主从信息



2.通过配置文件设置
在从机的配置文件里添加主机的端口和密码(如果有的话)

浙公网安备 33010602011771号