在学习redis之前我们先来了解一下什么是NoSQL
关系型数据库RDBMS,其中包含mysql,oracle,SQLserver。
非关系型数据库NoSQL,redis等等。
出现nosql的主要原因是由于互联网的发展,出现以下瓶颈,(传统应用没有这些问题):
- 访问量特别巨大,
- 高并发:同时存在高并发问题【高并发:许多用户同时去做一件事情,引起数据竞争的情况,比如秒杀活动等】
- 高可用:在访问量巨大的情况下,保证系统能够稳定运行。
- 海量数据
NoSQL
首先不要被名字所迷惑,NoSQL不是“不是SQL”,而是“Not only SQL”,即不仅仅是SQL,也叫non-relational(非关系型数据库)。在NoSQL数据库中数据之间是无联系的,无关系的。数据的结构是松散的,可变的。
为什么使用NoSQL
关系型数据库的瓶颈
1)无法应对每秒上万次的读写请求,无法处理大量集中的高并发操作。关系型数据的是IO密集的应用。硬盘IO也变为性能瓶颈。
2)表中存储记录数量有限,横向可扩展能力有限,一张表最大二百多列【也就是字段列,最多只能256列】。纵向数据可承受能力也是有限的【存了多少条,行】,一张表的数据到达百万级,读写的速度就会逐渐的下降。面对海量数据,必须使用主从复制,分库分表。这样的系统架构是难以维护的。【所以也就是为什么mysql等关系型数据库会建立外键关系将几张表的数据联系起来,而不是直接将几张表的字段写在一起,因为这样写会导致查询慢】
大数据查询SQL效率极低,数据量到达一定程度时,查询时间会呈指数级别增长
3)无法简单地通过增加硬件、服务节点来提高系统性能。数据整个存储在一个数据库中的。多个服务器没有很好的解决办法,来复制这些数据。【换cpu或者换硬盘并不能起太大作用】
4)关系型数据库大多是收费的,对硬件的要求较高。软件和硬件的成本花费比重较大。
NoSQL的优势
- 大数据量,高性能【得益于非关系型数据库】
- 灵活的数据模型【不需要建表和列的,随时可以存储自定义的数据格式,而在关系型数据库中,由于可能存在外键,增删字段等是很麻烦的】
- 高可用【解决了关系型数据库扩展性差的问题】
- 低成本
NoSQL的劣势
- (1)无关系,数据之间是无联系的。【造成数据的冗余】
- (2)不支持标准的SQL,没有公认的NoSQL标准
- (3)没有关系型数据库的约束,大多数也没有索引的概念
- (4)没有事务,不能依靠事务实现ACID
- (5)没有丰富的数据类型(数值,日期,字符,二进制,大文本等)
Redis介绍
Redis是当今非常流行的基于KV结构的作为Cache(缓存)使用的NoSQL数据库
既然是kv结构,那肯定是与map相关,所以redis你可以想象成一个大“map”
大致原理:
也就是说以前service层访问dao层,取出数据。而现在是service层在第一次访问dao层后,将数据存到redis中,下次访问就不用访问dao层了,直接从redis中去取。总之就是通过redis,减少了service层对数据库的访问,所以说对数据库的访问越少,数据库处理请求的效率越高(比如以前数据库处理十万条,现在把部分交给redis缓存,数据库现在只处理一万条,自然处理数据的效率就高了)。所以一般redis用来存储用户经常访问的数据。
一般情况下80%是处理查询操作,20%是增删改操作。
Redis安装和使用
一般在windows环境中做测试,linux才是正式环境。在linux环境中运行效率最高。
windows安装和启动redis
- 下载
http://redis.io/
直接解压就可以用了
redis的使用
- 启动redis
直接双击“redis-server.exe”就可以启动。
如果出现闪一下就关闭,是因为exe没有识别到配置文件“redis.windows.conf”,我们可以手动命令行启动
上面的界面表示启动成功,能够看到访问redis的端口号。启动后的窗口不能关闭,关闭窗口,服务器就停了。
- 打开redis客户端,访问里面的数据
双击redis-cli.exe【注意不要关闭启动的服务器窗口】
- 在客户端就可以进行kv的创建和取值了。
输入命令set,会提示你创建kv
输入命令get,可以获取对应k的v
linux安装和启动redis
- 下载好linux的redis包
- 上传到linux服务器
- 解压缩到当前目录
tar -zxvf redis-3.2.9.tar.gz
- 进入解压后的redis文件夹内,
找到redis.conf配置文件,许多操作基本都离不开redis.conf配置文件,比如修改安全策略,使其能够远程访问redis
- 进入解压后的redis文件夹内
找到src文件夹,里面有后缀为“.c”、“.h”的文件,“.c”是c编写的源文件,不能直接执行,需要编译成可执行文件后才能执行,执行命令是“make xxx.c”。怎么编译,需要安装一个编译器:gcc
- 安装gcc
使用yum进行安装:yum -y install gcc
- 安装完成后,进入解压后的redis文件夹内,
命令:ll,再命令:make,编译源文件
- 编译完后,再执行命令:make install
这个命令可执行也可不执行,大概就是把redis这些可执行程序,放入类似环境变量中,以至在任何地方都使用redis命令。
- 进入src文件夹,里面有绿色的文件,表示可执行文件。
redis-server表示启动服务,redis-cli表客户端
- 安装完成
- 启动redis-server
前台启动方式:./redis-server 回车 【这个命令中不能执行其他命令,执行ctrl+C停止redis服务】
后台启动方式:./redis-server & 回车 【这个命令执行后,可以使用其他linux命令,而redis会在后台继续运行】
使用“ps -ef | grep redis”命令,查看后台redis进程
- 启动服务器后,再启动客户端redis-cli
./redis-cli
- set创建kv/get获取kv
- 关闭redis-cli
(1)方式一
./redis-cli shutdown
这种方式推荐使用,执行该命令后,会拒绝接收新的请求,把正在处理的工作处理完毕,再关闭。
(2)方式二
kill pid或者kill -9 pid
这种方式不会考虑当前应用是否有数据正在执行操作,直接就关闭应用。
先使用“ps -ef | grep redis”命令查看进程号,再使用 kill 进程号
Redis客户端
redis启动之后,我们怎么去操作redis
redis命令行客户端
- redis命令行客户端,也就是之前使用的redis-cli
redis远程客户端
一个图形化的客户端:Redis Desktop Manager或者java写的redisclient,相当于Navicat
- 双击Redis Desktop Manager
这样在windows远程访问linux上的redis可能会失败,因为你需要考虑linux服务器的防火墙,还有就是redis有一个安全策略,也就是redis安装后默认只能本机访问。所以我们去修改redis的安全策略,使远程访问能够生效。
- 修改redis.conf配置文件
- 修改配置文件,vim redis.conf
- 首先使用“/bind”命令搜索“bind”字符,按N键匹配字段,按insert插入#,注释掉下面的这一行
#bind 127.0.0.1 -::1
- 其次把保护模式改为no
protected-mode no
- 将requirepass取消注释,配置好密码,否则容易造成key丢失,变为backup【设置密码后,进入server-cli,需要验证密码:auth “yourpassword”】
- 因为修改了配置文件,在启动redis时需要指定配置文件的位置【注意redis-server是在src文件夹下,而redis.conf与src文件夹同级】
先进入src目录
命令:./redis-server …/redis.conf &
- 再来看一下防火墙的状态
命令:systemctl status firewalld
通过查看active:dead表示防火墙是关闭的
- 以上两步都处理好了,我们可以继续在windows上远程连接linux上的redis了
- 连接成功
- 这些数据库不能单独命名,是用它索引来表示的db0-db15
注意:
连接超时问题
如果在windows客户端软件上出现连接超时【java.net.SocketTimeoutException: connect timed out 】错误,是linux服务器把redis的6379端口给拦截率,需要执行如下命令打开
/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT
key丢失问题
redis的key都变成了backup,值也都不见了,这是为什么呢?
redis编程客户端Jedis
表示使用某个工具库对redis的访问。
推荐使用Jedis客户端,是一个jar包。通过使用Jedis在中的方法,来完成对数据库操作。
Redis基本命令
命令行客户端操作命令
- 查看状态
- dbsize:查看当前数据库的key的数目【默认访问的是第0个数据库】
- redis默认使用16个库【0-15】,可以在redis.conf中修改库的个数【databases 16】
- select index【表示选择使用那个数据库,比如使用第六个的数据库:select 5,因为下标是从0开始的,但是名字还是db5】
- flushdb:删除当前库的所有数据
- exit或quit:退出redis命令行客户端,但是redis服务还是存在
key的操作命令
- keys pattern:用来查找key,pattern可以使用通配符*,?表示单个字符,如wo?d,匹配word,wood
- exists key[key…]:判断key是否存在,存在则返回1,不存在0;使用多个key,返回存在的key的个数
- expire key seconds:设置key的存活时间,超时自动删除,单位秒;设置成功返回1,其他情况0
5秒后刷新数据库,K1已经被自动删除
**业务实现:**一般我们可以为登录注册时为验证码设置存活时间。比如当用户来到注册页面时,填写注册信息时,页面向服务器发起请求,生成验证码,我们可以将这个验证码作为一个key使用set保存到redis数据库中(value也设为验证码),然后使用expire 为这个key设置存活时间60秒,我们还可以使用ttl命令去查看这个key的剩余存活时间,如果存活时间大于等于0,那么这个验证码就有效,还没过期。就能使用get拿出这个key的value,去和传过来的key进行比对。用户点击注册时,就能成功注册,如果是其他值则表示验证码过期。
- ttl key :返回key剩余的生存时间,单位秒;返回值-1,没有设置key的生产时间。-2表示key不存在。数字key的剩余时间,单位秒
- type key:查看key所存储的数据类型
none:key不存在
string字符串、list列表、set集合、zset有序集、hash哈希表
- del key[key…]:删除key
redis的5种数据类型
string
字符串类型是edis中最基本的数据类型,它能存储任何形式的字符串,包括二进制
数据,序列化后的数据,JSON化的对象甚至是一张图片。最大512M。
hash类型
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。相当于map。
这样理解有点抽象,我们来用map代码解释:
在Java中map的key,在redis叫做field。redis的key就是库key。
在上面的图中,我们创建一个Map对象data,将用户信息存进data中,再创建一个Map对象map,把前一个map对象data当做value存入map中,并为其定义一个key“loginuser”。这就是hash类型。
业务实现:一个用户登录后,session将用户信息保存到服务器A,但是第二次登录时,如果访问的不是服务器A,而是服务器B,那么用户就需要再次登录。有的人说那么每台服务器上都去备份一个该用户的session,但是这样有问题,如果该用户信息有所更改,岂不是每一台服务器上面的session都要改?
所以我们一般单独设置一台服务器用来专门保存用户信息,这台服务器使用redis库,当用户多次登录时,让其他服务器都来访问这个redis服务器,以获取信息。而这个redis就是用map来保存信息的。这其实也叫做共享会话
list列表类型
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
集合类型Set
Redis的Set是string类型的无序集合,集合成员是唯一的,即集合中不能出现重复的数据.
zset有序集合
Redis有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。
Redis数据类型操作命令
redis中对五种数据类型有各自专属的命令,每一种数据类型都有一组命令,来操作这个数据。
这些命令可以自行博客:
https://blog.csdn.net/wxyf2018/article/details/102831946
Redis高级
本节一般是服务器的配置,在现实开发中,一般是技术经理或者技术总监去做。
Redis事务
持久化
主从复制
安全设置
Jedis操作Redis
使用Redis官方推荐的Jedis
在java应用中操作Redis。Jedis几乎涵盖了Redis的所有命令。操作Redis的命令在Jedis中以方法的形式出现。jedis完全兼容redis2.8.xand3.x.x
- Jedis源码:https:/github.com/xetorthio/jedis
- api文档:http:/xetorthio.github.io/jedis/,
- 下载:http://search.maven.org/,搜索jedis
下载Jedis和Commons-Pool
Jedis在使用过程中,存在线程不安全问题,所以一般需要结合Commons-Pool线程池使用,一方面可以提高jedis库的使用效率,另一方面可以避免线程不安全问题。