特点:
1 全部使用SQL(结构化查询语句)进行数据操作
2 都存在主外键关系,表 等等关系特征
3 大部分都支持各种关系型数据库的特性:事务、存储过程、触发器、视图、临时表、模式、函数
典型:Redis、MongoDB、hbase、 Hadoop、elasticsearch、图数据库(Neo4j、GraphDB、SequoiaDB)
特点:
每一款都不一样。用途不一致,功能不一致,各有各的操作方式。
基本不支持主外键关系,也没有事务的概念。(MongoDB号称最接近关系型数据库的,所以MongoDB有这些)
Redis (Remote Dictionary Server 远程字典服务)
memcache 缺点:值为字符串 不能持久化
从数据库拿数据,涉及IO操作。影响性能。
机械硬盘和内存性能差100倍
内容网站,
不需要读写数据库,放入内存中。
数据库更多的起到备份的功能。
还需要涉及如何同步问题。
速度快
持久化
多种数据结构
支持多种编程语言:CS架构
功能丰富
简单: 代码短小精悍
主从赋值
高可用、分布式
本质如何访问mysqld的?
Mysql提供对外的接口,本质上基于socket的基础上实现。
先接受参数,验证通过了,才执行指令
存储数据结构不同
表存储
k:value存储
队列存储
Python作为生产者 生产数据, go作为消费者 消费数据
C:\Users\zhu>redis-cli
127.0.0.1:6379> set name user1
OK
127.0.0.1:6379> get name
"user1"
127.0.0.1:6379>
value类型 key:value
String //字符串
hash类型 {“”:””,} //类似字典
list类型 [] //列表
set类型{1,2,3} //集合 无序,去重
zset {1,2,3} //有序集合
d={“k1”:{}}
Redis大的字段
Redis= {
“”:””,
“”:[],
“”:{},
“”:{}
}
Python 值可以任意类型,键 可hash
Redis 键是字符串,根据值不同,相关方法
redis就是一个全局的大字典,key就是数据的唯一标识符。根据key对应的值不同,可以划分成5个基本数据类型。 1. string类型: 字符串类型,是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,也就是byte类型。 单个数据的最大容量是512M。 key: 值 2. hash类型: 哈希类型,用于存储对象/字典,对象/字典的结构为键值对。key、域、值的类型都为string。 key:{ 域(属性): 值, 域:值, 域:值, 域:值, ... } 3. list类型:(存值,有顺序) 列表类型,它的子成员类型为string。 key: [值1,值2, 值3.....] 4. set类型:(存值,无序,不重复) 无序集合,它的子成员类型为string类型,元素唯一不重复,没有修改操作。 key: {值1, 值4, 值3, ...., 值5} 5. zset类型(sortedSet): (存值 有权重 值有顺序) 有序集合,它的子成员值的类型为string类型,元素唯一不重复,没有修改操作。权重值(score,分数)从小到大排列。 key: { 值1 权重值1(数字); 值2 权重值2; 值3 权重值3; 值4 权重值4; } |
127.0.0.1:6379> set name user1
127.0.0.1:6379> get name
127.0.0.1:6379> keys *
127.0.0.1:6379> scan 0
set 默认覆盖的效果
127.0.0.1:6379> del name1
127.0.0.1:6379> setnx name1 user1
127.0.0.1:6379> get name1
键不存在,执行成功,返回integer 1
127.0.0.1:6379> setnx age 22
127.0.0.1:6379> get age
127.0.0.1:6379> setex gender 10 male
127.0.0.1:6379> get gender
过了10秒,再查看已过期
# 1 redis值为string的操作方法
set key value 设置键值
get key 获取某键的值
setnx key value # 当键存在则无效
setex key seconds value # 设置有效时间的键值对
127.0.0.1:6379> mset height 170 weight 60kg
127.0.0.1:6379> get height
127.0.0.1:6379> mget height weight
127.0.0.1:6379> mset a1 golang a2 java a3 c
返回总长度
127.0.0.1:6379> set article my
OK
127.0.0.1:6379> get article
my
127.0.0.1:6379> append article redis
7
127.0.0.1:6379> get article
myredis
127.0.0.1:6379> append article start
12
127.0.0.1:6379> get article
myredisstart
127.0.0.1:6379> mget name age
# 1 redis值为string的操作方法
set key value 设置键值
get key 获取某键的值
setnx key value # 当键存在则无效
setex key seconds value # 设置有效时间的键值对
mset height 70 weight 60kg # 设置多个键值
mget name age # 获取多个键的值
应用场景:电商抢购,秒杀,投票,攻击计数,在线人数等
存储的字符串? 如何自增
127.0.0.1:6379> set goods_count 100
127.0.0.1:6379> get goods_count
存储必须为数值类型的字符串
127.0.0.1:6379> incr goods_count
127.0.0.1:6379> incrby goods_count 5
127.0.0.1:6379> decr goods_count
127.0.0.1:6379> decrby goods_count 5
127.0.0.1:6379> get name
user1
127.0.0.1:6379> strlen name
var x int8 1B字节=8比特bit
注意:一般说的1kb是1024字节
1个in8: 1个字节, 存2的8次方 256个值
1个中文:3个字节
SETBIT # 设置一个bit数据的值 GETBIT # 获取一个bit数据的值 BITCOUNT # 统计字符串被设置为1的bit数. BITPOS # 返回字符串里面第一个被设置为1或者0的bit位。 |
127.0.0.1:6379> setbit mykey 7 1
127.0.0.1:6379> getbit mykey 7
127.0.0.1:6379> getbit mykey 6
应用案例
考勤 1出勤 0 未出勤
127.0.0.1:6379> bitcount mykey
第一次执行返回0,再次执行返回1
127.0.0.1:6379> setbit mykey 7 1
第一次设置为1或者0的比特位
127.0.0.1:6379> bitpos mykey 1
统计每个人的信息
不放到最外层,放到hash里边
redis = {
"user_1":"",
"":[],
"login":{
"user_1":""
},
"":""
}
自增自减练习
127.0.0.1:6379> set goods_count 100
127.0.0.1:6379> get goods_count
127.0.0.1:6379> incr goods_count
127.0.0.1:6379> decr goods_count
127.0.0.1:6379> keys *
127.0.0.1:6379> keys a*
127.0.0.1:6379> keys *a
127.0.0.1:6379> exists name
1
127.0.0.1:6379> exists names
0
127.0.0.1:6379> type name
string
127.0.0.1:6379> del weight height
# 给已经存在的某个键设置一个过期时间
127.0.0.1:6379> expire key seconds
127.0.0.1:6379> get name
127.0.0.1:6379> expire name 10
127.0.0.1:6379> get name
不存在的键,用ttl也会返回-2
127.0.0.1:6379> ttl name
以下命令无效
127.0.0.1:6379> expire a* 3
0
127.0.0.1:6379> flushall
127.0.0.1:6379> set name user1
OK
127.0.0.1:6379> rename name u1
OK
127.0.0.1:6379> get name
127.0.0.1:6379> get u1
user1
# 2 key操作:与键的值得数据内容无关
# 获取redis下所有的键
key *
# 判断某个key是否存在,存在返回1 不存在返回0
exists name
# 获取键的值得数据类型
type key
# 删除某个或某些键值对
del key1 key2
# 给已经存在的魔鬼键设置一个过期时间
expire key seconds
# 某个key剩余的有效期
ttl key
flushall # 清空redis的所有的key
rename oldkey newkey # 重命名
127.0.0.1:6379> select 1
键key:{
域field: 值value,
域field: 值value,
域field: 值value,
}
hset key field value
127.0.0.1:6379> hset info name user1
127.0.0.1:6379> hget info name
127.0.0.1:6379> hset info age 22
127.0.0.1:6379> hget info
ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hgetall info
name
user1
age
22
redis = {
"info":{
"name":"user1",
"age":"22"
}
}
127.0.0.1:6379> hmset info2 name user age 24
127.0.0.1:6379> hgetall info2
127.0.0.1:6379> hset info3 name user3 age 22
2
127.0.0.1:6379> hgetall info3
name
user3
age
22
127.0.0.1:6379> hkeys info3
name
age
127.0.0.1:6379> hvals info3
user3
22
用:下划线 都行
127.0.0.1:6379> hset user:1 name zhansan
1
127.0.0.1:6379> hgetall user:1
name
zhansan
127.0.0.1:6379> hgetall info3
name
user3
age
22
127.0.0.1:6379> hdel info3 age
1
127.0.0.1:6379> hgetall info3
name
user3
Exists
存在返回1 不存在返回0
127.0.0.1:6379> exists info3
1
127.0.0.1:6379> hexists info3
ERR wrong number of arguments for 'hexists' command
127.0.0.1:6379> hexists info3 name
1
127.0.0.1:6379> hgetall info2
name
user
age
24
127.0.0.1:6379> hincrby info2 age 2
127.0.0.1:6379> hincrby info2 age -2
127.0.0.1:6379> hset info3 age 18
1
127.0.0.1:6379> get info3
WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> hget info3 age
18
127.0.0.1:6379> hgetall info3
name
user3
age
18
127.0.0.1:6379> lpush names1 zhangsan lisi wangwu
3
127.0.0.1:6379> rpush names2 zhangsan lisi wangwu
3
127.0.0.1:6379> lrange names1 0 -1
127.0.0.1:6379> lrange names2 0 -1
127.0.0.1:6379> flushall
127.0.0.1:6379> rpush brother liu guan zhang
3
127.0.0.1:6379> lrange brother 0 -1
liu
guan
zhang
向指定位置插入指定值
127.0.0.1:6379> linsert brother after guan lvbu
4
127.0.0.1:6379> lrange brother 0 -1
liu
guan
lvbu
zhang
127.0.0.1:6379> lset brother 2 machao
OK
127.0.0.1:6379> lrange brother 0 -1
liu
guan
machao
zhang
删除指定成员
lrem key count value
# 注意: # count表示删除的数量,value表示要删除的成员。该命令默认表示将列表从左侧前count个value的元素移除 # count==0,表示删除列表所有值为value的成员 # count >0,表示删除列表左侧开始的前count个value成员 # count <0,表示删除列表右侧开始的前count个value成员 |
127.0.0.1:6379> lrange brother 0 -1
liu
guan
machao
zhang
user1
guanyu
user1
guanyu
user1
guanyu
127.0.0.1:6379> lrem brother -2 user1
2
127.0.0.1:6379> lrange brother 0 -1
liu
guan
machao
zhang
user1
guanyu
guanyu
guanyu
127.0.0.1:6379> del brother 1 127.0.0.1:6379> rpush brother A B A C A 5 127.0.0.1:6379> lrem brother 0 A 3 127.0.0.1:6379> lrange brother 0 -1 B C |
删右侧两个A 127.0.0.1:6379> del brother 1 127.0.0.1:6379> rpush brother A B A C A 5 127.0.0.1:6379> lrem brother -2 A 2 127.0.0.1:6379> lrange brother 0 -1 A B C |
删左侧两个A 127.0.0.1:6379> del brother 1 127.0.0.1:6379> rpush brother A B A C A 5 127.0.0.1:6379> lrem brother 2 A 2 127.0.0.1:6379> lrange brother 0 -1 B C A |
127.0.0.1:6379> del brother 1 127.0.0.1:6379> rpush brother liu guan zhang liu guan zhang 6 127.0.0.1:6379> lrange brother 0 -1 liu guan zhang liu guan zhang 127.0.0.1:6379> lindex brother 3 liu 127.0.0.1:6379> lindex brother 2 zhang |
redis = {
"names":["","",""]
}
lpush key value1 value2 ...
rpush key value1 value2 ...
lrange key 0 -1 # 支持正负索引
# 向指定位置插入某个值
linsert key after|before 标杆值 插入值
# 根据索引设置值
lset brother 2 machao
# 根据内容删除list中元素
lrem brother -2 guanyu
# 通过索引查找list中元素
lindex brother 3
# 通过索引范围查找多个元素值
lrange key start stop
移除并获取 获取:做返回值
remove一般按值删
pop一般按索引删
127.0.0.1:6379> lpop brother
127.0.0.1:6379> rpop brother
llen key
配套使用
lrange 查
linx
lrem 删
lset 改
127.0.0.1:6379> hset info1 name user1
(integer) 1
127.0.0.1:6379> hset info1 age 18
(integer) 1
127.0.0.1:6379> hget info1 name
"user1"
127.0.0.1:6379> hget info1 age
"18"
127.0.0.1:6379> hgetall info1
1) "name"
2) "user1"
3) "age"
4) "18"
127.0.0.1:6379> hmset info1 name:2 user2 age:2 18
OK
127.0.0.1:6379> hmset info1 name:3 user3 age:3 15
OK
127.0.0.1:6379> hset info1 name:4 user4 age:4 25
(integer) 2
127.0.0.1:6379> hkeys info1
1) "name"
2) "age"
3) "name:2"
4) "age:2"
5) "name:3"
6) "age:3"
7) "name:4"
8) "age:4"
127.0.0.1:6379> hvals info1
1) "user1"
2) "18"
3) "user2"
4) "18"
5) "user3"
6) "15"
7) "user4"
8) "25"
127.0.0.1:6379> sadd snames liubei guanyu zhangfei
127.0.0.1:6379> smembers snames
127.0.0.1:6379> scard snames
127.0.0.1:6379> spop snames
127.0.0.1:6379> sadd snames liubei guanyu zhangfei (integer) 3 127.0.0.1:6379> scard snames (integer) 3 127.0.0.1:6379> srem snames guanyu (integer) 1 127.0.0.1:6379> smembers snames 1) "liubei" 2) "zhangfei" |
C:\Users\zhu>redis-cli --raw 127.0.0.1:6379> sadd snames liubei guanyu zhangfei 1 127.0.0.1:6379> scard snames 3 127.0.0.1:6379> srem snames guanyu 1 127.0.0.1:6379> smembers snames liubei zhangfei |
应用场景:推荐 协同过滤,基于用户,基于物品
sinter key1 key2 key3 .... # 交集、比较多个集合中共同存在的成员 sdiff key1 key2 key3 .... # 差集、比较多个集合中不同的成员 sunion key1 key2 key3 .... # 并集、合并所有集合的成员,并去重 |
del user:1 user:2 user:3 user:4
sadd user:1 1 2 3 4 # user:1 = {1,2,3,4}
sadd user:2 1 3 4 5 # user:2 = {1,3,4,5}
sadd user:3 1 3 5 6 # user:3 = {1,3,5,6}
sadd user:4 2 3 4 # user:4 = {2,3,4}
# 交集
127.0.0.1:6379> sinter user:1 user:2
1) "1"
2) "3"
3) "4"
127.0.0.1:6379> sinter user:1 user:3
1) "1"
2) "3"
del user:1 user:2 user:3 user:4
sadd user:1 1 2 3 4 # user:1 = {1,2,3,4}
sadd user:2 1 3 4 5 # user:2 = {1,3,4,5}
sadd user:3 1 3 5 6 # user:3 = {1,3,5,6}
sadd user:4 2 3 4 # user:4 = {2,3,4}
# 并集
127.0.0.1:6379> sunion user:1 user:2 user:4
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
del user:1 user:2 user:3 user:4
sadd user:1 1 2 3 4 # user:1 = {1,2,3,4}
sadd user:2 1 3 4 5 # user:2 = {1,3,4,5}
sadd user:3 1 3 5 6 # user:3 = {1,3,5,6}
sadd user:4 2 3 4 # user:4 = {2,3,4}
# 差集
127.0.0.1:6379> sdiff user:1 user:3
1) "2"
2) "4"
127.0.0.1:6379> sdiff user:2 user:3
1) "4"
127.0.0.1:6379> sdiff user:3 user:2
1) "6"
127.0.0.1:6379> sadd snames liubei guanyu zhangfei
(integer) 3
127.0.0.1:6379> smembers snames
1) "liubei"
2) "guanyu"
3) "zhangfei"
127.0.0.1:6379> scard snames
(integer) 3
127.0.0.1:6379> spop snames
"guanyu"
127.0.0.1:6379> srem snames liubei
(integer) 1
127.0.0.1:6379> smembers snames
1) "zhangfei"
redis值为zset的操作方法
sadd key val1 val2 ...
127.0.0.1:6379> zadd achievements 61 xiaoming 62 xiaohong 83 xiaobai 78 xiaohei 87 xiaohui 99 xiaolan
zincrby key score member
127.0.0.1:6379> zincrby achievements 100 xiaoming
127.0.0.1:6379> zcard achievements
127.0.0.1:6379> zscore achievements xiaoming
zrank key member
127.0.0.1:6379> zcard achievements
6
# score 从小到大的排名
127.0.0.1:6379> zrank achievements xiaoming
5
# score 从大到小的排名
127.0.0.1:6379> zrevrank achievements xiaoming
zcount key min max
127.0.0.1:6379> zcount achievements 0 70
127.0.0.1:6379> zrangebyscore achievements 60 70
127.0.0.1:6379> zrange achievements 0 -1
zrem key member1 memeber2 memer3 ...
127.0.0.1:6379> zrem achievements xiaoming
127.0.0.1:6379> zpopmin achievements 2
# 删除指定数量的成员,从最低score开始删除
zpopmin key [count]
# 删除指定数量的成员,从最高score开始删除
zpopmax key [count]
使用场景如下: 字符串string: 用于保存一些项目中的普通数据,只要键值对的都可以保存 例如,保存 session/jwt,定时记录状态,倒计时、验证码、防灌水答案 哈希hash:用于保存项目中的一些结构体/map类型数据,但是不能保存多维结构 例如,商城的购物车,文章信息,json结构数据 列表list:用于保存项目中的列表/切片数据,但是也不能保存多维结构 例如,消息队列,秒杀系统,排队, 无序集合set: 用于保存项目中的一些不能重复的数据,可以用于过滤 例如,候选人名单, 作者名单, 有序集合zset:用于保存项目中一些不能重复,但是需要进行排序的数据 例如:分数排行榜, 海选人排行榜,热搜排行, |
数据缓存、
分布式数据共享、
分布式锁、
计数器、
限流、
位统计(用户打卡、签到)、
购物车、
消息队列、
抽奖奖品池、
排行榜单(搜索排名)、
推荐、用户关系记录[收藏、点赞、关注、好友、拉黑]
开放封闭原则
redis: 消息队列(发布订阅)
订阅 subscribe
发布 publish
C:\Users\zhu>redis-cli
127.0.0.1:6379> subscribe msg
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg"
3) (integer) 1
再开消费者
C:\Users\zhu>redis-cli
127.0.0.1:6379> subscribe msg
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "msg"
3) (integer) 1
127.0.0.1:6379> publish msg hellmsg
(integer) 2
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
conn,err:=redis.Dial(
"tcp",
"127.0.0.1:6379",
redis.DialPassword(""),
redis.DialDatabase(0),
)
if err!=nil{
fmt.Println("conn redis error:",err)
return
}
fmt.Println(conn)
defer conn.Close()
}
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main(){
conn,err:=redis.Dial("tcp","127.0.0.1:6379")
if err!=nil{
fmt.Println("connect redis error:",err)
return
}
defer conn.Close()
// 创建hash
_,err=conn.Do("HSET","student1","username","xiaoming","age",18)
if err!=nil{
fmt.Println("redis mset error:",err)
}
//获取全部键值对
res,err:=redis.StringMap(conn.Do("HGETALL","student1"))
if err!=nil{
fmt.Println("redis HGETALL err:",err)
}else{
fmt.Printf("res=%v \n",res)
for i,v := range res{
fmt.Println(i,v)
}
}
// 提取成员
age,err:=redis.Int64(conn.Do("HGET","student1","age"))
if err!=nil{
fmt.Println("redis HGET err:",err)
}else{
fmt.Printf("age=%v\n",age)
}
}
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
"reflect"
)
func main() {
conn,err:=redis.Dial("tcp","127.0.0.1:6379")
if err!=nil{
fmt.Println("conn redis error:",err)
return
}
defer conn.Close()
// 创建列表
_,err=conn.Do("RPUSH","brother","liubei","guanyu","zhangfei")
if err!=nil{
fmt.Printf("redis rpush err:",err)
}
//末位列出
item, err := redis.String(conn.Do("RPOP", "brother"))
if err != nil {
fmt.Println("redis POP error:", err)
} else {
res_type := reflect.TypeOf(item)
fmt.Printf("res[%s]: %s \n", res_type, item)
}
// 获取列表
res,err:=redis.ByteSlices(conn.Do("LRANGE","brother",0,-1))
if err != nil {
fmt.Printf("redis pop error:",err)
}else{
fmt.Printf("%s\n",res)
}
}