- 易扩展
- 灵活的数据模型
- 高可用
- 大数据量,高性能
Redis的概述
- 高性能键值对数据库,支持的键值数据类型:
- 字符串类型 - `String`
- 列表类型 - `Set`
- 有序集合类型 - `Sorted Set`
- 散列类型 - `Hash`
- 集合类型 - `List`
代码语言:txt复制- 缓存
- 任务队列
- 网站访问统计
- 应用排行榜
- 分布式集群架构中的session分离
Redis在Linux上的使用
可以看我这篇文章【Linux学习】 Redis常用的一些指令
Jedis的入门
- 我们要在
Java
平台上使用redis
,肯定需要Jedis
这个客户端。首先在pom
文件中引入Jedis
的依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
- 普通方式创建Jedis对象。
public void methodOne() {
Jedis jedis = new Jedis("100.64.84.47", 6379);
jedis.set("name", "cmazxiaoma");
String value = jedis.get("name");
System.out.println(value);
jedis.close();
}
- 通过线程安全的连接池来创建Jedis对象。
public void methodTwo() {
//获得连接池的配置对象
JedisPoolConfig config = new JedisPoolConfig();
//设置最大连接数
config.setMaxTotal(30);
//设置最大空闲连接数
config.setMaxIdle(10);
//获得连接池
JedisPool jedisPool = new JedisPool(config, "100.64.84.47", 6379);
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String value = jedis.get("name");
System.out.println(value);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
jedisPool.close();
}
}
}
- 编写测试类。
public class JedisDemo1Test {
private JedisDemo1 demo;
@Before
public void setUp() {
demo = new JedisDemo1();
}
@Test
public void methodOne() throws Exception {
demo.methodOne();
}
@Test
public void methodTwo() throws Exception {
demo.methodTwo();
}
}
- 运行
Test Case
,测试成功。
image.png
- 我们在
Xshell
软件,输入get name
指令,也可以看到输出cmazxiaoma
。
image.png
Redis的数据结构
String
Key
定义的注意点:
- 不要过长。
- 不要过短。
- 统一的命名规范。存储
代码语言:txt复制- 二进制安全的,存入和获取的数据相同。
- `Value`最多可以容纳的数据长度是`512M`。存储
代码语言:txt复制- 赋值
image.png
代码语言:txt复制- 取值
image.png
代码语言:txt复制- 删除
image.png
代码语言:txt复制- 数值增减
如果属性不存在的话,那么integer
类型默认为0
。
image.png
如果name
属性的值不能转换成integer
类型,那么会抛出ERR is not an integer or out of range
异常。
image.png
decr
指令也是一样的。
image.png
- 扩展命令
incrby
、decrby
也是一样的,很简单。
image.png
append
指令可以拼接字符串。
image.png
如果append key cmazxiaoma
。这个key
不存在的话,首先会创建这个key
,然后存入cmazxiaoma
内容,接着输出cmazxiaoma
。
image.png
Hash
- 赋值,可以使用
hset myhash key value
单一赋值、hmset myhash key value key value
多次赋值。
image.png
- 取值,可以用
hget myhash key
单一取值、hmget myhash key key
多个取值、hgetall
取出所有key
所对应的值。
image.png
- 删除 ,可以用
hdel myhash key
删除单一的key
。
image.png
hdel myhash key key
删除多个的key
。
image.png
del myhash
删除myhash
中所有的key
。
image.png
- 数值增减,
hincrby myhash key 100
image.png
- 使用
hexists myhash key
判断key
是否在myhash
中存在,存在返回1
,不存在返回0
。
image.png
hlen myhash
获取myhash
中存在key
的数量。
image.png
hkeys myhash
获取myhash
中所有的key
。
image.png
hvals myhash
获取myhash
中所有的values
。
image.png
List
- 存储list:
- `ArrayList`使用数组方式
- `LinkedList`使用双向链表方式两端添加
代码语言:txt复制- 使用`lpush a b c` 命令在左端添加,那么`c`肯定是在最左端。
image.png
代码语言:txt复制- 使用`rpush a b c`命令在右端添加,那么`c`肯定是在最右端。
image.png
- 两端弹出
- 使用`lpop mylist`弹出`mylist`中头部元素、`rpop mylist2`弹出`mylist2`尾部中的元素。它们都是`3`。
image.png
代码语言:txt复制- 我们接着来查看`mylist`、`mylist2`。
image.png
- 查看列表
- 使用
lrange mylist 0 5
来查看mylist
列表,mylist
插入的方式从头结点开始添加的,那么输出肯定是321abc
。
- 使用
image.png
代码语言:txt复制- 使用`lrange mylist2 0 5`查看`mylist2`列表,`mylist2`插入的方式是从最右端添加的,那么输出肯定是`abc123`
image.png
image.png
- 获取列表元素的个数
- 使用`llen mylist`命令
image.png
- 扩展命令
- 使用`lpushx mylist x`,使插入的元素在头部位置。
image.png
代码语言:txt复制- 使用`rpushx mylist x`,使插入的元素在尾部位置。
image.png
代码语言:txt复制- 使用`lrem mylist count element`,`count`代表是删除的次数,`element`代表是需要删除的元素。如果`count > 0` 代表删除的方式从头到尾,删除`count`个`element`,`count < 0`代表删除的方式从尾到头,删除`count`个`element`。如果`count = 0`,删除`mylist`中所有和`element`相同的元素。
image.png
image.png
代码语言:txt复制- `lrem mylist 2 test1`
image.png
代码语言:txt复制- `lrem mylist -2 test1`
image.png
代码语言:txt复制- `lrem mylist 0 cmazxiaoma`
image.png
代码语言:txt复制- 在某一个下标位置插入元素。`lset mylist index element`
image.png
代码语言:txt复制- 在目标元素之前插入指定的元素。`linsert mylist before helloworl before_helloworld`
image.png
image.png
代码语言:txt复制- 在目标元素之后插入指定的元素。`linsert mylist helloworld after after_helloworld`
image.png
代码语言:txt复制- 弹出`mylist`中最后一个元素,并插入到`mylist`中的头部。`rpoplpush mylist mylist`
image.png
代码语言:txt复制- `rpoplpush`使用场景
image.png
Set
和List
类型不同的是,Set
集合中不允许出现重复的元素。
- 添加/删除元素
- 添加
sadd myset a b c
,如果我们重复添加相同的元素,肯定是不成功的。比如sadd myset a
。
- 添加
image.png
代码语言:txt复制- 删除 `srem myset a`,删除`myset`中的`a`元素。
image.png
代码语言:txt复制- 查看`myset`中的元素。`smembers myset`
image.png
代码语言:txt复制- 查看指定元素是否是`myset`中的成员。`sismember myset a`,返回`0`代表不存在,返回`1`代表存在。
image.png
- 获得集合中的元素,
smembers myset
- 集合中的差集运算,
sdiff myset2 myset
。myset2
中元素有b,c,d
。myset
中元素有b,c
。它们之间的差集运算结果应该为d
。
image.png
代码语言:txt复制- 集合中的交集运算,`sinter myset2 myset`,应该输出`cb`。
image.png
代码语言:txt复制- 集合中的并集运算,`sunion myset2 myse`t,应该输出`cbd`。
image.png
- 扩展命令
- `scard myset` 查看`myset`有多少个元素。
image.png
代码语言:txt复制- `srandmember myset` 随机返回`myset`中的一个元素。
image.png
代码语言:txt复制- `sdiffstore new_myset myset2 myset` 把`myset`和`myset2`差集元素的结果存储到`new_myset`中。(`sinterstore`, `sunionstore`也是一样的用法)
image.png
- Set使用场景
- 跟踪一些唯一性的数据。
- 用于维护数据对象之间的关联关系。
SortedSet
SortedSet
中的成员在集合中的位置是有序的。
- 添加元素
zadd mysort 70 cmazxiaoma 80 xiaoma 100 doudou
image.png
- 获得元素
- `zcard mysort` 获得`mysort`中所有元素的个数
image.png
代码语言:txt复制- 获得`mysort`中`name`为`cmazxiaoma`对应的成绩。`zscore mysort cmazxiaoma`
image.png
- 删除元素,
zrem mysort cmazxiaoma deli doudou xiaoma
image.png
- 范围查询
zrange mysort 0 -1
,输出的key
是按成绩正序排列。
image.png
代码语言:txt复制- 如果输出的数据项要带上成绩的话,指令应该是`zrange mysort 0 -1 withscores`
image.png
代码语言:txt复制- 如果输出的数据项想按成绩逆序排序,那么就应该`zrevrange mysort 0 -1 withscores`
image.png
代码语言:txt复制- 如果想按排名范围进行删除的话,那么应该`zremrangebyrank mysort 0 2`
image.png
代码语言:txt复制- 如果想按成绩范围进行删除的话,那么应该`zremrangebyscore mysort 0 10`。顾名思义删除成绩在`0-10`之内的数据项。
image.png
- 扩展命令
- 查看分数在`0-10`之内的学生信息,`zrangebyscore mysort 0 10 withscores`
image.png
代码语言:txt复制- 查看分数在`0-100`之内且在第`1`行-第`2`行的学生信息。`zrangebyscore mysort 0 100 withiscores limit 0 2`
image.png
代码语言:txt复制- 给`cmazxiaoma`的成绩加`100`分。`zincrby mysort cmazxiaoma 100`
image.png
代码语言:txt复制- 查看成绩`0-10`之间的学生的个数。`zcount mysort 0 10`
image.png
Sorted Set
使用场景
- 如大型在线游戏积分排行榜
- 构建索引数据
Redis中的通用命令
key *
获取所有redis中的key
image.png
keys my*
获取所有redis
中以my
开头的key
image.png
exists mylist
查看redis
中是否存在mylis
t,0
代表不存在,1
代表存在。
image.png
rename name new_name
给名字为name
的数据结构重命名为new_name
image.png
expire new_name 10
设置redis
中new_name
过期时间,通过ttl new_name
看到其距离过期的时间。
image.png
type mylist
,可以查看mylist
对应的数据结构类型。
image.png
Redis的事务
Redis
相关的特性:
- 多数据库
- `Redis`事务一个
image.png
- 我们想把第
0
号的数据库中某些key
移动到第1
号数据库里面,那么我们该怎么做呢。通过move cmazxiaoma_test_mayday_5 1
就可以完成。
image.png
- 我们可以通过
multi
、exec
、discard
来完成事务操作。事务执行期间,Redis
不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。multi
相当于开启事务,exec
相当于提交,discard
相当于回滚。 - 首先我们在第一个客户端进行如下操作。我们在第一个客户端开启了事务,在事务中我们
incr num
2
次,按理来说,get num
应该等于4
。
redis第一个客户端.png
- 我们在第二个客户端输入
get num
,发现num
还是2
。那么证明了我们的结论:事务执行期间,Redis
不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。
image.png
- 如果我们在第一个客户端提交了事务。
image.png
- 接着我们在第二个客户端
get num
,发现可以num
的值得到了更新。
image.png
- 我们可以演示一下回滚操作,首先
set user cmazxiaoma
,接着开启事务,在事务中set user xiaoma
,然后进行回滚操作,发现get user
依然是cmazxiaoma
。
image.png
Redis的持久化
Redis
的性能体现在它把数据都保存在内存当中。我们把内存中的数据同步到硬盘当中的操作称之为持久化。
Redis
持久化方式:
- `RDB`方式,在指定的时间内,把内存中的数据快照写入到硬盘当中。
- `AOF`方式,将以日志的形式记录服务器所处理的每一个操作。当`Redis`服务器启动之初,它会读取该`aof`文件,会重新构建我们的数据库。保证我们启动之后,保证数据的完整性。
- 无持久化,我们可以通过配置禁止`Redis`服务器的持久化,我们认为`Redis`就是缓存的一种机制了。
- 同时使用。
代码语言:txt复制- 默认情况下,每隔一段时间`redis`服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做`"dump.rdb"`的文件里,这个持久化机制叫做`SNAPSHOT`。有了`SNAPSHOT`后,如果服务器宕机,重新启动`redis`服务器时,`redis`会自动加载`"dump.rdb"`,将数据库状态恢复上一次`SNAPSHOT`的状态。
- `Redis`服务器初始化过程中,设定了定时时间,每隔一段时间就会触发持久化操作,进入定时事件处理程序中,就会`fork`出子进程来进行持久化操作。
- `Redis`服务器预设了`save`指令,客户端可要求服务器进程中断服务,执行持久化操作。
- 我们可以通过`vim /etc/redis.conf`打开配置文件,可以看到以下配置。
image.png
代码语言:txt复制- 同时我们还可以看到内存快照输出在`file`文件名。
image.png
优缺点:
代码语言:txt复制- 如果数据集很大,`RDB`相对于`AOF`启动效率很更高。
- 如果想保证数据的高可用性,最大限度的避免数据的丢失,`RDB`将不是一个好的选择。因为系统在定时持久化操作之前,还没来得及在硬盘写入数据就发生宕机的话,就造成了数据的丢失。
- `RDB`通过`fork`出子线程来完成数据持久化操作,如果当数据集很大的时候,可能会导致服务器停止几百`ms`,或者几`s`。
RDB.png
AOF
(append only file
):- 对于
Redis
服务器而言,其缺省的机制是RDB
,如果需要使用AOF
,则需要修改appendonly no
改成appendonly yes
。Redis
在每一次收到数据修改的命令之后,都会将其追加到AOF
文件中。在Redis
下一次重新启动时,需要加载AOF
文件中的信息来构建最新的数据到内存中。
image.png
image.png
- 可以记录服务器的所有写操作。在服务器重新启动时,会把所有的写操作重新执行一遍从而实现数据的备份。当写操作集过大(比原有的数据集还大),
Redis
会重写写操作集。 - 带来更好的数据安全性,有
3
种同步策略,每秒同步,每修改同步,不同步。 每秒同步也是异步完成的,效率也非常高。缺点是一旦系统发生宕机的现象,那么这一秒中的修改的数据就会发生丢失。每修改同步,我们可以视为同步持久化。每一次发生数据的变化,就会立即的记录在磁盘,这种效率很低,但是很安全。 - 采用
append
追加的模式,就算系统发生宕机,也不会影响我们日志文件中已经存在的内容。然而我们本次操作中,只写入了一半数据就出现了系统崩溃的问题。在Redis下一次启动之前,我们可以通过"redis-check-aof --fix <filename>"
命令来修复坏损的AOF
文件,解决数据一致性的问题。 - 对于相同数量的数据集而言,
AOF
文件通常要大于RDB
文件。 AOF
在运行效率上往往会慢于RDB
。
AOF.png
RDB
和AOF
的区别 前者是保存了数据本身,而后者是记录了数据的变更。
尾言
这篇文章最后在网吧完成的,勿以善小而不为。