目录
数据库的两种形式:
1.关系型数据库:Mysql
2.非关系型数据库:Redis
什么是NoSQL?
NoSQL=Not Only SQL(不仅仅是SQL)
为什么要使用NoSQL?
NoSQL数据库是随着互联网的发展而产生的。
互联网应用的一些特征:
1.访问量大(用户量大)
2.高并发
3.高可用:让系统可以持续稳定的运行
4.海量数据
在当今互联网应用的特征下,关系型数据库已经无法满足快速的对海量数据进行读取,NoSQL顺势而生。
NoSQL的优势:
1.大数据量,高性能:得益于他无关系性,数据库结构简单。
2.灵活的数据模型:NoSQL无需事先建立字段,随时可以存储自定义的数据格式。
3.高可用
4.低成本
NoSQL的劣势:
1.无关系,数据之间是无联系的。
2.不支持标准的SQL
3.没有关系型数据库的约束,大多数也没有索引的概念
4.没有事务,不能依靠事务实现ACID
5.没有丰富的数据类型
Redis是当今非常流行的基于Key-Value结构的作为Cache使用的NoSQL数据库
Redis的安装和启动
redis真正意义上只有linux版本的,也只有在linux上可以发挥其最大的性能,所以我去阿里云租了一台服务器,使用的系统是linux
通过Xftp将redis压缩包上传至服务器,然后打开Xshell,通过解压缩以及make命令,完成redis的安装,如图:
接下来运行redis,redis的运行有两种方式:前台运行和后台运行(常用)
指令:
前台运行:./redis-server
后台运行:./redis-server &
然后打开redis客户端 ./redis-cli 测试链接是否正常
可以看到连接正常,redis正常运行
关闭redis:
1.正常关闭:使用redis客户端关闭,切换到/src/目录,执行 ./redis-cli shutdown
2.暴力关闭:指令 kill pid 或 kill -9 pid
附上远程连接阿里云redis方法
Redis的基本操作命令
1)沟通命令,查看状态:ping
返回PONG,表明redis服务运行正常
2)查看当前数据库中的key的数目:dbsize
默认访问的是第0个库
选择其他库的命令:select 1/2/3……
3)删除当前库的所有数据:flushdb
Redis的Key的操作命令
1) keys
查找当前库中的key。
keys * 查找所有的key值
2)exists
exists key[key]
判断查询的key是否存在
返回值,整数:存在返回1,不存在返回0
3)expire
expire key seconds
设置key的存活时间,超过时间key自动删除,时间是s
4)ttl
ttl key
以s为单位,返回一个key的存活时间
返回-1:key没有设置存活时间,永不过期
返回-2:key不存在
5)type
type key
查看key所存储值的数据类型
返回值:
none:key不存在
string:字符串
list:列表
set:集合
zset:有序集
hash:哈希表
6)del
del key[key]
删除指定的key,如果key不存在就忽略
Redis的五种数据类型
1)string字符串
redis的最基本的数据类型,可以存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON对象,甚至是一张图片,最大512M。
2)hash哈希表
一般是存放Java对象的信息,用途是共享会话,在分布式服务器里面可以用到,单门设置一个redis服务器里面存放用户信息,其余所有服务器从redis服务器中读取信息,实现服务器的信息共享。
3)list列表
是简单的字符串列表,按照插入的顺序排序。
4)set集合
是无序集合,集合的成员是唯一的,即集合中不能出现同样的数据。
5)zset有序集合
是一个排序的set集合。
字符串类型
基本命令
1)set
Set key value
每次创建一个key和一个value
2)get
get key
获取一个key所对应的value
3)incr
Incr key
将key中储存的数字值+1,类似于i++。只能对数字类型的数据操作
作用:incr的操作是原子性的,可以保证数据的安全,可以做全局的计数器
4)decr
用法同incr
5)append
append key value
如果key存在,则将value追加到key旧值的末尾
如果key不存在,则将key设置为value
返回追加后的总长度(数字)
常用命令
1)strlen
strlen key
返回key对应的字符串的长度
如果key不存在则返回0
2)getrange
getrange key start end
取子串,相当于java中的substring
3)setrange
setrange key offset value
替换原有的值
4)mset
mset key value[key value]
一次设置多个key-value
5)mget
mget key[key]
一次获取多个key所对应的值
哈希类型
基本命令
1)hset
hset hash表的key field value
将hash表key中的域field的值设置为value
2)hget
hget key field
获取哈希表key中给定域field的值
3)hmset
hmset key field value[field value]
设置多个field-value
4)hmget
hmget key field[field]
获取多个field对应的value
5)hgetall
hgetall key
获取哈希表key中的所有的数据
6)hdel
hdel key field
删除哈希表key中的给定域field的值
常用命令
1)hkeys
hkeys key
获取哈希表key中所有的field
2)hvals
hvals key
获取哈希表key中所有的values
3)hexists
hexists key field
检测哈希表key中的field是否存在
列表类型
基本命令
left->表头。。。表尾<-right
命令中“l”开头的是从表头开始的,“r”开头的是从表尾开始的
1)lpush/rpush
lpush key value[value]
将一个或多个插入到表头/表尾
2)lrange
lrange key start stop
获取列表key指定区间内的元素
取出所有的元素 lrange key 0 -1
3)lindex
lindex key index
取出特定位置上的元素
4)llen
llen key
获取列表的长度
常用命令
1)lset
lset key index value
将列表key下标为index的元素替换成value
2)linsert
linsert key before|after pivot value
将值value插入到列表key当中位于值pivot之前或之后的位置。
集合类型
基本命令
1)sadd
sadd key member[member]
将一个或多个成员加入到集合key中
2)smembers
smembers key
获取集合key中所有的成员元素
3)sismember
sismember key member
判断成员member是否在集合key中
4)scard
scard key
获取集合key中有多少的成员
5)srem
srem key member[member]
删除集合key中的一个或多个成员
常用命令
1)srandmember
srandmember key [count]
随机返回集合key中的count个元素
注:count是正数,元素不可以重复;count是负数,元素可以重复
应用:在制作验证码可能会用到
2)spop
跟srandmember差不多
是随机删除几个元素
有序集合类型
有序集合和集合的区别就是:有序集合每个元素都有一个score,redis通过这个score从小到大进行排序,score可以重复。score相同的,按member字典顺序排序
基本命令
1)zadd score member [score member]
添加成员
2)zrange key start stop [withscroes]
按从小到大的顺序获取成员
不加withscroes则只显示成员,不显示分数
加上两者都显示
3)zrevrange key start stop [withscroes]
按从大到小的顺序获取成员
4)zrem key member[member]
删除一个或多个成员
5) zcard key
获取有序集合中有多少成员
常用命令
1)zrangebyscore key min max
获取分数在min和max之间的所有成员,按照从小到大的顺序进行排序
注:min和max是包含在内的,(min,(max表示不把min和max包含在内。min,max可以用-inf,+inf表示负无穷和正无穷。用limit可以在结果集中进行分页处理
2)zrevrangebyscore key min max
获取分数在min和max之间的所有成员,按照从大到小的顺序进行排序
3)zcount key min max
获取分数在min和max之间的成员有几个
事务
与mysql中的事务不同,redis中的事务只是保证一条或多条命令可以执行成功,没有回滚之类的操作
相关命令
1)multi:开启事务
2)exec:执行事务
3)discard:放弃事务
4)watch
5)unwatch
事务的实现
1)正常事务的执行
步骤:开启事务->向事务队列中加入命令->提交事务
2)事务执行exec之前,入队命令错误,放弃事务
3)入队命令语法没错,但是运行时出错
这种情况事务还是被提交上去了,并没有回滚的动作,所以该命令前面的是都被执行且提交上去了的(就很呆,作者认为这是你自己的错误,不是我redis的错误【狗头】)
主从复制——配置redis服务器集群
通过修改配置文件的内容,实现redis的主从关系的制定,从而实现读写分离
写操作都在主服务器上进行,主服务器会把写入的key-value共享给从服务器。从服务器只能进行读取操作,这样加快了读取数据的性能
实现步骤:
1)拿到主服务器的ip和端口
2)修改从服务器的配置文件:
加上slaveof 主服务器ip 主服务器redis的端口号
masterauth 主服务器redis登录密码
3)重启主从redis服务
4)测试配置是否成功
redis的主从复制可以很好的实现数据的备份,以及容灾处理。当主服务器发生故障宕机时,我们可以手动提升一台从服务器为主服务器,其余从服务器设置为新的主服务器的从服务器(冷处理)
但是这种容灾处理是需要人工参与的,所以就有一定的延迟。后来redis开发了一套Sentinel模式,可以自动实现容灾处理
高可用Sentinel哨兵
工作模式:
哨兵系统最少三个,而且必须是奇数个
为了模拟,我们设置一主二从,设置三个哨兵。
先暂停redis服务器。
step1:修改哨兵配置文件。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
例如:
设置连接master和slave时的密码,注意的是sentinel不能分别为master和slave设置不同的密码,因此master和slave的密码应该设置相同。
例如:
step2:启动各个服务
注意启动顺序:先启动主服务器,在启动各个从服务器,然后在启动哨兵系统
我们让哨兵系统在前台运行,这样可以看到日志信息。
接下来我们模拟主服务器宕机情况:
关闭主服务器,然后我们会发现其中一个哨兵检测到主服务器宕机了,然后发起了投票,有如下的日志信息
从最后一行可以看出,哨兵系统自动的把6381这个端口的从服务器提到了主服务器,然后修改了其余服务器(包括原先的主服务器)的配置文件,完成了自动的处理
Jedis
Jedis是用java语言编写的,能够访问redis数据库的一个工具
Jedis对Redis操作的方法命名和redis的命令是一样的,所以非常的友好。
使用:
先添加maven依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
创建RedisUtil类
public class RedisUtil {
private static ShardedJedisPool pool;
//创建JedisPool对象
public static ShardedJedisPool open() {
if (pool == null) {
//创建pool
//创建JedisPoolConfig,给config设置连接池的参数。
JedisPoolConfig config = new JedisPoolConfig();
//设置最大的线程数,一个线程就是一个Jedis
config.setMaxTotal(100);
//设置最大空弦数
config.setMaxIdle(30);
//设置检查项为true,表示从线程池中获取的对象一定是经过检查可用的
config.setTestOnBorrow(true);
//集群
JedisShardInfo jedisShardInfo1 = new JedisShardInfo("114.55.27.202",6380);
jedisShardInfo1.setPassword("123123");
List<JedisShardInfo> list = new LinkedList<>();
list.add(jedisShardInfo1);
pool = new ShardedJedisPool(config,list);
}
return pool;
}
//关闭pool对象
public static void close() {
if (pool != null) {
pool.close();
}
}
}
使用工具类创建连接池,获取Jedis对象
public static void main(String[] args) {
ShardedJedisPool pool = null;
ShardedJedis jedis = null;
try{
pool = RedisUtil.open();
jedis = pool.getResource();
}catch (Exception e){
System.out.println(e.getMessage());
}finally {
RedisUtil.close();
}
}