1 .NoSQL数据库简介
1.1技术发展
技术分类:
1.解决功能性问题:java ,Jsp ,RDBMS,Tomcat,HTML,Linux,JDBC,SVN
2.解决扩展性问题:Struts,Spring,SpringMVC,Hibernate,Mybatis
3.解决性能问题:NoSQL,java线程,Hadoop,Nginx,MQ,ElasticSearch
web2.0利用负载均衡(nginx)减轻服务器的压力,但对数据库造成了压力。并且session值会出现问题
解决方案:
1)存储到客户端(不能保证数据的安全)
2)session复制(会浪费服务器的空间)
这个时候出现了NoSql(能减少cpu, io的压力直接通过内存读取)
1.2NoSQL数据库
1.2.1NoSQL数据库概述
NoSQL(NOSQL=not only sql)意思就是 不仅仅是SQL,泛指非关系型数据库。
NoSQL不依赖业务逻辑方式存储,而以简单的key-value模式存储,因此大大增加了数据库的扩展能力。
不遵循SQL标准
不支持ACID
远程SQL的性能
1.2.2NoSQL适用的场景
对数据高并发的读写(秒杀)
海量数据的读写
对数据可扩展性的
1.2.3NoSQL不适用的场景
需要事务支持
基于sql的结构化查询存储,处理复杂的关系,需要即席查询
(用不着sql的和用了sql也不行的情况,考虑用nosql)
1.2.4 Memcache
很早出现的NoSQL数据库
数据都在内存中,一般不持久化,
支持简单的key-value模式,支持类型单一
一般作为缓存数据库的辅助持久化的数据库。
1.2.5 Redis(内存数据库)
几乎覆盖了Memcache的绝大部分功能
数据都在内存中,支持持久化,主要用作备份恢复
除了支持简单的key-value模式,还支持多种数据结构的存储,比如list,set,hash,zset
一般是作为缓存数据库的辅助持久化的数据库
1.2.6 MongoDB
高性能,开源,模式自由的文档型数据库
数据都在内存,如果内存不足,把不常用的数据保存到硬盘
虽然是key-value模式,但是对value(尤其是json)提供了丰富的查询功能
支持二进制数据及大型对象
可以根据数据的特点代替RDBMS,成为独立的数据库,或者配合RDBMS,存储特定的数据。
1.3行式存储数据库(大数据时代)
1.3.1 行式数据库
查找快,统计慢
1.3.2列式数据库
查数据的平均值快,查id=1这条数据慢
1.4图关系数据库
主要应用:社会关系,公共交通,地图,以及网络拓普
2.Redis概述安装
redis基本知识
1)测试redis服务的性能
redis-benchmark
2)查看redis服务是否正常运行
ping 如果正常返回一个----pong
3)查看redis服务器的一些统计信息:
info 查看redis服务的所有统计信息
info [信息段] 查看redis服务器的指定的统计信息, 如:info Replication
4)redis默认的16个库:作用类似于mysql数据实例,redis中的数据库实例只能有redis服务来创建和我维护,开发人员不能修改和自行创建(只能使用),默认情况下redis刚一启动的时候就会创建16个数据库实例,并且给这些数据库实例进行编号,从0开始一直到15,开发人员使用时,通过编号使用数据库;可以通过配置文件来指定redis自动创建的数据库个数;(即使只用了1个库也不会浪费太多存储空间,可以忽略不计)redis每一个数据库实例,本身占用的存储空间是很少的,所以也不会造成存储空间太多浪费。
默认情况下,redis客户端连接的是编号是0的数据库:可以使用select index切换数据库实例
5)切换数据库 select 1切换到数据库1
6)查看当前数据库中key的数目:dbsize
7)查看当前数据库中所有的key:keys *
8)清空数据库所有的数据:flushdb
9)清空所有的数据库实例:flushall
10)查看redis中的所有的配置信息:config get *
查看指定的信息 config get 信息
Redis的5中数据结构
1.支持数据持久化
2.支持多种数据
3.支持数据备份
程序是用来处理数据的,Redis是用来存储数据的,程序处理完的数据要存储到redis数据库,不同特点的数据要存储在redis中不同类型的数据结构中。
java redis
String 字符串 1.string 单key单value:username guojunxu , age 23
list 集合(列表)有序 2.list 单key多value有序:contacts 18180255616 ,1360459926@qq.com
set集合 无序去重 3. set 单key对value无序:
pojo: id:1001,name:gjx,age:23 4. hash 单key:对象(属性:值):
student:id :1001,name:guojunxu,age:23
5.zset 单key:多个有序value:
city:30000 北京,20000 上海,10000 天津,5000 重庆
Redis的常用操作命令
redis有关key的操作命令
keys
keys ***
查看数据库中的key
查找所有符合模式pattern的key, pattern可以使用通配符。
例如keys *所有的key
查看key名字k开头的
keys k*
keys k*o 查看k开头o结尾,中间任意
keys k*o 查看k开头o结尾,中间一个
keys h[abc]llo:查看数据库中所有以h开头llo结尾,并且h后只能取abc中任意一位的key
2)判断key在数据库中是否存在:exists key 如果存在则返回1;如果不存在则返回0;
exists name 判断name是否存在
exists k1 k2 k3返回是数找到的个数
3)移动指定的key到指定的数据库:
move key index
例如move name 2:将key叫name的数据移动到2数据库
4)查看指定key’的剩余生成时间:ttl
ttl key的名称 返回值是-2说明没有这个数据
返回设置是-1说明没有设置生存时间
5)设置key的最大生存时间:expire key 2(2秒)
expire k2 20
6)查看key的数据类型type key名称
7)重命名key rename key newkey
rename name k2
8)删除key
del key
del k1,k2,k3返回值是删除的数量
字符串类型string
1.)存:set key value 2.)取:get key
set name gjx get name
set age 20
set age 30
最后一次会覆盖前一次
3)追加字符串append key
set phone 13
append phone 14 返回追加后字符串的长度,如果key不存在就新建一个key,并且把value值设置为追加的内容
最终为1314
4)获取字符串的长度 strlen
5)(前提存储的这个key的value必须是一个数字)将字符串数值进行加一运算 :incr key(返回加一的值,如果key不存在,会首先设置一个key,值初始化为0,然后进行incr运算最终变为一)
incr age
6)将字符串数值进行减一运算:decr key
decr age((返回加一的值,如果key不存在,会首先设置一个key,值初始化为0,然后进行decr运行最终变为-1)
7)将字符串数值进行加法运算:incrby key 3
incrby age 10(将age加10)返回加10后的数据如果key不存在,会首先设置一个key,值初始化为0,然后进行incrby 10运算最终变为10
8)将字符串数值进行减法运算:decrby key 3
9)获取字符串中的子字符串从startIndx 到endIndx(截取):getrange key startIndx endIndx
name=guojunxu
getrange name 2 3====oj(注意从0开始,所以2对应的是o,3对应的是j)
10)setrange key startIndex value(用value来覆盖从下标为sartIndex开始之后的所以的内容)
setrange name 5 huhuhu
11)设置字符串数据的同时,设置他的最大生命周期:setex key senconds value
setex k1 20 88
12)设置字符串类型的数据,如果已经存在这个key则不设置,就不会覆盖以前的内容(set会覆盖以前的内容)setnx key value
13)批量设置string数据 :mset key1 value key2 value key3 value key4 value
14)批量获取string数据 :mget key1 key2 key3 key4 key5 key6
15)批量设置string类型的数据value到数据库中,当所有key都不存在时设置成功,有一个key存在就失败:msetnx
列表list操作命令
一个key 对应多个value 最左侧是表头,最右侧是表尾,每一个元素都有下标,表头元素下标是0,依次往后排序,最后一个元素下标是列表的长度减一,
每一个元素的下标可以用负数表示,负数下标从表尾计算,最后一个元素下标用-1表示,依次往前。
元素在列表中的顺序(下标)由放入的顺序来决定。
1)将一个或者多个值依次按顺序插入到列表的表头(列表的最左侧):lpush key value1,value2,value3
lpush list1 guojunxu 23 18180255616 1360459926
lpush list2 1 2 3 结果:3 2 1
lpush list2 4 5结果:5 4 3 2 1
2)获取指定列表中的元素:lrange key startIndex endIndex
lrange list1 1 1(23)
lrange list1 1 3(23 18180255616 1360459926)
3)将一个或者多个值依次插入到列表中(表尾右侧):rpush key value
4)从指定列表中移除并且返回表头元素,lpop key
list 1 2 3 4
lpop lsit(结果为 2 3 4)返回1
5)从指定列表中移除表尾元素并且返回表尾元素:rpop key
list 1 2 3 4
rpop list(结果为1 2 3 )返回4
6)获取指定列表中指定下标的元素:lindex key index
list2 =1 2 3
lindex list2 1(结果为2)
7)获取列表的长度:llen key
8)移除指定列表中和value值一样的元素:lrem key count value
·· count>0从表头移除count个和value相等的数据
count《0从列表的表尾移除count个和value相等的数据
count=0移除列表中所有和value值相同的数据
list 1 2 3 4
lrem list 1 1(结果为2 3 4)
9)截取列表中指定下标区间的元素组成新的列表,并且赋值给key:ltrim key startIndex endIndex
list=1 2 3 4
ltrim list 1 3(结果为 2 3 4)
10)将列表中指定的下标元素设置为指定的值:lset key index value
list =1 2 3 4
lset list 1 3(结果为:1 3 3 4)
11)将value插入到列表某一个元素的前/后位置:linsert key before/after 元素 value
list=1 2 3 4
linsert list before 2 x(结果1 x 2 3 4)
linsert list after 2 x(结果1 2 x 3 4)
redis有关set的操作命令
单key多个value无序,一个key对应多个value,value之间没有顺序,并且不能重复;
操作通过业务数据来直接操作集合。
1)将一个或者多个数据添加到集合中:sadd key value1 value2 value3(如果元素有重复的则只插入一条)
sadd set guojunxu 23 18180255616
2)获取指定集合中所有的元素:smembers key
smembers set1
3)判断元素在集合中是否存在:sismember key value
sismember set1 f(存在返回1,不存在返回0)
4)获取集合的长度:scard key
scard set1
5)删除集合中的一个或者多个元素:srem key value1 value2 value3
set1=1 2 3 4
srem set1 1 2(结果3 4 )返回成功移除的个数
6)随机获取集合中的一个元素 :srandmember key 【count】
count》0:从集合中随机获取count个元素(并且count中的元素不能重复)
count《0从集合中随机获取count个元素(可能重复)
srandmember set1
7)随机从集合中移除一个或者多个元素:spop key 【count】
count
spop set1
8)将集合中的元素移动到另一个集合中:smove source dest member
set1=gjx mrr gmm gyy hm
set2=1 2 3 4
smove set1 set2 hm(结果将set1中的hm移动到set2中 set2的数据为1 2 3 4 hm)
9)返回一个集合有其他集合都没有的数据组成的新集合(注意那个都字,如果其他集合中有一个有就不成立):sdiff key key key
set1 1 2 2 3
set2 1 2 2 3 3
set3 9 2 1 3
10)获取所有集合中都有的元素组成的新集合:sinter key key key
set1 1 2 3 4
set2 1 8 7 8
set3 1 9 9 9
11)获取所有集合中所有的元素组成的大集合:sunion key key key
redis中有关hash类型的数据的操作命令
单key:field-value field-value field-value field-value
studentzs:id 1001
name 郭峻旭
age 23
1)将一个或者多个field-valude插入到hash表中:hset key field-valued
(如果存在会把以前的值覆盖掉)
hset hash1 name 郭峻旭 age 23 phone 18180255616 emil 1360459926
2)获取hash表中指定的field的值;hget key field
hget hash1 name
3)批量将多个field-value对设置到hash中:hmset 可以 field-value
hmset key
4)批量获取hash表中的数据:hmget key field
hmget hash1 name age phone
5)获取hash中所有的数据:hgetall key
hgetall key
6)删除hash中一个或者多个值:hdel key field
hdel key name age phone
7)获取hash中数据的个数:hlen key
hlen hash1
8)判断hash中是否存在某个数据:hexists key field
hexists hash1 name
9)获取hash中所有的field列表:hkeys key
hkeys hash1
10)获取hash中所有的value:hvals key
hvals hash
11)对hash中指定的数据进行整数加法运算:hincrby key field int
hincrby hash age 3
12)对hash中指定的数据进行浮点数加法运算:hincrbyfloat key field float
hincrbyfloat hash1 age 3.1
13) 想hash中插入数据(如果已经存在这个field,就不添加):hsetnx key field value
hsetnx hash1 age 30
redis中有关zset类型的操作命令
有序集合,适用的场景(每一个元素都会关联一个数字)
本质上是集合,所以元素不能重复,每一个元素都关联一个分数,redis会根据分数自动排序,分数可以重复,但是元素不能重复。
既然都有序了,那么集合中每个元素就有下标,
有序集合中的元素的排序规则又与列表的排序规则不一样。
1)将一个或者多个元素及其分数值加入到zset中:zadd key 数值 元素
zadd zset1 20 gjx 30 mrr(如果已经存在就将以前的覆盖掉)
2)获取zset中指定下标的下标:zrange key startIndex endINdex(如果结尾加上withscores,可以把分数显示出来)
zrange zset1 0 -1(按分数从小到大排序)
3)获取集合中分数区间的元素:zrangebyscore key min max
zrangebyscore zset1 60 80(找到区间在60到80分的元素,也可以加withscore显示分数)
4)删除一个或者多个数据:zrem key 元素名1 元素名2
zrem zset1 gjx mrr hm
5)获取元素的个数:zcard key
zcard zset1
6)获取集合中元素的排名:zrank key 元素名
zrank zset1 gjx(排序是从0开始的,第一个为0)
7)获取在一个分数区间中元素的个数:zcount key min max
zcount zset1 20 60(20到60)
8)获取集合中指定元素的分数:zscore key 元素
zscore zset1 gjx
9)获取集合中的元素的排名(从大到小的排名):zrevrank key 元素名
zrevrank zset1 gjx
redis配置文件
在redis根目录下提供redis.conf配置文件;可以配置一些redis服务端运行时的一些参数,如果不使用配置文件,redis会按照默认的参数运行,如果使用配置文件,再启动redis服务时必须指定所使用的配置文件
1)redis配置文件中关于网络的配置:
port:指定redis服务使用的端口,默认使用6379
bind:配置客户端连接redis服务时,所能使用的ip地址,默认可以使用redis服务所在主机上任何一个ip都可以;一般情况下,都会配置一个ip,而且通常是一个真实。
如果配置了port和bind ,则客户端连接redis服务时,必须指定端口和ip:
redis-cli -h 192.168.1.1.128 -p 6380
关闭服务:redis-cli -h 192.168.1.1.128 -p shutdown
tcp-keepalive:连接保活策略。
2)redis中常规配置:
loglevel:配置日志级别,开发阶段配置debug,上线阶段配置notice或者warning。
logfile:指定日志文件。redis在运行过程中,会输出一些日志信息,默认情况下,这些日志信息会输出到控制台;我们可以使用logfile配置日志文件,使redis把日志信息输出到指定文件中
databases:配置数据库的数量
databases 18
3)redis安全配置
requirepass:配置redis的访问密码。默认不配置密码,即访问不需要密码验证。此配置需要在protected-mode=yes时起作用,使用密码登录客户端:redis-cli -h ip -p6379 -a pwd(默认不使用)
一旦设置了密码验证,客户端连接redis服务时。必须使用密码连接:redis-cli -h ip -p port -a pwd
Redis持久化
redis是内存数据库,把数据存储到内存,这样在加快读取速度的同时也对数据安全性产生了新的问题,即当redis所在的服务器发生宕机后,redis数据库里的所有数据将全部丢失,为了解决这个问题,redis提供了持久化功能—RDB和AOF(Append Only File)
redis提供持久化策略,在适当的时间采用适当的手段,把内存中的数据持久化到磁盘中,每次redis服务启动时,都可以把磁盘上的数据再次加载到内存中使用。
RDB策略
在指定时间间隔内,redis服务执行指定次数的写操作会自动触发一次持久化操作。
默认一分钟改了1万次会触发一次
或者5分钟10次
或者15分钟内改变了1次
save:配置持久化策略
默认是开启的
dbfilename :redis持久化数据生成的文件名,默认是dump.rdb也可以自己配置
dir:redis持久化生成文件保存的目录,默认是./即redis的启动目录,也可以自己配置
AOF策略
采用操作日志来记录在redis服务器上来进行的每一次写操作。每次redis服务启动时,都会重新执行一遍操作日志中的指令。
默认没有开启(效率低下)
appendonly:配置是否开启AOF,yes开启 no关闭 默认是on
appendfilename:AOF保存文件名(配置操作日志文件)
appendfsync:AOF异步持久化策略
aways:同步持久化,每次发生数据变化立刻写入到磁盘中,性能较差但是数据的完整性比较好,(慢 安全)
everysec:出厂默认推荐,每秒异步记录一次(默认值)
no:不及时同步,由操作系统决定何时同步
no-appendfsync-on-rewrite:重写时是否运用appendsync 默认no 可以保证数据的安全性
auto-aof-rewrite-percentage:设置重写的基准百分比
auto-aof-rewrite-min-size:设置重写的基准值
小结:
根据数据的特点来决定开启那种持久化:
一般情况,开启RDB就足够了。
因为在实际开发中redis中的数据在关系数据库中都存在
Redis的事务简介
什么是事务?
事务:把一组数据库操作放在一起执行,来保证操作的原子性,要么同时成功,要么同时失败。
Redis的事务:允许把一组redis命令放在一起执行,把这些命令进行序列化,(依次执行)然后一起执行,能够保证部分原子性
Redis事务的实现
把命令按照序列压入到一个队列中,当需要执行时,把这个事务执行了,按照压入的顺序依次执行
1)multi:用来标记一个事务开始。
multi
set key value1
set key2 value2
exec
2)exec:用来执行事务中s所有的命令
3)redis的事务只能保证部分原子性:
1.如果一直命令中,有在压入事务队列过程中发生错误命令,本事务中所有的命令都不执行,能够保证事务的原子性
2.如果一组命令在压入队列过程中正常但是在执行事务队列命令时发生错误,则只会影响发生错误的命令,而不会影响其他命令的执行,不能保证事务的原子性。
4)discard:清除所有已经压入队列中的命令,并且结束整个事务。
multi
set k5 v5
set k6 v6
discard
5)watch:监控某一键,当事务在执行过程中,这个键发生了变化,则本事务放弃执行,否则正常执行,同一时间用一个卡在两家店买东西存在的问题为了避免这个事情
set balance 100
set balance2 1000
set version 1
watch version
multi
decrby balance 50
incrby balance 50
exec
6)unwatch:放弃监控某一个键
事务小结:
1.单独的隔离操作,事务中所有的命令都会序列化,顺序的执行。事务在执行过程中,不会被其他客户端发来的命令打断。
2.不保证事务的原子性,redis同一个事务中如果一条命令执行失败,其后的命令仍然可能会执行,redis的事务没有回滚。redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。
Redis消息发布与订阅
解决的问题(redis客户端之间需要进行消息的通信)
redis客户端订阅频道,消息的发布者往频道上发布消息,这样所有订阅此频道的客户端都能接受到此消息。
1)消息的订阅命令:subscribe:订阅一个或者多个频道
subscribe ch1 ch2 ch3
2)发布消息的命令:publish:将消息发布到指定频道
publish ch1 hello
(实际开发用的不多)
3)psubscribe:订阅一个或者多个频道,功能更强大,频道名支持通配符
redis的主从复制:
主机数据更新后根据配置和策略,会自动同步到从机的master/slave,Master以写为主,Slave以读为主。
主少从多,主写从读,读写分离,主写同步到从。
搭建一主二 从redis集群
1)准备三个redis服务,一个作主库,二个作为从库:
提供三份redis配置文件:redis6379.conf redis6380.conf redis6381.conf
修改三份配置文件:
port 6379
pidfile /var/run/redis_6379.pid
logfile “6379.log”
dbfilename dump6379.rdb
分别使用三个redis配置文件,启动三个redis服务:
redis-server redis6379.conf &
redis-server redis6380.conf &
redis-server redis6381.conf &
2)通过redis客户端分别连接三台redis服务
redis -cli -h 127.0.0.1 -p 6379
redis -cli -h 127.0.0.1 -p 6380
redis -cli -h 127.0.0.1 -p 6381
3)查看三台服务redis服务在集群中的主从角色
info replication
默认情况下所有的redis服务都是主机,都能够写和读,但是都没有从机(现在还不是集群)
4)先往6379进行写操作,看会不会影响其他的服务
现在三台redis服务互相独立,互不影响
5)设置主从关系:
6379当主句 6380 6381 当从机
6379不动因为他现在就是主机,我们只需要修改6380 6381(设从不设主)
在6380执行:slaveof 127.0.0.1 6379(设置127.0.0.1上的6379的从机)
同理在6381上执行slaveof 127.0.0.1 6379(设置127.0.0.1上的6379的从机)
6)全量复制:一旦主从关系确定,会自动把主机上已有的数据同步复制到从机上。
在6380 和6381上执行 keys * 就能看到在6379上插入的数据
7)增量复制:往6379上添加数据(主机上写的数据会自动同步到从库中)
set k2 v2
6380 和6381上也有了
8)主写从读,读写分离在6380和6381上执行
set k3 v3(会报错,因为是从机只能读不能写)
9)主机宕机,从机原地待命(模拟关闭6379 redis-cli -h 127.0.0.1 -p 6379 shutdown)
查看6380和6381的服务的主从角色:info replication
6380 和 6381 角色还是从机但是此时连接状态是关闭的
主机宕机,从机原地待命
10)主机恢复:一切恢复正常(模拟:重启6379 redis-server redis6379.conf & 客户端连接redis-cli -h 127.0.0.1 -p 6379)
11)从机宕机,主机从机少一个,其他从机不变
12)从机恢复,从机变成主机(投胎重做人),必须从新设置为从机
13)从机上位:
1.主机宕机:从机原地待命(主机修好了)
2.让6380上位:从机断开原来的主从关系:6380上执行 slaveof no one
3.从新设置主从关系,在6381上 slaveof 127.0.0.1 6380
4.以前的主机修好了,现在变成孤家寡人
现在让6379变成6381的从机
总结:一台主机配多台从机 ,一台从机又可以配置对台从机,从而形成一个庞大的集群架构,这种集群主要是减轻一台主机的压力,但是他增加了服务间的延迟时间
Redis哨兵模式
主机宕机,从机上位的自动版。
准备三个redis服务,一个作主库,二个作为从库:
分别使用三个redis配置文件,启动三个redis服务:
redis-server redis6379.conf &
redis-server redis6380.conf &
redis-server redis6381.conf &
2)提供一个哨兵配置文件:
在redis安装目录下创建配置文件:redis_sentinel.conf
内容:sentinel monitor dc-redis 127.0.0.1 6379 1
表示:指定监控主机的ip地址,port端口号,得到哨兵的票数(当哨兵投票数大于或者等于此数时切换主从关系)
3)启动哨兵:redis-sentinel redis_sentinel.conf
4)主机宕机:
哨兵程序自动选择从机上位
5)原来主机恢复了: 自动从属新的主机
小结:
主从复制原则:开始是全量复制,之后是增量复制,
哨兵的三大任务:监控,提醒,自动故障迁移
缺点:redis的主从复制的最大缺点就是延迟,,主机复制写,从机负责备份,这个过程有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,从机器的数量增加也会使这个问题更加严重。
Jedis操作Redis
使用Redis官方推荐的Jedis,在java应用中操作Redis。Jedis几乎涵盖了Redis的所有命令,操作Redis的命令在Jedis中一方法的形式出现。
Redis