Redis(https://redis.io/)是一款C语言开发的高性能键值存储数据库,遵守BSD开源协议。
扩展
- Redis中文网:http://www.redis.net.cn/。
- 官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s。
x1- 下载地址:https://github.com/dmajkic/redis/downloads
2- 启动服务端:redis-server.exe [配置文件]
3- 启动客户端:redis-cli.exe [-h 127.0.0.1] [-p 6379] [-a "mypass"]
4- 配置文件:redis.windows.conf
5
141- 下载地址:https://redis.io/download/
2
3---# 源码安装 -------
4$ wget http://download.redis.io/releases/redis-7.2.4.tar.gz
5$ tar xzf redis-7.2.4.tar.gz
6$ cd redis-7.2.4
7$ make
8$ ./redis-server
9$ ./redis-cli
10
11
12---# apt-get/yum安装 -----
13xxx install redis-server
14
31- 客户端源码:https://github.com/uglide/RedisDesktopManager
2- 客户端安装包:https://github.com/lework/RedisDesktopManager-Windows/releases
3
541# 获取所有配置项
2CONFIG GET *
3
4# 获取指定配置项
5CONFIG GET xxx
6
7# 修改配置项
8CONFIG SET name value
9CONFIG SET loglevel "notice"
10
11# 设置密码
12# 设置密码后,客户端连接 redis 服务就需要密码验证,否则无法执行命令
13CONFIG set requirepass "123" # 设置密码
14CONFIG get requirepass # 查看密码(为空字符串表示没有密码)
15AUTH 123 # 验证密码
16
17# 基础配置
18daemonize no # 是否以守护进程的方式运行
19pidfile /var/run/redis.pid # 守护进程PID
20bind 127.0.0.1 # 绑定的主机地址
21port 6379 # Redis监听端口
22requirepass foobared # 设置Redis连接密码,如果配置了连接密码,默认关闭
23timeout 300 # 当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
24loglevel verbose # 指定日志记录级别:debug、verbose、notice、warning
25logfile stdout # 日志文件,stdout表示标准输出(当为守护进程时,stdout将发送到/dev/null)
26include /path/to/local.conf # 指定包含其它的配置文件
27
28# 数据库配置
29databases 16 # 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
30dbfilename dump.rdb # 指定本地数据库文件名
31dir ./ # 指定本地数据库存放目录
32rdbcompression yes # 存储时是否进行压缩(LZF压缩)
33
34# 同步配置
35save <seconds> <changes> # 同步时机设置
36appendonly no # 是否在每次更新操作后立即进行日志记录
37appendfilename appendonly.aof # 更新日志文件名
38appendfsync everysec # 更新日志缓冲区刷新行为
39
40# 主从配置
41slaveof <masterip> <masterport> # 当本机为slav服务时,设置master服务的IP地址及端口
42 # 在Redis启动时,它会自动从master进行数据同步
43masterauth <master-password> # 当master服务设置了密码保护时,slav服务连接master的密码
44
45# 调优配置
46maxclients 128 # 设置同一时间最大客户端连接数,默认无限制,为Redis进程可以打开的最大文件描述符数
47maxmemory <bytes> # 指定Redis最大内存限制
48glueoutputbuf yes # 在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
49vm-page-size 32 # 页大小
50
51# 虚拟内存配置
52vm-enabled no # 允许将访问量较少的页即冷数据存入虚拟内存
53vm-swap-file /tmp/redis.swap # 虚拟内存文件路径
54
161# 客户端连接
2redis-cli.exe [-h 127.0.0.1] [-p 6379] [-a "mypass"]
3
4# 验证密码
5AUTH password
6
7# 切换数据库
8SELECT index
9
10# 验证连接是否成功
11PING # 查看服务是否运行
12ECHO message # 打印字符串
13
14# 关闭连接
15QUIT # 关闭当前连接
16
131# 服务器信息
2# https://www.redis.net.cn/tutorial/3518.html
3INFO # 打印服务器信息
4TIME # 返回当前服务器时间
5LASTSAVE # 最近持久化时间(时间戳格式)
6MONITOR # 实时打印出 Redis 服务器接收到的命令,调试用
7
8# 客户端信息
9CLIENT LIST # 已连接的客户端列表
10CLIENT SETNAME # 设置当前连接的名称
11CLIENT GETNAME # 获取当前连接的名称
12CLIENT PAUSE # 挂起客户端
13CLIENT KILL # 关闭客户端
221# key的增删改查
2keys pattern # 如 keys * 表示查询Redis中所有的key
3type key # 获取key对应value的类型
4exists key # 判断key是否存在
5del key # 删除指定的key和value
6rename key newkey # 修改 key 的名称
7renamenx key newkey # 修改 key 的名称(仅当newkey不存在时)
8randomkey # 从当前数据库中随机返回一个 key
9move key db # 将当前数据库的 key 移动到给定的数据库 db 当中
10
11# key超时设置
12EXPIRE key seconds
13PEXPIRE key milliseconds
14EXPIREAT key timestamp
15PEXPIREAT key milliseconds-timestamp
16PERSIST key # 移除key的过期时间
17PTTL key # 以毫秒为单位返回 key 的剩余的过期时间
18TTL key # 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)
19
20# 全库操作
21FLUSHALL # 删除所有数据库的所有key
22FLUSHDB # 删除当前数据库的所有key
421# 字符串(String)
2# https://www.redis.net.cn/tutorial/3508.html
3set key value
4setnx key value # 只有在 key 不存在时设置 key 的值
5get key
6getset key value # 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
7strlen key # 返回 key 所储存的字符串值的长度
8incr key # 将 key 中储存的数字值增一
9incrby key increment # 将 key 所储存的值加上给定的增量值(increment)
10incrbyfloat key increment # 将 key 所储存的值加上给定的浮点增量值(increment)
11decr key # 将 key 中储存的数字值减一
12decrby key decrement # 将 key 所储存的值减去给定的减量值(decrement)
13APPEND key value # 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾
14del key
15
16# 哈希映射(hash)
17hset hashmap01 id 1001
18hset hashmap01 name hyx
19hget hashmap01 name
20hexists hashmap01 name # 查看哈希表 hashmap01 中,指定的字段是否存在
21hgetall hashmap01 # 获取map所有键值对
22hdel hashmap01 name
23
24# 列表/队列(list) # 可存储重复元素
25lpush list01 zhangsan # 将元素加入列表左表
26rpush list01 lisi # 将元素加入列表右边
27lrange list01 0 -1 # 使用下标范围获取
28lpop list01 # 删除列表最左边的元素,并将元素返回
29rpop list01 # 删除列表最右边的元素,并将元素返回
30
31# 集合(set)
32sadd set01 a # 第一次存储元素a,返回1
33sadd set01 a # 不允许存储重复元素,返回0
34smembers set01 # 获取集合所有元素
35srem set01 a # 删除集合中的某个元素
36
37# 有序集合(sortedset) # 不允许重复元素,且元素通过分数排序
38zadd zset01 1.0 a
39zadd zset01 2.1 b
40zrange zset01 0 -1 [withscores] # 使用下标范围获取(可选是否查询分数值)
41zrem zset01 a # 删除集合中的某个元素
42
注意:
- String类型的value最大支持512M,单个set和list最大存储 2^32-1 个键值对(40多亿)。
- list可存储重复元素,set不可以存储重复元素,sortedset不允许重复元素,且元素通过分数排序。
51# 基数(HyperLogLog)
2PFADD w3ckey "redis"
3PFADD w3ckey "mongodb"
4PFCOUNT w3ckey
5
141# 订阅
2subscribe channel01 # 订阅
3psubscribe channel* # 订阅(支持通配符)
4
5# 发布
6publish channel01 "msg01" # 发布
7
8# 退订
9unsubscribe channel01 # 退订
10punsubscribe channel* # 退订(支持通配符)
11
12# 查看订阅与发布系统状态
13PUBSUB subcommand [argument [argument ...]]
14
注意
- 必须先订阅后发布,订阅某个通道,并不能收到该通道之前已发布的消息。
Redis的事务可以一次执行多个命令,它可以保证:
171# 开启事务
2MULTI
3
4# 输入多个命令
5SET key01 value01
6SET key02 value02
7
8# 执行命令
9EXEC
10
11# 回滚命令
12DISCARD
13
14# 监视命令
15WATCH key01 [key02 ...] # 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
16UNWATCH # 取消 WATCH 命令对所有 key 的监视。
17
171# 方式一:RDB
2# 默认方式,不需要进行配置,默认就使用这种机制
3# 在一定的间隔时间中,检测key的变化情况,然后持久化数据
4save <seconds> <changes> # 同步时机设置(注:设置后需重启)
5save 900 1 # 900秒(15分钟)内有1个更改
6save 300 10 # 300秒(5分钟)内有10个更改
7save 60 10000 # 60秒内有10000个更改
8
9# 方式二:AOF
10# 日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据
11appendonly yes # 开启aof
12appendfilename appendonly.aof # AOF日志文件名
13appendfsync everysec # AOF日志缓冲区刷新行为:
14 # no:表示等操作系统进行数据缓存同步到磁盘(快)
15 # always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
16 # everysec:表示每秒同步一次(折衷,默认值)
17
71# 备份
2save # 将在 redis 安装目录中生成 dump.rdb 文件
3bgsave # 后台执行
4
5# 恢复
6CONFIG GET dir # 查询安装目录,并将 dump.rdb 文件移动到该目录并重启
7
51<dependency>
2 <groupId>redis.clients</groupId>
3 <artifactId>jedis</artifactId>
4 <version>2.9.0</version>
5</dependency>
141import redis.clients.jedis.Jedis;
2public class RedisJava {
3 public static void main(String[] args) {
4 //连接本地的 Redis 服务
5 Jedis jedis = new Jedis("localhost", 6379 );
6 System.out.println("Connection to server sucessfully");
7
8 //查看服务是否运行
9 System.out.println("Server is running: "+jedis.ping());
10
11 // 关闭连接
12 jedis.close();
13 }
14}
281// 字符串
2jedis.set("username","zhangsan");
3String username = jedis.get("username");
4
5// 哈希
6jedis.hset("user","name","lisi");
7jedis.hset("user","age","23");
8jedis.hset("user","gender","female");
9String name = jedis.hget("user", "name");
10Map<String, String> user = jedis.hgetAll("user");
11
12// 列表/队列
13jedis.lpush("mylist","a","b","c");
14jedis.rpush("mylist","a","b","c");
15List<String> mylist = jedis.lrange("mylist", 0, -1);
16String element1 = jedis.lpop("mylist");
17String element2 = jedis.rpop("mylist");
18
19// 集合
20jedis.sadd("myset","java","php","c++");
21Set<String> myset = jedis.smembers("myset");
22
23// 有序集合
24jedis.zadd("mysortedset",3,"亚瑟");
25jedis.zadd("mysortedset",30,"后裔");
26jedis.zadd("mysortedset",55,"孙悟空");
27Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);
28
61// 设置过期时间
2jedis.setex("key01",20,"value01"); // 20秒后自动删除该键值对 key01:value01
3
4// keys
5List<String> list = jedis.keys("*");
6
331// Jedis连接池工具类
2public class JedisPoolUtils {
3
4 // 连接池引用
5 private static JedisPool jedisPool;
6
7 // 连接池初始化
8 static{
9
10 // 1. 读取配置文件
11 InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
12 Properties pro = new Properties();
13 try {
14 pro.load(is);
15 } catch (IOException e) {
16 e.printStackTrace();
17 }
18
19 // 2. 创建配置类
20 JedisPoolConfig config = new JedisPoolConfig();
21 config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
22 config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));
23
24 // 3. 创建JedisPool
25 jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
26 }
27
28 // 获取Jedis连接
29 public static Jedis getJedis(){
30 return jedisPool.getResource();
31 }
32
33}
注意:
- Jedis连接使用完毕后,必须调用
jedis.close();
归还连接。
81<dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-data-redis</artifactId>
4</dependency>
5<dependency>
6 <groupId>org.apache.commons</groupId>
7 <artifactId>commons-pool2</artifactId>
8</dependency>
1031
2public class RedisTestController {
3
4 private StringRedisTemplate redisTemplate;
5
6 "redisTest") (
7 public String redisTest() {
8
9 // 1. 关于key的操作
10 // 获取所有的key
11 Set<String> keys = redisTemplate.keys("*");
12 System.out.println("keys:" + keys);
13 // 判断是否存在指定的key
14 Boolean hasKey = redisTemplate.hasKey("k1");
15 System.out.println("判断是否存在指定的key:" + hasKey);
16 // 删除指定的key
17 Boolean k1 = redisTemplate.delete("k1");
18 System.out.println("是否删除指定key成功:" + k1);
19
20
21 // 2. 操作Stirng
22 ValueOperations<String, String> forValue = redisTemplate.opsForValue();
23 // 设置和获取
24 forValue.set("k2", "张明喆");
25 String k2 = forValue.get("k2");
26 System.out.println("k2:" + k2);
27 //只有在 key 不存在时设置 key 的值
28 Boolean aBoolean = forValue.setIfAbsent("k2", "zmz2");
29 System.out.println("是否存入成功:" + aBoolean);
30 //incr decr
31 Long k4 = forValue.increment("k4", 20);
32 System.out.println("k4:" + k4);
33 forValue.decrement("k4");
34 //批量添加
35 Map<String, String> map = new HashMap<>();
36 map.put("m1", "m1");
37 map.put("m2", "m2");
38 forValue.multiSet(map);
39
40 // 3. 操作hash
41 HashOperations<String, Object, Object> forHash = redisTemplate.opsForHash();
42 // 逐个put
43 forHash.put("k5", "name", "zmz");
44 forHash.put("k5", "age", "16");
45 forHash.put("k5", "sex", "男");
46 // 批量put
47 Map<String, String> map1 = new HashMap<>();
48 map.put("name", "jsl");
49 map.put("age", "29");
50 map.put("sex", "男");
51 forHash.putAll("k6", map1);
52 // 获取
53 Map<Object, Object> k5 = forHash.entries("k5");
54 System.out.println(k5);
55 Set<Object> k6 = forHash.keys("k6");
56 System.out.println(k6);
57 System.out.println(forHash.values("k6"));
58
59 // 4. 操作list
60 ListOperations<String, String> list = redisTemplate.opsForList();
61 // 放入单个 key value
62 list.leftPush("l1", "111");
63 // 放入 批量value
64 list.leftPushAll("l2", "zmz", "jsl", "hql", "fxd");
65 // 获取列表指定范围内的元素
66 List<String> l2 = list.range("l2", 0, -1);
67 System.out.println(l2);
68 // 移出并获取列表的第一个元素
69 list.leftPop("l2");
70
71 // 5. 操作set
72 SetOperations<String, String> forSet = redisTemplate.opsForSet();
73 // 向集合添加一个或多个成员
74 forSet.add("s1", "张明喆", "贾善领", "黄启龙", "张明喆", "贾善领");
75 forSet.add("s2", "张明喆1", "贾善领2", "黄启龙3", "张明喆", "贾善领");
76 // 返回集合中的所有成员
77 Set<String> s1 = forSet.members("s1");
78 System.out.println(s1);
79 // 随机获取一个或多个元素
80 String s11 = forSet.randomMember("s1");
81 System.out.println(s11);
82 // 返回给定所有集合的交集
83 Set<String> intersect = forSet.intersect("s1", "s2");
84 System.out.println(intersect);
85
86 // 6. 操作sort set
87 ZSetOperations<String, String> forZSet = redisTemplate.opsForZSet();
88 // 向有序集合添加一个或多个成员,或者更新已存在成员的分数
89 forZSet.add("z1", "math", 80);
90 forZSet.add("z1", "chinese", 99);
91 forZSet.add("z1", "english", 78);
92 forZSet.add("z1", "physics", 76);
93 forZSet.add("z1", "biology", 60);
94 // 通过索引区间返回有序集合成指定区间内的成员
95 Set<String> z1 = forZSet.range("z1", 0, -1);
96 System.out.println(z1);
97 // 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
98 Set<String> z11 = forZSet.reverseRange("z1", 0, -1);
99 System.out.println(z11);
100
101 return "OK";
102 }
103}
RedisTemplate
允许你以Java对象的形式存取数据。
181public class Test2 {
2
3 private RedisTemplate redisTemplate;
4
5
6 void test(){
7 ValueOperations valueOperations = redisTemplate.opsForValue();
8 valueOperations.set("user",new User("张明喆",29,"上海"));
9 Object o = valueOperations.get("user");
10 System.out.println(o);
11
12 HashOperations hashOperations = redisTemplate.opsForHash();
13 hashOperations.put("k3","name","zmz");
14 Map<String, Object> map = new HashMap<>();
15 map.put("1", new User("zz",22,"ll"));
16 hashOperations.putAll("k5", map);
17 }
18}
但其默认采用JDK序列化机制,阅读能力差,而且占用空间大,一般需要人为指定序列化方式:
361package com.sws;
2
3import com.fasterxml.jackson.annotation.JsonAutoDetect;
4import com.fasterxml.jackson.annotation.PropertyAccessor;
5import com.fasterxml.jackson.databind.ObjectMapper;
6import org.springframework.context.annotation.Bean;
7import org.springframework.context.annotation.Configuration;
8import org.springframework.data.redis.connection.RedisConnectionFactory;
9import org.springframework.data.redis.core.RedisTemplate;
10import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
11import org.springframework.data.redis.serializer.RedisSerializer;
12import org.springframework.data.redis.serializer.StringRedisSerializer;
13
14
15public class RedisConfig {
16
17
18 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
19 RedisTemplate<String, Object> template = new RedisTemplate<>();
20 RedisSerializer<String> redisSerializer = new StringRedisSerializer();
21 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
22 ObjectMapper om = new ObjectMapper();
23 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
24 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
25 jackson2JsonRedisSerializer.setObjectMapper(om);
26 template.setConnectionFactory(factory);
27 //key序列化方式
28 template.setKeySerializer(redisSerializer);
29 //value序列化
30 template.setValueSerializer(jackson2JsonRedisSerializer);
31 //value hashmap序列化
32 template.setHashValueSerializer(jackson2JsonRedisSerializer);
33 template.setHashKeySerializer(redisSerializer);
34 return template;
35 }
36}
Redis 使用 Lua 解释器来执行脚本,可参考:https://www.redis.net.cn/tutorial/3516.html
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
91$(echo -en "PING\r\n SET w3ckey redis\r\nGET w3ckey\r\nINCR visitor\r\nINCR visitor\r\nINCR visitor\r\n"; sleep 10) | nc localhost 6379
2
3+PONG
4+OK
5redis
6:1
7:2
8:3
9
这可以显著的改善往返时延,提提高Redis的性能。
101# 命令格式
2# https://www.redis.net.cn/tutorial/3521.html
3redis-benchmark [option] [option value]
4
5# 同时执行 10000 个请求
6redis-benchmark -n 100000
7
8# 显示每秒执行的请求数,执行的命令为 set,lpush
9redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 100000 -q
10