Redis
Posted dins
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis相关的知识,希望对你有一定的参考价值。
一、NoSQL 概述
什么是 NoSQL
NoSQL = Not Only SQL
一种全新的数据库理念,泛指非关系型数据库。
为什么需要 NoSQL?
传统关系型数据库在应付 web2.0 网站时,特别是超大规模、高并发的 SNS web2.0 动态网站,已经力不从心,并暴露出一些难以克服的问题。
- High performance - 高并发读写
- Huge Storage - 海量数据的高效率存储和访问
- High Scalability && High Availability - 高可扩展性和高可用性
主流产品
- CouchDB
- Redis
- MongoDB
四大分类
NoSQL 的特点
- 易扩展。去掉了关系型数据库中的关系。
- 灵活的数据模型
- 大数据量、高性能的存储
- 高可用
二、Redis 概述
- Redis 的由来
什么是 Redis?
一款用 C 语言开发的,开源的、高性能的、键值对的数据库,通过提供多种键值数据类型,来适应不同场景下的存储需求。
目前支持的键值数据类型:- 字符串类型
- 列表类型
- 有序集合类型
- 散列类型
- 集合类型
Redis 的应用场景
- 提供缓存服务,存储访问频率高的热数据,防止穿透到数据库
- 任务队列
- 网站访问统计
- 数据过期处理
- 应用排行榜
- 分布式集群架构中的 session 分离
- 在分布式系统中可以作为实现分布式锁的一种实现方案
三、Jedis 入门
Jedis 是 Redis 官方首选的 java 客户端开发包。
地址:https://redis.io/clients#java
jedis 集成了 redis 的一些命令操作,提供了连接池管理。
添加 maven 依赖:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.0.10.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
简单的使用:
public class JedisDemo {
/**
* 单实例测试
*/
@Test
public void demo1() {
// 1. 设置 ip 和端口
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 2. 保存数据
jedis.set("name", "jack");
// 3. 获得数据
String value = jedis.get("name");
System.out.println(value);
// 4. 释放资源
jedis.close();
}
/* 连接池方式连接 */
@Test
public void demo2() {
// 获得连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
// 设置最大连接数
config.setMaxTotal(20);
// 设置最大空闲连接数
config.setMinIdle(10);
// 获取连接池
JedisPool pool = new JedisPool(config, "127.0.0.1", 6379);
// 获取核心对象
Jedis jedis = null;
try {
// 通过连接池获的连接
jedis = pool.getResource();
// 设置数据
jedis.set("name", "root");
// 获取数据并打印
System.out.println(jedis.get("name"));
}catch (Exception e) {
if (jedis != null) {
jedis.close();
}
if (pool != null) {
pool.close();
}
}
}
}
四、Redis 的数据类型
Redis 中 key 定义的注意点:
- 不要过长,不要超过 1024 个字节,消耗内存,降低查找效率;
- 不要过短,影响可读性;
- 统一的命名规范。
Redis 中可以存储的数据类型:
- 字符串(String)
- 字符串列表(list)
- 有序字符串集合(sorted set)
- 哈希(hash)
- 字符串集合(set)
4.1 存储 String
- 二进制安全的,存入和获取的数据相同;
- 字符串类型的 value 可以容纳 512M。
常用命令:
赋值
$ redis-cli 127.0.0.1:6379> set name Tom
OK{ // 添加数据
jedis.set("name", "Jack");
}取值
127.0.0.1:6379> get name "Tom"
127.0.0.1:6379> getset name Jack
"Tom"
127.0.0.1:6379> get name
"Jack"{ // 获取数据
jedis.get("name")
}getset
命令相当于先执行 get 获取命令再执行 set 设置命令。删除
127.0.0.1:6379> del name (integer) 1
127.0.0.1:6379> get name
(nil){ // 删除数据
jedis.del("name");
}数值增减
127.0.0.1:6379> incr num (integer) 1
127.0.0.1:6379> get num
"1"
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> get num
"2"
127.0.0.1:6379> set name Tom
OK
127.0.0.1:6379> incr name
(error) ERR value is not an integer or out of rangeincr
将指定的 key 的 value 值递增 1,如果这个值不存在,就将这个值初始为 0,再执行 +1;如果这个 value 不是整型,则命令执行失败。127.0.0.1:6379> decr num (integer) 1
127.0.0.1:6379> decr name
(error) ERR value is not an integer or out of rangedecr
将指定的 key 的 value 值递增 1,如果这个值不存在,就将这个值初始为 0,再执行 -1;如果这个 value 不是整型,则命令执行失败。扩展命令
127.0.0.1:6379> get num "1"
127.0.0.1:6379> incrby num 3
(integer) 4
127.0.0.1:6379> get num
"4"{ // 用于将键的整数值递增 1。
// 如果键不存在,则在执行操作之前将其设置为 0;如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。
// 此操作限于 64 位有符号整数
jedis.incr("age");
}incrby
将指定的 key 的 value 增加指定数值,如果这个值不存在,就将这个值初始为 0,再增加;如果这个 value 不是整型,则命令执行失败。127.0.0.1:6379> get num "4"
127.0.0.1:6379> decrby num 5
(integer) -1
127.0.0.1:6379> decrby name
(error) ERR wrong number of arguments for 'decrby' commanddecrby
将指定的 key 的 value 增加指定数值,如果这个值不存在,就将这个值初始为 0,再增加;如果这个 value 不是整型,则命令执行失败。127.0.0.1:6379> get num "-1"
127.0.0.1:6379> append num 12
(integer) 4
127.0.0.1:6379> get num
"-112"
127.0.0.1:6379> incr num
(integer) -111
127.0.0.1:6379> append password 123456
(integer) 6
127.0.0.1:6379> get password
"123456"{ // 拼接数据
jedis.append("name", " Ma");
}append
拼凑字符串。如果 value 存在,就在原来的字符串后面追加;如果不存在,就创建一个新字符串,value 等于要拼接的字符串。命令返回结果字符串的长度。
4.2 存储 Hash
- 具有 String 类型的 Key 和 String 类型的 Value 的 map 容器。适合存储值对象的信息,用户名、密码等。
- 每一个 Hash 可以存储 4294967295 个键值对。
常用命令:
赋值
127.0.0.1:6379> hSet myhash username jack (integer) 1
127.0.0.1:6379> hSet myhash age 18
(integer) 1
127.0.0.1:6379> hmset myhash2 username rose age 21
OK{ // 添加数据
Map<String, String> map = new HashMap<String, String>();
map.put("username", "jack");
map.put("age", "18");
jedis.hmset("myhash", map);
}hmset
一次设置多个键值对。取值
127.0.0.1:6379> hget myhash username "jack"
127.0.0.1:6379> hmget myhash username age
1) "jack"
2) "18"
127.0.0.1:6379> hgetall myhash
1) "username"
2) "jack"
3) "age"
4) "18"
127.0.0.1:6379> hget myhash company
(nil){ // 返回结果是一个泛型的 List
List<String> list = jedis.hmget("myhash", "username", "age");
System.out.println(list);
// 获取 map 中某个值
jedis.hget("myhash", "age")
}hmget
一次获取 hash 中多个指定 key 的 vlaue。
hgetall
获取 hash 中所有的键值对信息,key 和 value 的值都打印出来。删除
127.0.0.1:6379> hdel myhash username age (integer) 2
127.0.0.1:6379> hgetall myhash
(empty list or set)
127.0.0.1:6379> hdel myhash username
(integer) 0
127.0.0.1:6379> hmset myhash username jack age 18
OK
127.0.0.1:6379> del myhash
(integer) 1
127.0.0.1:6379> hget myhash username
(nil){ jedis.del("myhash");
}hdel
删除 hash 中没有的 key 时,返回 0,操作失败。增加数字
127.0.0.1:6379> hincrby myhash age 5 (integer) 23
127.0.0.1:6379> hget myhash age
"23"自学命令
127.0.0.1:6379> hexists myhash username (integer) 1
127.0.0.1:6379> hexists myhash password
(integer) 0hexists
判断 myhash 中是否存在为 username 的 key。0 表示不存在,1 表示存在。127.0.0.1:6379> hgetall myhash 1) "username"
2) "jack"
3) "age"
4) "23"
127.0.0.1:6379> hlen myhash
(integer) 2hlen
获取 hash 中键值对的个数。127.0.0.1:6379> hkeys myhash 1) "username"
2) "age"hkeys
获取 hash 中所有的键。127.0.0.1:6379> hvals myhash 1) "jack"
2) "23"myhash
获取 hash 中所有的值。
4.3 存储 list
Redis 的 list 是按照插入顺序排序的一个字符串的链表,和数据结构中的普通链表一样,可以在它的头部(左侧)和尾部(右侧)添加新的元素。
在插入的时候,如果该键不存在,那么 redis 会为这个键创建一个新的链表,与此相反,如果链表中的所有元素都被移除了,那么该键也会被从数据库中删除。
如果是在链表的两头插入和删除元素,是非常高效的;如果元素插入和删除是作用在链表的中间,是比较低效的。
数据存储的方式:
ArrayList
使用数组方式。
根据索引查询速度快,插入和删除需要涉及位移操作,所以比较慢。LinkedList
使用双向链接方式。
插入删除操作只改变前后元素的指针指向,速度非常快。
常用命令:
两端添加
127.0.0.1:6379> lpush mylist a b c (integer) 3
127.0.0.1:6379> lpush mylist 1 2 3
(integer) 6lpush
左侧添加数据。127.0.0.1:6379> rpush mylist2 a b c (integer) 3
127.0.0.1:6379> rpush mylist2 1 2 3
(integer) 6rpush
右侧插入数据。查看列表
127.0.0.1:6379> lrange mylist 0 5 1) "3"
2) "2"
3) "1"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> lrange mylist2 0 -1
1) "a"
2) "b"
3) "c"
4) "1"
5) "2"
6) "3"
127.0.0.1:6379> lrange mylist2 0 -3
1) "a"
2) "b"
3) "c"
4) "1"lrange key start stop
lrange
命令是显示左侧 start 位置到 stop 位置间的元素内容。如果 start/stop 是负数,表示从尾部开始算,-1 表示倒数第一个,-2 表示倒数第二个...。简而言之,正数是从左向右数,负数是从右向左数。
两端弹出
127.0.0.1:6379> lpop mylist "3"
127.0.0.1:6379> lrange mylist 0 -1
1) "2"
2) "1"
3) "c"
4) "b"
5) "a"
127.0.0.1:6379> rpop mylist2
"3"
127.0.0.1:6379> lrange mylist2 0 -1
1) "a"
2) "b"
3) "c"
4) "1"
5) "2"lpop
从左侧弹出一个元素,rpop
从右侧弹出一个元素。弹出的元素从 list 中移除。获取列表元素个数
127.0.0.1:6379> llen mylist (integer) 5
127.0.0.1:6379> llen mylist2
(integer) 5扩展命令
127.0.0.1:6379> lpushx mylist x (integer) 6
127.0.0.1:6379> lrange mylist 0 -1
1) "x"
2) "2"
3) "1"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> lpushx mylist3 x
(integer) 0
127.0.0.1:6379> rpushx mylist2 y
(integer) 6
127.0.0.1:6379> lrange mylist2 0 -1
1) "a"
2) "b"
3) "c"
4) "1"
5) "2"
6) "y"lpushx
仅当指定的 key 存在时,就可以向关联的 list 中从左侧插入相应的值。上面的 mylist3 不存在,所以返回 0,不进行操作。
rpushx
从右侧插入相应的值。127.0.0.1:6379> lpush mylist3 1 2 3 (integer) 3
127.0.0.1:6379> lpush mylist3 1 2 3
(integer) 6
127.0.0.1:6379> lpush mylist3 1 2 3
(integer) 9
127.0.0.1:6379> lrange mylist3 0 -1
1) "3"
2) "2"
3) "1"
4) "3"
5) "2"
6) "1"
7) "3"
8) "2"
9) "1"
127.0.0.1:6379> lrem mylist3 2 3
(integer) 2
127.0.0.1:6379> lrange mylist3 0 -1
1) "2"
2) "1"
3) "2"
4) "1"
5) "3"
6) "2"
7) "1"
127.0.0.1:6379> lrem mylist3 -2 1
(integer) 2
127.0.0.1:6379> lrange mylist3 0 -1
1) "2"
2) "1"
3) "2"
4) "3"
5) "2"
127.0.0.1:6379> lrem mylist3 0 2
(integer) 3
127.0.0.1:6379> lrange mylist3 0 -1
1) "1"
2) "3"lrem key count value
lrem
如果指定的 key 存在,从指定方向遍历,删除count
个value
,如果 count = 2,value = 3,表示从左向右删除 2 个“3”;如果 count = 0,value = 3,表示从左向右删除所有的“3”;如果 count = -2,value = 3,表示从右向左删除 2 个“3”。127.0.0.1:6379> lrange mylist 0 -1 1) "x"
2) "2"
3) "1"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> lset mylist 3 mmm
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "x"
2) "2"
3) "1"
4) "mmm"
5) "b"
6) "a"lset
在指定位置插入指定元素。注意:插入索引是从 0 开始。127.0.0.1:6379> lpush mylist4 a b c (integer) 3
127.0.0.1:6379> lpush mylist4 a b c
(integer) 6
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "b"
3) "a"
4) "c"
5) "b"
6) "a"
127.0.0.1:6379> linsert mylist4 before b 11
(integer) 7
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "11"
3) "b"
4) "a"
5) "c"
6) "b"
7) "a"
127.0.0.1:6379> linsert mylist4 after b 22
(integer) 8
127.0.0.1:6379> lrange mylist4 0 -1
1) "c"
2) "11"
3) "b"
4) "22"
5) "a"
6) "c"
7) "b"
8) "a"linsert
在指定元素的前面/后面插入指定元素。127.0.0.1:6379> lpush mylist5 1 2 3 (integer) 3
127.0.0.1:6379> lpush mylist6 a b c
(integer) 3
127.0.0.1:6379> lrange mylist5 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lrange mylist6 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> rpoplpush mylist5 mylist6
"1"
127.0.0.1:6379> lrange mylist5 0 -1
1) "3"
2) "2"
127.0.0.1:6379> lrange mylist6 0 -1
1) "1"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> rpoplpush mylist6 mylist6
"a"
127.0.0.1:6379> lrange mylist6 0 -1
1) "a"
2) "1"
3) "c"
4) "b"rpoplpush source destination
rpoplpush
将 source 中的尾部(右侧)元素移除并压入 destination 的头部(左侧)。
4.4 存储 Set
将 Redis set 看作为无序的字符集合,和 List 一样。可以执行添加、删除、判断是否存在等操作。
- 和 List 类型不同的是,Set 集合中不允许出现重复的元素
- 在服务器端完成多个 set 的聚合操作,如 union 等;
- Set 可包含的最大元素数量是 4294967295。
常用命令:
添加/删除元素
127.0.0.1:6379> sadd myset a b c (integer) 3
127.0.0.1:6379> sadd myset a
(integer) 0
127.0.0.1:6379> sadd myset 1 2 3
(integer) 3sadd
如果集合中已经有了元素,再次添加时,返回 0,操作失败。127.0.0.1:6379> srem myset 1 2 (integer) 2
获得集合中的元素
127.0.0.1:6379> smembers myset 1) "c"
2) "3"
3) "b"
4) "a"
127.0.0.1:6379> sismember myset a
(integer) 1
127.0.0.1:6379> sismember myset x
(integer) 0smembers
查看集合中的元素。
sismember
判断集合中是否有指定的元素,如果有返回 1,没有返回 0。集合中的差集行算
127.0.0.1:6379> sadd myset1 a b c (integer) 3
127.0.0.1:6379> sadd myset2 a b 1 2
(integer) 4
127.0.0.1:6379> sdiff myset1 myset2
1) "c"
127.0.0.1:6379> sdiff myset2 myset1
1) "1"
2) "2"注意:两个参数 key 的位置不同,得到的结果不同。
集合中的交集运算
127.0.0.1:6379> sinter myset1 myset2 1) "b"
2) "a"集合中的并集运算
127.0.0.1:6379> sunion myset1 myset2 1) "a"
2) "c"
3) "1"
4) "2"
5) "b"扩展命令
127.0.0.1:6379> smembers myset 1) "c"
2) "3"
3) "b"
4) "a"
127.0.0.1:6379> scard myset
(integer) 4scard
计算集合的元素个数。127.0.0.1:6379> srandmember myset "a"
127.0.0.1:6379> srandmember myset
"c"
127.0.0.1:6379> srandmember myset
"3"
127.0.0.1:6379> srandmember myset
"c"srandmember
获取集合中随机的元素。127.0.0.1:6379> sdiffstore mydiff myset1 myset2 (integer) 1
127.0.0.1:6379> smembers mydiff
1) "c"
127.0.0.1:6379> sinterstore myinter myset1 myset2
(integer) 2
127.0.0.1:6379> smembers myinter
1) "b"
2) "a"
127.0.0.1:6379> sunionstore myunion myset1 myset2
(integer) 5
127.0.0.1:6379> smembers myunion
1) "a"
2) "c"
3) "1"
4) "2"
5) "b"sunionstore destination key [key ...]
将两个集合的交集、并集、差集存储到 destination 集合中。
存储 Set 的使用场景:
- 跟踪一些唯一性数据;
- 用于维护数据对象之间的关联关系。
4.5 存储 Sorted-Set
Sorted-Set 和 Set 的区别:Sorted-Set 中的每一个元素都有一个“分数”,根据这个分数判断它们的先后顺序。
Sorted-Set 的元素在集合中的位置是有序的。
常用命令:
添加元素
127.0.0.1:6379> zadd mysort 70 zhangsan 80 lisi 90 wangwu (integer) 3
127.0.0.1:6379> zadd mysort 100 zhangsan
(integer) 0
127.0.0.1:6379> zadd mysort 60 tom
(integer) 1zadd
命令返回新插入元素的个数,如果集合中已有同名元素,那么将新的 score 替换已有的,并返回 0。获得元素
127.0.0.1:6379> zscore mysort zhangsan "100"
127.0.0.1:6379> zcard mysort
(integer) 4zscore
返回指定元素的分数。
zcard
返回集合中的元素个数。删除元素
127.0.0.1:6379> zrem mysort tom wangwu (integer) 2
返回被删除的元素个数。
范围查询
127.0.0.1:6379> zrange mysort 0 -1 1) "lisi"
2) "zhangsan"
127.0.0.1:6379> zrange mysort 0 -1 withscores
1) "lisi"
2) "80"
3) "zhangsan"
4) "100"zrange key start stop [WITHSCORES]
zrange
在指定 key 对应集合中,查找从 start 位置到 stop 位置之间的元素。[WITHSCORES] 是可选项,表示是否同时返回元素对应的分数。127.0.0.1:6379> zrevrange mysort 0 -1 withscores 1) "zhangsan"
2) "100"
3) "lisi"
4) "80"默认 zrange 是按照分数升序排列,分数低的先返回。
zrevrange
是按照分数倒序排序。扩展命令
127.0.0.1:6379> zremrangebyrank mysort 0 1 (integer) 2
127.0.0.1:6379> zcard mysort
(integer) 0zremrangebyrank key start stop
zremrangebyrank
删除 start~stop 范围内的元素。127.0.0.1:6379> zadd mysort 80 lucy 90 lily 100 lucky (integer) 3
127.0.0.1:6379> zremrangebyscore mysort 80 100
(integer) 3zremrangebyscore key min max
zremrangebyscore
删除 min~max 之间分数的元素。127.0.0.1:6379> zadd mysort 70 zhangsan 80 lisi 90 wangwu (integer) 3
127.0.0.1:6379> zrangebyscore mysort 0 100
1) "zhangsan"
2) "lisi"
3) "wangwu"
127.0.0.1:6379> zrangebyscore mysort 0 100 withscores
1) "zhangsan"
2) "70"
3) "lisi"
4) "80"
5) "wangwu"
6) "90"
127.0.0.1:6379> zrangebyscore mysort 0 100 withscores limit 0 2
1) "zhangsan"
2) "70"
3) "lisi"
4) "80"zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
zrangebyscore
从指定 key 对应的集合中,查找 min~max 之间分数的元素。[WITHSCORES] 是可选项,表示是否显示它们的分数;[LIMIT offset count] 是可选项,表示从 offset 位置开始,共 count 个元素中查询。127.0.0.1:6379> zincrby mysort 3 lisi "83"
127.0.0.1:6379> zscore mysort lisi
"83"增加指定元素对应的分数。
127.0.0.1:6379> zcount mysort 80 90 (integer) 2
zcount key min max
统计 min~max 之间分数的元素个数。
Sorted-Set 使用场景:
- 大型在线游戏积分排行榜
- 构建索引数据
五、Keys 的通用操作
127.0.0.1:6379> keys *
1) "mydiff"
2) "myset2"
3) "company"
4) "mylist6"
5) "mylist2"
6) "mylist5"
7) "mylist4"
8) "myhash"
9) "password"
10) "myset"
11) "mysort"
12) "mylist"
13) "myset1"
14) "num"
15) "myunion"
16) "name"
17) "mylist3"
18) "myinter"
127.0.0.1:6379> keys my?
(empty list or set)
127.0.0.1:6379> keys my*
1) "mydiff"
2) "myset2"
3) "mylist6"
4) "mylist2"
5) "mylist5"
6) "mylist4"
7) "myhash"
8) "myset"
9) "mysort"
10) "mylist"
11) "myset1"
12) "myunion"
13) "mylist3"
14) "myinter"
keys
查询指定规则的 key。
127.0.0.1:6379> exists mylist6
(integer) 1
127.0.0.1:6379> del mylist6
(integer) 1
127.0.0.1:6379> exists mylist6
(integer) 0
exists
查询指定 key 是否存在。
127.0.0.1:6379> get name
"Tom"
127.0.0.1:6379> rename name newName
OK
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get newName
"Tom"
rename
重命名 key。
127.0.0.1:6379> expire newName 1000
(integer) 1
127.0.0.1:6379> ttl newName
(integer) 994
expire key seconds
expire
设置 key 的超时时间。
ttl
查询 key 的剩余超时时间。
127.0.0.1:6379> type newName
string
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type myset
set
127.0.0.1:6379> type myhash
hash
127.0.0.1:6379> type mysort
zset
type
查看 key 对应 value 的数据类型。
六、Redis 的特性
- 多数据库
- Redis 事务
6.1 多数据库
一个 Redis 实例可以包含多个数据库,客户端可以指定连接 redis 实例的哪个数据库。最多包含 16 个数据库,从 0~15,默认为 0 号数据库。
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
(empty list or set)
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> keys *
1) "mydiff"
2) "myset2"
3) "company"
4) "mylist2"
5) "mylist5"
6) "mylist4"
7) "myhash"
8) "newName"
9) "password"
10) "myset"
11) "mysort"
12) "mylist"
13) "myset1"
14) "num"
15) "myunion"
16) "mylist3"
17) "myinter"
select
命令选择不同的数据库。
127.0.0.1:6379> keys *
1) "mydiff"
2) "myset2"
3) "company"
4) "mylist2"
5) "mylist5"
6) "mylist4"
7) "myhash"
8) "newName"
9) "password"
10) "myset"
11) "mysort"
12) "mylist"
13) "myset1"
14) "num"
15) "myunion"
16) "mylist3"
17) "myinter"
127.0.0.1:6379> move myset 1
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "myset"
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> keys *
1) "mydiff"
2) "myset2"
3) "company"
4) "mylist2"
5) "mylist5"
6) "mylist4"
7) "myhash"
8) "newName"
9) "password"
10) "mysort"
11) "mylist"
12) "myset1"
13) "num"
14) "myunion"
15) "mylist3"
16) "myinter"
move key db
move
将当前数据库中的 key 移入到目标数据库 db 中。注意:移动的 key 会从当前的数据库中移除。
6.2 事务
Redis 作为 NoSQL 数据库,也提供了事务的机制。在 Redis 中可以使用 multi
、exec
、discard
命令来实现事务,在事务中,所有的命令都将会串行化、顺序执行,事务执行期间,Redis 不会为其他的客户端提供任何的服务,从而保证事务中的所有命令都会被原子化执行。
和关系型数据库的事务相比,在 Redis 中,如果某一个命令执行失败了,它后面的命令还会被执行。
multi
命令开启事务。在执行 multi
命令之后执行的命令,都视为在事务里面执行的。
exec
命令提交事务。
discard
命令回滚。
在事务开启之前,如果客户端和服务器之间出现通信故障,并导致网络断开,那么它之后执行的语句,都不会被服务器执行;如果网络发生中断是在 exec
命令之后,那么事务中的所有命令都会被服务器执行。
127.0.0.1:6379> set num 2
OK
127.0.0.1:6379> get num
"2"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> exec
1) (integer) 3
2) (integer) 4
127.0.0.1:6379> get num
"4"
七、Redis 的持久化
Redis 的高性能是由于所有的数据都存储在内存中,为了使 Redis 在重启之后数据不丢失,那么就需要将数据从内存同步到磁盘当中,这个过程称为持久化操作。
Redis 的持久化方式:
- RDB 方式
- AOF 方式
- 无持久化
- 同时使用 RDB 和 AOF
7.1 RDB 持久化
默认支持的,不需要配置。
RDB 方式:
在指定的时间间隔内,将内存中的数据集快照写入到磁盘。
优势:
- 整个 Redis 的数据库将会只包含一个文件,这对于文件备份而言非常好;
- 对于灾难恢复而言,RDB 是非常不错的选择,因为我们可以将单独的文件拷贝,并压缩;
- 性能最大化。对于 Redis 的进程而言,需要做的,只是分叉出一些子进程,之后,再由子进程完成持久化的工作,这样就能极大的避免服务端进程执行 IO 的操作
- 相比 AOF 方式,如果数据集很大,RDB 启动速度会更快。
劣势:
- 如果想保证数据的高可用性,最大限度避免数据丢失,RDB 不是一种很好的方式。
$ cd /Users/D/Downloads/redis-5.0.7/etc
$ vim redis.conf
在配置文件中,找到如下的内容
save 900 1
表示每 900 秒至少有 1 个 key 发生变化,触发持久化操作;
save 300 10
表示每 300 秒至少有 10 个 key 发生变化,触发持久化操作;
save 60 10000
表示每 60 秒至少有 10000 个 key 发生变化,触发持久化操作;
数据保存的位置。
7.2 AOF 持久化
AOF 方式:
将以日志的形式记录服务器所处理的每一个操作,在 Redis 服务器启动之初,它会读取该文件,重新构建数据库,来保障启动后的数据时完整的。
Redis 的 AOF 持久化策略是将发送到 Redis 服务端的每一条命令都记录下来,并且保存到硬盘中的 AOF 文件中,类似修改日志文件,来一条命令就记录一条。
优势:
- 带来更高的数据安全性。Redis 提供了三种同步策略:每秒同步、每修改同步、不同步。每秒同步是异步完成的,效率也很高,但存在宕机时数据丢失问题;每修改同步是每次发生数据的变化,会立即记录到磁盘中,效率更低,更安全;
对日志文件的写入操作是 append 模式,因此在写入过程中,即使在发生了宕机,也不会破坏已经存在的内容。如果在写入一半之后出现了系统崩溃的问题,在 Redis 下一次启动之前,我们可以通过
redis/check/aof
工具来帮助我们解决数据一致性的问题。如果日志过大,Redis 可以自动启动重写机制,那么 Redis 以 append 模式不断的将修改的数据写入到老的磁盘当中,同时 Redis 还会创建新的文件,来记录此期间有哪些修改命令被执行了,因此,在进行重写切换的时候可以更好的保证数据的安全性。
AOF 方式包含一个格式非常清晰的、易于理解的日志文件,用于记录所有的修改操作。可以通过这个文件,进行数据的重建。
劣势:
- 对于相同数量的数据集而言,AOF 文件比 RDB 文件要大;
- 根据同步策略的不同,运行效率往往低于 RDB。
appendfsync always
每修改一次就同步到磁盘。
appendfsync everysec
每秒同步。
127.0.0.1:6379> shutdown
not connected> exit
$ redis-server /Users/D/Downloads/redis-5.0.7/etc/redis.conf
修改成 AOF 方式之后,先关闭服务器,然后重新启动。注意:启动要带有 conf 的文件路径。
$ redis-cli
127.0.0.1:6379> set num1 1
OK
127.0.0.1:6379> set num2 2
OK
127.0.0.1:6379> keys *
1) "num2"
2) "num1"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty list or set)
flushall
清空数据库。
清空之后,可以手动修改 appendonly.aof
文件,删除文件中记录的 flushall
命令,然后再次打开 redis 服务器和客户端,清除的数据就回来了。
注意:再次打开数据库的时候使用 $ redis-server xx/redis.conf
,而不是 $ redis-server
。
八、Redis 连接池
public final class RedisPool {
// Redis 服务器 IP
private static String IP = "127.0.0.1";
// Redis 的端口号
private static Integer PORT = 6379;
/* 可用连接实例的最大数目。
默认为 8,如果 MAX_TOTAL = -1,则表示不限制。
如果 pool 已经分配了 maxActive 个 jedis 实例,则此时 pool 的状态为 exhausted(耗尽)
*/
private static Integer MAX_TOTAL = 20;
// 控制一个连接池最多有多少个状态为空闲的 jedis 实例,默认值是 8。
private static Integer MAX_IDLE = 10;
// 等待可用连接的最大时间,单位是毫秒,默认值为-1,表示永不超时。
// 如果超过等待时间,则直接抛出 JedisConnectionException 异常
private static Integer MAX_WAIT_MILLIS = 10000;
private static Integer TIMEOUT = 10000;
// 在用一个 jedis 实例时,是否提前进行 validate(验证)操作;
// 如果为 true,则得到的 jedis 实例均是可用的
private static Boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;
static {
try {
// 获得连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
/*
在高版本的 jedis jar 包中,JedisPoolConfig 没有 maxActive 和 maxWait 属性。
maxActive ==> maxTotal
maxWait==> maxWaitMillis
*/
config.setMaxTotal(MAX_TOTAL);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT_MILLIS);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, IP, PORT, TIMEOUT);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized static Jedis getJedis(){
try {
if(jedisPool != null){
Jedis jedis = jedisPool.getResource();
return jedis;
}
else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
九、文章来源
慕神 & Redis 入门
redis ---- java 操作redis 及 redisClient可视化工具的安装使用
Redis客户端,提取码: kxee
以上是关于Redis的主要内容,如果未能解决你的问题,请参考以下文章