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.通过配置文件设置

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

 

 

 

 

 

 

 

res = res<<1;
posted @ 2020-07-25 23:43  嫩西瓜  阅读(163)  评论(0)    收藏  举报