NoSQL一词最先出现于1998年,是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。2009年,Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论,来自Rackspace的Eric Evans再次提出了NoSQL的概念,这时的NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式。它不一样于传统的关系数据库,二者存在许多显著的不一样点,其中最重要的是NoSQL不使用SQL做为查询语言。其数据存储能够不须要固定的表格模式。前端
git
Redis是使用c语言开发的一个高性能键值数据库。经常使用于分布式系统中的缓存、电商秒杀、排行榜、访问量统计、分布式会话共享等高并发应用场景。Redis能够经过一些键值类型来存储数据。其数据类型包括字符类型、散列类型、列表类型、集合类型、有序集合类型。github
访问Redis官网https://redis.io/download下载最新的版本 。redis
解压并编译安装sql
$ tar xzf redis-5.0.3.tar.gz
$ cd redis-5.0.3
$ make install
Redis官网并无提供windows版本,但能够前往https://github.com/tporadowski/redis/releases下载windows的我的编译版本(注意:并非最新的版本)。数据库
在redis的src目录有一个redis-server文件,用于启动一个redis服务。windows
redis的默认端口为6379,当客户端须要链接到redis服务时,就经过服务端的IP地址以及这个端口进行链接。也能够修改这个默认端口。在redis的根目录下有一个redis.conf文件,它是redis的核心配置文件,redis的全部配置信息都在此文件中。若是须要修改端口,咱们在配置文件中找到port配置,并将6379改成其余的端口号。后端
修改完后须要从新启动redis服务,须要注意的是,在使用redis-server启动服务时须要指定redis.conf文件的绝对路径,不然redis将以默认的配置启动一个服务实例。设计模式
前端启动的模式咱们能够在终端看到redis的启动信息和相关的操做日志,但此时若是关闭了终端或者使用control+c将会当即中止redis服务。缓存
所谓后端启动,就是以一个独立的进程来运行一个redis服务。首先修改redis.conf文件,找到daemonize选项并设置为yes,以下图:
保存退出后从新启动redis服务,此时redis将之后台进程的方式启动服务。终端没有显示相关的启动信息,而且启动完成后,终端能够继续执行其余的操做。
在redis的src目录下有一个redis-cli命令,这个就是官方提供的redis客户端,可使用它来链接和操做redis。固然,这仅仅只是一个命令行的客户端程序,在实际的开发中会有不一样的平台语言,所以官网也提供了对各类语言的客户端实现,在实际的项目开发中使用不一样语言的客户端来操做redis。例如官网提供了一个Java的客户端Jedis。
1)使用redis-cli
可使用使用官方自带的redis-cli客户端来链接redis服务。参数-h为链接redis服务器的IP地址,-p为redis的端口号。链接完成后就能够对redis进行操做了,咱们使用简单的set和get命令来进行存储和访问操做。
2)退出客户端
若是想要退出客户端的链接只须要在链接的状态下输入quit或者exit便可。
3)身份认证
默认链接Redis时是不须要认证密码的,咱们能够为其设置一个链接的认证密码。首先在redis.conf中找到requirepass配置项,取消注释并设置一个密码。
保存后重启服务,在链接客户端时加上-a参数并输入配置的密码。
链接时也能够不指定密码也能够正常链接,但在操做Redis时候会提示一个错误,要求输入认证密码。这时使用auth命令来输入密码便可。
若是设置了认证密码,在关闭客户端时也一样须要指定。
也可使用第三方的redis的可视化客户端RDM(redis-desktop-manager),它同时提供了各类系统平台的编译版本,安装后便可使用。下载地址:
点击左上角的Connect to Redis Server,在弹出的窗口中填写相关的Name(链接名称)、Address(链接地址)、端口号以及认证密码(Auth),点击OK便可。
这里咱们看到链接redis后默认有16个库(0 ~ 15),这是redis默认的配置,能够在redis.conf中能够找到相应的选项并修改默认数量。
当咱们使用客户端链接redis时,默认选择的是index为0的数据库,然而也可使用select命令选择其余数据库。例如选择index为15的数据库,以下操做:
若是使用前端启动redis,可使用control+c或者kill命令来杀掉进程的方式关闭redis(注意:control+c并不能中止后端启动的redis),但这些方式都是强制性的关闭redis,因为redis保存的数据先会存储在内存,若是此时强制关闭,将致使redis还没将数据持久化到文件中就退出,可能会照成部分的数据丢失。所以,应该使用正常的退出方式来中止redis服务,正常退出redis一样使用redis-cli客户端。
上面的命令表示关闭本机端口为6379的redis服务。
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及sorted set(zset:有序集合)。
String 是 redis 最基本的类型,一个 key 对应一个 value。它是二进制安全的,能够包含任何数据,如jpg图片或者序列化的对象。
1)SET
语法:set key value
赋值操做。
2)GET
语法:get key
取值操做。
3)GETSET
语法:getset key value
取值并赋值。
4)MSET
语法:mset key value [key value ...]
同时设置多个键值。
5)MGET
语法:mget key [key ...]
获取多个键值。
6)DEL
语法:del key [key ...]
删除一个或多个键值对。
7)INCR
语法:incr key
当存储的字符串是整数时,让当前键值递增,并返回递增或增长后的值。
8)INCRBY
语法:incrby key increment*
当存储的字符串是整数时,让当前键值增长指定的数值,并返回递增或增长后的值。
9)DECR
语法:decr key
让当前键值递减,并返回递减或减小后的值。
10)DECRBY
语法:decrby key decrement
让当前键值减小指定的数值,并返回递减或减小后的值。
11)APPEND
语法:append key value
向键值的末尾追加value。若是键不存在则将该键的值设置为value,即至关于 SET key value。返回值是追加后字符串的总长度。
12)获取字符串长度(STRLEN)
STRLEN命令返回键值的长度,若是键不存在则返回0。
hash是一个string类型的field和value的映射表,而field只能是String类型,hash特别适合用于存储对象。
1)HSET
语法:HSET key field value
HSET一次只能设置一个字段值。HSET命令不区分插入和更新操做,当执行插入操做时HSET命令返回1,当执行更新操做时返回0。
2)HMSET
语法:HMSET key field value [field value ...]
HMSET和HSET做用同样,只不过一次能够设置多个字段值。
3)HSETNX
语法:HSETNX key field value
当字段不存在时赋值,相似HSET。区别在于若是字段存在,该命令不执行任何操做。
例如:hsetnx user name zing
说明:若是user中不存在name字段则设置name的值为zing,不然不作任何操做。
4)HGET
语法:HGET key field
HGET一次只能获取一个字段值。
5)HMGET
语法:HMGET key field [field ...]
HMGET一次能够获取多个字段值。
6)HGETALL
语法:HGETALL key
获取全部字段值。
7)HDEL
语法:HDEL key field [field...]
能够删除一个或多个字段,返回值是被删除的字段个数。
8)HINCRBY
语法:HINCRBY key field increment
为某个字段增长数值。
9)HEXISTS
语法:HEXISTS key field
判断字段是否存在,存在则返回1,不然返回0。
10)HKEYS
语法:HKEYS key
获取全部的字段名。
11)HVALS
语法:HVALS key
获取全部字段的值。
12)HLEN
语法:HLEN key
获取字段数量。
Redis的list是采用来链表来存储的,因此对于Redis的list数据类型的操做,是操做list的两端数据来操做的。
1)LPUSH
语法:LPUSH key value [value ...]
向列表左边添加元素。
2)RPUSH
语法:RPUSH key value [value ...]
向列表右边添加元素。
3)LRANGE
语法:LRANGE key start stop
LRANGE命令是列表类型最经常使用的命令之一,用于获取列表中的某一片断,将返回start到stop之间的全部元素(包含两端的元素),索引从0开始。索引能够是负数,如:-1表明最后边的一个元素。
4)LPOP
语法:LPOP key
LPOP命令从列表左边弹出一个元素,会分两步完成:第一步是将列表左边的元素从列表中移除。第二步是返回被移除的元素值。
5)RPOP
语法:RPOP key
RPOP命令从列表右边弹出一个元素,步骤与LPOP相似,第一步是将列表右边的元素从列表中移除。第二步是返回被移除的元素值。
6)LLEN
语法:LLEN key
获取列表中元素的个数
7)LREM
语法:LREM key count value
LREM命令会删除列表中前count个值为value的元素,返回实际删除的元素个数。根据count值的不一样,该命令的执行方式会有所不一样:
当count>0时, LREM会从列表左边开始删除。
当count<0时, LREM会从列表右边开始删除。
当count=0时,LREM删除全部值为value的元素。
8)LINDEX
语法:LINDEX key index
得到指定索引的元素值。
9)LSET
语法:LSET key index value
设置指定索引的元素值。
10)LTRIM
语法:LTRIM key start stop
只保留列表的指定片断
11)LINSERT
语法:LINSERT key BEFORE|AFTER pivot value
LINSERT首先会在列表中从左到右查找值为pivot的元素,而后根据第二个参数是BEFORE仍是AFTER来决定将value插入到该元素的前面仍是后面。
12)RPOPLPUSH
语法:RPOPLPUSH source destination
将一个列表的最后一个元素转移到另外一个列表的最前面
Redis 的 Set 是 String 类型的无序集合。集合成员是惟一的,这就意味着集合中不能出现重复的数据。
1)SADD
语法:SADD key member [member ...]
增长一个或多个元素。
2)SREM
语法:SREM key member [member ...]
移除一个或多个元素。
3)SMEMBERS
语法:SMEMBERS key
得到集合中的全部元素。
4)SISMEMBER
语法:SISMEMBER key member
判断元素是否存在集合中。存在返回1,不然返回0。
5)SDIFF
语法:SDIFF key [key ...]
查找属于集合A而且不属于集合B的元素。(差集运算)
6)SINTER
语法:SINTER key [key ...]
查找属于集合A且属于集合B的元素。(交集运算)
7)SUNION
语法:SUNION key [key ...]
查找属于集合A或者属于集合B的元素。(合并运算)
8)SCARD
语法:SCARD key
获取集合中元素的个数。
9)SPOP
语法:SPOP key [count]
从集合中弹出一个或多个元素,由count指定。若是不指定count,默认弹出一个。因为集合是无序的,全部SPOP命令会从集合中随机选择一个元素弹出。
zset又称sorted set,称之为有序集合,可排序的,可是惟一。和set的不一样支出在于zet会给集合中的元素添加一个分数,而后经过这个分数进行排序。
1)ZADD
语法:ZADD key score member [score member ...]
向有序集合中加入一个或多个元素和该元素的分数,若是该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数,不包含以前已经存在的元素。
2)ZSCORE
语法:ZSCORE key member
获取元素的分数。
3)ZREM
语法:ZREM key member [member ...]
移除有序集合中的一个或多个成员,不存在的成员将被忽略。
4)ZRANGE
语法:ZRANGE key start stop [WITHSCORES]
按照元素分数从小到大的顺序返回索引从start到stop之间的全部元素(包含两端的元素)。若是须要得到元素的分数能够在命令尾部加上WITHSCORES参数。
5)ZREVRANGE
语法:ZREVRANGE key start stop [WITHSCORES]
按照元素分数从大到小的顺序返回索引从start到stop之间的全部元素(包含两端的元素)。若是须要得到元素的分数的能够在命令尾部加上WITHSCORES参数。
6)ZRANK
语法:ZRANK key member
获取元素排名(从小到大)。
7)ZREVRANK
语法:ZREVRANK key member
获取元素排名(从大到小)。
8)ZRANGEBYSCORE
语法:ZRANGEBYSCORE key min max WITHSCORES
得到指定分数范围的元素。
9)ZINCRBY
语法:ZINCRBY key increment member
增长某个元素的分数,并返回更改后的分数。
10)ZCARD
语法:ZCARD key
获取集合元素的数量。
11)ZCOUNT
语法:ZCOUNT key min max
获取指定分数范围内的元素个数。
12)ZREMRANGEBYRANK
语法:ZREMRANGEBYRANK key start stop
按照排名范围删除元素。
13)ZREMRANGEBYSCORE
语法:ZREMRANGEBYSCORE key min max
按照分数范围删除元素。
Redis键是二进制安全的,这意味着你可使用任何二进制序列做为键,从像”foo” 这样的字符串到一个 JPEG文件的内容。空字符串也是合法的键。
不要使用太长的键。例如,不要使用一个1024字节的键,不只是由于占用内存,并且在数据集中查找key时须要屡次耗时的key比较。
不要使用过短的key。例如,user:1001比u1001更具备实际意义,相对于key自己以及value对象来讲,增长的空间微乎其微。固然,短的键会消耗少的内存,须要找到平衡点。
规范一种模式 (schema)。用冒号或者下横线来链接多单词字段,例如:”user:1000”或者"user_1000"。
1)KEYS
语法:keys pattern
返回指定pattern的全部key
2)EXISTS
语法:exists key
判断一个key是否存在。存在返回后1,不然返回0。
3)RENAME
语法:rename key newkey
重命名key
4)TYPE
语法:type key
根据key返回value的类型。
5)EXPIRE
语法:expire key seconds
设置key的生存时间。Redis的数据是缓存在内存中的,而后不少时候数据通常都会设置一个过时时间(即到期后销毁数据,从而释放更多的内存)。过时时间默认以秒为单位,默认值为-1,表示永不过时。
也能够在设值的时候指定过时时间(秒)
6)TTL
语法:ttl key
查看key剩余的过时时间。
7)PERSIST
语法:persist key
清除key的过时时间。
8)PEXPIRE
语法:pexpire key
以毫秒为单位设置key的过时时间。
也能够在设值的时候指定过时的时间(毫秒)
Redis是一个支持持久化的内存数据库,能够将内存中的数据同步到磁盘保证持久化。咱们知道Redis会将数据缓存在内存中,若是没有持久化,在服务器关闭或重启以后数据会丢失。为了保证数据的安全以及效率,Redis会周期性的把更新的数据写入磁盘或者把修改操做写入追加的记录文件。而Redis提供了RDB和AOF两种持久化策略。
Redis默认是会以快照RDB的形式将数据持久化到磁盘的一个dump.rdb二进 制文件。当Redis决定要持久化时,会 fork 一个子进程将数据写到磁盘上一个临时的RDB文件中,当子进程完成写操做后,将原来的RDB替换掉。而Redis会在知足某些条件后会进行持久化,而且能够对其进行配置。
配置RDB
在redis.conf文件中找到“Save the DB on disk”的配置,咱们能够根据须要来修改这Redis的RDB持久化策略。
说明:
save 900 1(若是在900秒以内有1次操做,则执行快照保存)
save 300 10(若是在300秒内有10次操做,则执行快照保存)
save 60 10000(若是在1分钟以内有10000个次操做,则执行快照保存)
SAVE和BGSAVE
咱们能够在客户端直接使用SAVE或者BGSAVE命令当即将Redis的数据持久化到RDB文件中。他们二者的区别在于BGSAVE命令会fork一个子进程在后台进行持久化,主进程能够继续处理客户端发送的命令(非阻塞)。而SAVE命令须要等待Redis持久化完成后才能够继续处理客户端发送的命令(阻塞)。
RDB优势
RDB很是适合用于数据备份, 能够在当天内每小时备份一次,或者每月的天天都进行备份。 若是遇到断电或者宕机等其余一些灾难状况,能够随时将数据集还原。
RDB缺点
若是对数据的完整性和安全性要求很是高,要求每一次的操做数据都能持久化到文件中,这时RDB就不太适合了。由于RDB是按照时间范围的操做次数为条件促发持久化,若是未知足这些触发条件,Redis并不会将数据保存到文件,致使数据丢失。例如:save 60 10000,若是在1分钟以内有9000次的操做,若是此时服务器异常退出或宕机,因为未知足条件,将致使丢失这1分钟的数据。
AOF持久化能够记录每一个写操做,将Redis执行过的全部写指令(读操做不记录)保存到appendonly.aof文件中,而且只容许追加文件而不能够改写文件。在Redis启动的时候会读取该文件从新构建缓存数据。在打开AOF持久化机制以后,Redis每当接收到一条写命令,会先写入系统缓存,而后每隔必定时间(默认是每秒钟)fsync一次(写入到指定文件)。
启用AOF
AOF持久化默认是关闭的,若是要启用AOF,须要在redis.conf配置文件中启用该功能,将appendonly no设置为appendonly yes。
全部写操做默认保存在appendonly.aof文件中,能够自行修改保存的路径和文件名。
同步策略
AOF提供了三种同步策略:
always(每次写操做就执行一次fsync)
everysec(每秒执行一次fsync,默认)
no(不执行fsync)
AOF重写
AOF会记录Redis全部的写操做命令,但这种方式会形成一个问题,就是随着时间的推移,大量频繁的操做将致使AOF文件体积的急剧增加,对系统会形成影响。为了解决以上的问题, Redis就须要对AOF文件进行重写。重写的过程会建立一个新的AOF文件来代替原有的AOF文件, 而新AOF文件和原有AOF 文件保存的数据状态是一致的,但新文件的体积将变得尽量地小。如下两种方式会触发AOF重写。
1)手动出发
在客户端直接向Redis发送BGREWRITEAOF命令,这个命令会经过移除AOF文件中的冗余命令来重写(rewrite)AOF文件。
2)自动触发
其实在启用了AOF以后(appendonly yes),Redis会依据redis.conf配置文件中的auto-aof-rewrite-percentage选项和auto-aof-rewrite-min-size选项来自动执行BGREWRITEAOF命令。
说明:
例如设置了auto-aof-rewrite-percentage为100和auto-aof-rewrite-min-size为64mb,那么当AOF文件的体积大于64MB时,而且AOF文件的体积比上一次重写以后的体积大一倍(100%)的,Redis将执行BGREWRITEAOF命令进行重写。
AOF优势
AOF弥补了RDB按照时间范围的操做次数为条件的缺点,即便在默认的策略中发生故障,最多也只会丢失一秒钟的数据,更大程度的保证了数据的安全性。
AOF缺点
AOF会保存每一次的写操做,这将致使AOF文件的体积一般要大于RDB文件。若是选用always策略,则表示每一次操做都会记录到AOF文件中,从性能的角度上来讲会低于RDB。固然,使用默认的everysec策略进行持久化性能仍是很是可观的。
在实际应用中,一般会同时使用RDB和AOF两种持久化来找到一个最佳的平衡点,即能保证性能的同时最大程度保证数据的安全。所以须要RDB和AOF二者同时进行合理的设置和调整。而从Redis 4.0开始,官方提供了一种更加方便的混合持久化配置。
未启用混合持久化
在未启用混合持久化以前,若是咱们往Redis写入一条记时,RDB文件会保存操做的键值数据,AOF文件则保存的是写操做的指令,咱们能够分别查看一下这两个文件的内容。
使用cat命令查看RDB文件
然而显示的内容并不太直观也不易理解,所以能够借助Redis提供的redis-check-rdb工具进行查看。
RDB文件中会保存Redis的相关信息以及存储的keys数量和相关的活期时间。接下来咱们继续查看AOF文件的内容,直接使用cat命名进行查看。
结果显示AOF文件中保存的是相关的操做指令。
启用混合持久化
要使用混合持久化,除了在redis.conf文件中启用AOF(将appendonly设置为yes),还须要将aof-use-rdb-preamble设置为yes。
设置完从新启用Redis服务。启用了混合持久化以后,使用BGREWRITEAOF命令执行一次AOF重写,同时向Redis插入一条新的数据。
而后再次使用cat命令再次查看AOF文件,这时会发现启用混合持久化以后的AOF文件内容和未启用时的AOF文件内容不同。这是由于此时产生的AOF文件是一个RDB-AOF的混合文件,Redis会基于某种协议将此文件的前半部分存储RDB的数据,后半部分存储的是AOF的操做命令。
Redis事务能够一次执行多个命令(批量命令操做),而且是一个单独的隔离操做。事务中的全部命令都会按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。
Redis事务主要由MULTI 、 EXEC、DISCARD、WATCH和UNWATCH这些基础命令构成。
1)MULTI
语法:MULTI
用于标记事务的开始,后续客户端执行的命令都将被存入一个命令队列,直到执行EXEC时,这些命令才会被执行。
2)EXEC
语法:EXEC
执行命令队列中的全部命令,但若是在启用一个事务以前执行了WATCH命令,那么只有当WATCH所监控的keys没有被修改的前提下,EXEC命令才能执行事务队列中的全部命令,并返回全部命令的执行结果,不然EXEC将放弃当前事务中的全部命令。
3)DISCARD
语法:DISCARD
取消事务队列中的全部命令,并将当前链接的状态恢复为非事务状态。若是WATCH命令被使用,会自动执行UNWATCH取消监视的全部keys。
4)WATCH
语法:WATCH key[key...]
WATCH命令相似于关系型数据库的乐观锁,能够在启用事务以前监视某些keys的变化。在MULTI命令执行以前,能够指定须要监视的keys,在执行EXEC以前,若是被监控的keys发生修改,EXEC将放弃执行该队列中的全部指令。而且WATCH命令能够监控一个或多个键,一旦其中有一个键被修改(或删除),以后的事务就不会执行。
首先打开一个客户端,并使用watch命令监视user:1001的key,接着使用multi启用事务。
而后打开第二个客户端,并修改key为user:1001的value为user01。
最后回到第一个客户端再次对key为user:1001的value修改成user001,并执行exec命令。因为user:1001这个key被第一个客户端所监视,而这个key在启用事务前被第二个客户端修改了,所以当第一个客户端启用事务后再对其进行修改时这是无效的,Redis将放弃队列中的全部指令,返回了(nil)。
5)UNWATCH
语法:WATCH key[key...]
取消当前事务中指定监控的keys。若是执行了EXEC或DISCARD命令,则无需再手工执行该命令了,由于在此以后UNWATCH命令会自动执行,事务中全部的keys都将自动取消监控。
在关系型数据库中的原子性表明一系列不可分割的操做,要么所有执行成功,要么所有不执行。若是执行过程当中产生了错误或者异常,那么事务将会自动回滚。而在Redis的事务中是否具有原子性呢?咱们看看如下两种状况,并得出相关的结论。
错误指令
在使用multi命令开启事务以后,而后输入一些命令,其中包含一个错误的命令。
从结果来看彷佛有点符合咱们对事务的理解。但仔细想一想,这只是在输入命令的时候产生语法的错误,Redis对其进行了校验,报错以后Redis就放弃了这个事务。所以得出的结论是:Redis在启用事务输入操做命令时是原子操做,它会对命任何一个命令进行语法检查,当输入有误时,Redis会清空队列并放弃事务。
运行时错误
若是输入的命令都正确,而在执行这些命令时产生了错误,Redis是否会取消全部命令并放弃事务呢?看下面的例子。
当执行到第二条命令时产生了错误(用户名不是一个整型数值,并不能自增),可是前面和后面的命令都执行成功。并不会由于执行了一个错误的命令而回退全部已经执行成功的命令并放弃整个事务。所以得出的结论是:Redis在执行命令队列时并非原子性的,通俗点说就是Redis自己并不支持事务的回滚机制。