Redis简易教程

6 篇文章 1 订阅

Redis

数据类型

查看帮助:help 命令名;例如:help set;

string类型

redis中只有字符串,没有num,但如果字符串里全是数字的话可以当成是数字使用;

数字上限是java中long类型的最大值;

数据容量的最大上限是512MB;

基操

存:set key value;

取:get key;

删:del key;

存多个:mset key1 value1 key2 value2;

取多个:mget key1 key2;

字符串长度:strlen key

追加信息到原字符串:append key value

数字操作

自增1:incr key

自增任意整数:incrby key 任意整数

自增任意小数:incrbyfloat key 任意小数

自减1:decr key

自减任意整数:decrby key 任意整数

时效操作

设置秒数:setex key seconds value

设置毫秒数:psetex key miliseconds value

hash类型

hash的键在redis中称为field,而redis的键称为key;

hash类型的值就是字符串,不存在其他类型(不能嵌套);

基操

存:hset key field value

取:hget key field

取全部:hgetall key

删除:hdel key field1 field2 ……

存多个:hmset key field1 value1 field2 value2 ……

取多个:hmget key field1 field2 ……

获取字段数量:hlen key

查询指定字段是否存在:hexists key field

获取所有字段名:hkeys key

获取所有字段值:hvals key

没有这个字段就存,有的话啥也不干:hsetnx key field value

数字操作

自增任意整数:hincrby key field 任意整数

自增任意小数:hincrbyfloat key field 任意小数

list类型

list在redis中用双向链表实现

基操

左插:lpush key value

右插:rpush key value

按索引查询:lrange key index1 index2

查询全部:lrange key 0 -1

查询单个:lindex key index

查询长度:llen key

左删:lpop key

右删:rpop key

删除指定个数指定值:lrem key count value

消息队列

取的时候等一段时间:blpop key1 key2 …… seconds

与上面的同理也可以:brpop key2 key2 …… seconds,如果能取到,就取出,否则只要在seconds秒中等待取出;

set类型

set类型的实现与hash类型相同,只不过将value全部设置成了nil

基操

添加:sadd key value

删除:srem key value

查询全部:smembers key

获取set长度:scard key

是否为set元素:sismember key value

随机操作

随机获取数据(不弹出set):srandmember key [count],可指定数量,不指定则默认获取1个;

随机获取数据(弹出set):spop key [count],可指定数量,不指定则默认弹出1个;

集合运算操作

求set交集:sinter key1 key2 [……]

求set并集:sunion key1 key2 [……]

求set差集:sdiff key1 key2 [……]

将set交集存到另一个集合中:sinterstrore 目标集合 key1 [……]

将set并集存到另一个集合中:sunionstrore 目标集合 key1 [……]

将set差集存到另一个集合中:sdiffstrore 目标集合 key1 [……]

set间的元素移动:smove source destination member

sorted_set类型

sorted_set是一个有序的集合,顺序由插入时给定的得分决定,注意我们并不使用得分来存储数据,它仅仅是为了排序

基操

添加:zadd key score1 value1 [……]

升序查询:zrange key index1 index2

降序查询:zrevrange key index1 index2

删除:zrem key value

查询时带上得分:zrange key index1 index2 withscores

获取set长度:zcard key

获取元素索引:zrank key element

获取元素索引(反向):zrevrank key element

获取元素得分:zscore key element

修改元素得分:zincr key increment element

条件操作

按得分区间升序查询:zrangebyscore key min max [limit],limit类似于mysql中的limit,可以限定查询个数

按得分区间降序查询:zrevrangebyscore key min max

按索引删除:zremrangebyrank key index1 index2

按得分区间删除:zremrangebyscore key min max

按得分查询set长度:zcount key min max

集合运算操作

交:zinterstore destination key1 [……]

并:zunionstore destination key1 [……]

通用操作

key的操作

基操

删除key:del key

是否存在:exists key

查看value类型:type key

查询key:keys pattern,pattern类似于正则的写法,*匹配任意,?匹配单个字符,[]匹配指定符号

改名:rename key newkey,若newkey本身存在会被覆盖

改名:renamenx key newkey,只有newkey不存在时才改名

排序:sort key,注意排序操作不会改变值本身的结构

时效操作

设置有效时长(秒):expire key seconds

设置有效时长(毫秒):pexpire key miliseconds

设置有效时长(时间戳):expireat key timestamp

设置有效时长(毫秒+时间戳):pexpireat key miliseconds-timestamp

获取有效时长(秒):ttl key

获取有效时长(毫秒):pttl key

将有效期设置为永久:persist key

db的操作

一个redis服务会将空间划分成16个区域,编号0~15;

基操

选择数据库:select num,num的范围是0~15;

退出:quit

网络测试:ping

输出信息:echo message

数据移动:move key db

查看当前数据库key的总量:dbsize

删除当前库所有key:flushdb

删除所有库所有key:flushall,慎用!!!

Jedis

基本使用

maven坐标:

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

简单来说就三个步骤:连接、操作、断开

package com.jedis;
import org.junit.Test;
import redis.clients.jedis.Jedis;

public class TestJedis1 {
	
	@Test
	public void testJedis() {
		//1.连接
		Jedis jedis = new Jedis("127.0.0.1",6379);
		//2.操作
		jedis.set("hello","hello world");
		//3.断开
		jedis.close();
	}
}

列表和哈希的使用

jedis中方法的操作和redis中的指令是一样的,下面给出list和hash的例子;

list:

@Test
public void testList() {
    Jedis jedis = new Jedis("127.0.0.1",6379);
    jedis.lpush("list1","a","b","c");
    List<String> list = jedis.lrange("list1", 0, -1);
    for(String s:list) {
        System.out.println(s);
    }
    System.out.println(jedis.llen("list1"));
    jedis.close();
}

hash:

@Test
public void testHash() {
    Jedis jedis = new Jedis("127.0.0.1",6379);
    jedis.hset("hash1", "name","ljj");
    jedis.hset("hash1", "age","24");
    jedis.hset("hash1", "sex","male");
    Map<String,String> map = jedis.hgetAll("hash1");
    for(String s:map.keySet()) {
        System.out.println(s+":"+map.get(s));
    }
    jedis.close();
}

工具类的封装

redis.properties

redis.host=127.0.0.1
redis.port=6379
redis.maxTotal=30
redis.maxIdle=10

工具类封装

package com.jedis;

import java.util.ResourceBundle;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisUtils {
	private static JedisPool jp = null;
	private static String host = null;
	private static int port;
	private static int maxTotal;
	private static int maxIdle;
	static {
		ResourceBundle rb = ResourceBundle.getBundle("redis");
		host = rb.getString("redis.host");
		port = Integer.valueOf(rb.getString("redis.port"));
		maxTotal = Integer.valueOf(rb.getString("redis.maxTotal"));
		maxIdle = Integer.valueOf(rb.getString("redis.maxIdle"));
		JedisPoolConfig jpc = new JedisPoolConfig();
		jpc.setMaxIdle(maxIdle);
		jpc.setMaxTotal(maxTotal);
		jp = new JedisPool(jpc, host, port);
	}

	public static Jedis getJedis() {
		return jp.getResource();
	}
}

Linux下的基本使用

ubuntu为例:apt install redis-server

默认配置文件在/etc/redis

启动:redis-server 配置文件

关闭:redis-cli shutdown

持久化

rdb

配置文件中配置属性dir,这个就是默认的rdb生成目录;

每当你在客户端里save一次,rdb文件就会更新一次;

默认的名称是dump.rdb,可以修改;

相关配置如下:

port 6379
daemonize yes
logfile redis-6379.log
dir /etc/redis
dbfilename dump-6379.rdb 
rdbcompression yes #是否压缩
rdbchecksum yes #是否校验

做一个试验你就会发现,即使服务端关了,重启之后还是能拿到之前save的数据。

但是save指令可能会很耗资源,所以就有了另一个异步 指令:bgsave,在后台保存数据;

如何让redis自动save呢?

save seconds changes

配置文件中配上这个就行了,代表多少秒内发生了多少次变化就自动dbsave一次;

aof

这是redis持久化的另一种策略,他不记录数据,而是记录指令;当redis服务重启的时候重新执行一遍这些指令,那么这些数据就又回来了;

配置时需要开启aof功能:appendonly yes

同时需要指定记录指令的方式,一共有三种方式:

  1. always:总是记录;
  2. everysec:每秒记录一次;
  3. no:由系统控制;

一般我们都会使用everysec;即appendfsync everysec

当然文件名也是可以修改的:appendfilename filename

还有一个问题就是,aof文件可能会很大,有一条指令可以重写aof文件,合并一些操作,减小文件大小:

bgrewriteaof

对比

持久化方式RDBAOF
占用存储空间
存储速度
恢复速度
数据安全性会丢失数据依据策略决定
资源消耗
启动优先级

事务

基本操作

开启事务:multi,此后的指令不会被执行,而是放到一个队列中;

执行事务:exec,执行事务队列中的所有指令;

中途取消事务:discard,退出事务;

注意redis中事务的指令队列中如果有语法错误的指令,那么这个事务本身不成立;如果语法正确但是执行出错,redis只会在出错的那条指令抛异常,后面的指令正常执行,不存在事务的回滚操作;

所以,持久化很重要;

上锁:watch key [key]

解锁:unwatch,解锁全部被watch的key

上锁的意义:如果一个key是被watch的,那么下一个事务执行之前,如果value被其他操作所改变了,那么该事务将不被执行(取出的值为nil);所以如果我们的事务中需要某个值不被别的客户端修改,那么在执行事务之前可以先watch那个key;

分布式锁

使用watch后别的客户端仍然可以修改,只不过你的事务取不到这个值了。

如果我就是要动某个数据,别的客户端不能碰它,怎么操作?

用之前的setnx即可,比如这个数据是num,上锁与解锁的过程如下:

上锁:setnx lock-num 1,如果成功则证明你有权利碰num,失败则证明别人正在使用这个数据,你先等着吧;

对数据的操作:incr num

解锁:del lock-num

我们要保证所有客户端都是用的lock-num这同一把锁;

但其实这里面还有一个问题:如果有一哥们上了锁,但是停电了,忘记解锁了,怎么办?

所以解锁操作不能完全依赖于用户,我们在上锁之后可以给锁加上一条时间限制,例如

expire lock-num 10给他设置个10s,当然实际情况不会这么长的;10s之后锁失效,别人就又能用num这个数据了;

删除策略

定时删除:一个数据到期后马上删除,对cpu不友好,对内存友好(用时间换空间);

惰性删除:一个数据到期后知道下次访问该数据时再删除,对cpu友好,对内存不友好(用空间换时间);

定期删除:定期随机抽取一定量的数据进行到期删除(折中方案);

redis内部使用的删除策略是惰性删除和定期删除;

逐出算法:如果有新的数据要添加进来,但是内存不够用了怎么办?

删!怎么删?

有以下策略可供选择:

  1. volatile-lru:定时数据中最近没使用的数据被优先淘汰;
  2. volatile-lfu:定时数据中使用次数最少的数据被优先淘汰;
  3. volatile-ttl定时数据中快过期的数据被优先淘汰;
  4. volatile-random:定时数据随机淘汰;
  5. allkeys-lru:所有数据中最近没的数据被优先淘汰;
  6. allkeys-lru:所有数据中使用次数最少的数据被优先淘汰;
  7. allkeys-lru:所有数据随机淘汰;
  8. no-enviction:放弃淘汰,直接报OOM异常;

我们可以在配置文件中设置以上逐出策略:maxmemory-policy volatile-lru

主从复制

master主要负责写操作,slave主要负责读操作;

如果有多个redis,只要他们的数据是同步的,那么即使有一台挂了,仍能正常提供服务;

基操

redis-server redis-6379.conf
redis-server redis-6380.conf
# 开启两个redis服务,6379作为master,6380作为slave

redis-cli -p 6379
redis-cli -p 6380
# 开启两个客户端

# 在6379中添加一个数据
set name ljj
# 在6380里是一定拿不到的(返回nil)
get name

# 现在我们将6380作为6379的slave
slaveof 127.0.0.1 6379

# 然后再获取那个数据就能拿到了
get name

# 我们也可以直接在启动服务的时候将6380作为slave
redis-server redis-6380.conf --slaveof 127.0.0.1 6379
# 最常用的方法还是直接把这句话写在配置文件里
slaveof 127.0.0.1 6379

显然slave是不能对数据进行写操作的,如果你试图在slave写,那么会报error:

(error) READONLY You can't write against a read only slave.

原理

主从复制分为全量复制和增量复制两个阶段;

全量复制阶段就是slave把master中原本的数据都拿过来;

增量复制就是slave把master的缓冲区中的指令都拿过来;

原理还有很多,但是我不想写了,都是些理论,没啥意思;

哨兵机制

主从复制解决了redis挂掉的问题,如果一台slave挂掉,那么不会影响整体的服务;

但是如果master挂掉了呢?

哨兵机制解决了这个问题。哨兵会在redis运行过程中一直监视master和slave,做一些消息的通知,如果master挂掉了,那么哨兵会将一个slave推选为新的master,所以哨兵一般设置为单数个,放置同票。

基本配置

哨兵基本类似于server,也可以用redis-cli连接,用redis-sentinel 配置文件的方式启动;

简单的配置如下:

port 26379
dir /etc/redis
daemonize yes
# 2代表2个哨兵票即可确定master,因为我只配了3个哨兵
sentinel monitor mymaster 127.0.0.1 6379 2
# master挂掉多久后重新推选
sentinel down-after-milliseconds mymaster 30000
# 每次同步多少
sentinel parallel-syncs mymaster 1
# 多少时间内未同步完成视为失败
sentinel failover-timeout mymaster 180000

另外的哨兵除了端口号其他配置一样即可;

启动

先启动master,在启动slave,再启动哨兵;

redis-server redis-6379.conf;

redis-server redis-6380.conf;

redis-server redis-6381.conf;

redis-sentinel sentinel-26379.conf;

redis-sentinel sentinel-26380.conf;

redis-sentinel sentinel-26381.conf;

如果我们把master6379进行shutdown,根据我们上面的配置,30秒后,哨兵们就会推选出一个新的master;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值