redis是一个高性能的key-value数据库,也是NOSQL数据库,是为了解决高并发,高扩展,大数据存储等问题而产生的数据库解决方案,是一个非关系型数据库,并且Redis是基于内存的单线程数据库(6.0之后支持多线程)。
1.NoSql优点
2.主要的NoSql数据库分类
分类
|
数据库
|
应用场景
|
数据类型
|
优点
|
缺点
|
键值
(key-value)
|
Redis,Tokyo,
Oracle BDB
|
内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统
|
Kye指向Value的键值对,通常用hash table来实现
|
查询速度快
|
数据无结构化,通常只被当作字符串或二进制数据
|
列表存储
|
Cassandra,HBase,Riak
|
分布式文件系统
|
以列簇式存储,将同一列数据存在一起
|
查询速度快,可扩展性强,更容易进行分布式扩展
|
功能相对局限
|
文档型数据库
|
CouchDB,
MongoDB
|
web应用(与key-value类似,value是结构化的不同的是数据库可以了解value的内容)
|
key-value对应的键值对,Value为结构化数据
|
数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构
|
查询性能不高,而且缺乏统一性的查询语法
|
图形数据库
|
Neo4J,InfoGrid,Infinite Graph
|
社交网络,推荐系统等。专注于构件关系图谱
|
图结构
|
利用图结构相关算法,比如最短路径寻址,N度关系查找等
|
很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案
|
MongoDB:
MongoDB数据库是一个基于分布式文件存储的数据库,C++编写,主要来处理大量的文档,MongoDB是一个介于关系型数据库和非关系型数据库中间的产品,MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的
图形数据库保存的是这种关系:
3.Redis特点
4.redis性能测试
压力测试命令(在bin下执行):
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 1000
5 基础命令 :
涵义
|
命令
|
注释
|
windows连接redis
|
redis-cli -h 127.0.0.1 -p 6379
|
在bin目录运行
|
linux连接redis
|
redis-cli -p 6397
|
|
得到redis安装目录
|
config get dir
|
|
切换数据库
|
select 1
|
redis默认有16个数据库,默认使用第0个
|
查询数据库大小
|
dbsize
|
|
查询所有的key
|
keys *
|
|
清空数据库
|
flushall
|
|
清空当前数据库
|
flushdb
|
|
设置键值
|
set key value
|
|
得到值
|
get key
|
|
删除key
|
del key
|
|
移除key
|
move key 数据库编号
|
|
判断key是否存在
|
exists key
|
|
设置过期时间
|
expire key 时间
|
时间单位为秒
|
查询剩余时间
|
ttl key
|
|
查询key类型
|
type key
|
|
获取配置信息
|
CONFIG GET *
|
也可以使用 CONFIG GET "配置名" 得到配置信息
|
修改配置信息
|
CONFIG SET 配置名 “值”
|
6.redis数据类型及窗口命令 :
涵义
|
命令
|
注释
|
设置键值
|
setnx key val
|
当key存在不做任何操作
|
批量设置键值
|
mset key1 val1 key2 val2
|
|
批量获取值
|
mget key1 key2
|
这个操作是一个原子性操作,要么一起成功要么一起失败
|
组合getset
|
getset key val
|
key不存在创建,key存在覆盖原来的
|
追加内容
|
append key val
|
如果当前key不存在,执行新增操作
|
获取值长度
|
strLen key
|
|
根据key加一
|
incr key
|
|
根据key减一
|
decr key
|
|
根据key增加指定值
|
incrby key 10
|
|
根据key减少指定值
|
decryby key 10
|
|
字符串截取
|
getrange key 开始位置 结束位置
|
下标从0开始,结束位置-1为最后
|
替换字符串
|
setrange key 替换的位置 替换的值
|
原字符串:aabbcc 从1替换值 xx
结果: axxbcc
|
设置key及过期时间
|
setex key 过期时间 值
|
//设置值 mset user:name 张三 user:age 18 //获取值 mget user:name user:age //得到结果: 张三 18 这个样设置key向设置对象一样,方便查询和管理
涵义
|
命令
|
注释
|
添加
|
Hset key key val
|
|
获取
|
Hget key key
|
|
添加多个
|
Hmset key key val key2 val2
|
|
获取所有的值
|
Hgetall key
|
|
获取长度
|
Hlen key
|
|
判断key是否存在
|
Hexists key key
|
|
获取所有的key
|
Hkeys key
|
|
获取所有的val
|
Hvals key
|
涵义
|
命令
|
注释
|
首部添加值
|
Lpush key val
|
例子:Lpush a one
Lpush a two
|
尾部添加值
|
Rpush key val
|
|
获取
|
Lrange key 开始下标 结束下标
|
下标从0开始,结束位置为-1拿全部,先入后出
|
删除数据
|
Lpop key 删除左边第一个
Rpop key 删除右边第一个
|
|
根据下标获取值
|
Lindex key 下标
|
|
获取列表长度
|
Llen key
|
|
移除指定值
|
Lrem key 移除个数 值
|
因为list是可重复的
|
截取指定范围内的值
|
Ltrim key 前下标 后下标
|
截取后list只剩那几个值了
|
移除列表最后一个元素,移动到新列表中
|
RpopLpush key1 key2
|
将key1的最后一个值移动到key2n内
|
替换值
|
Lset key 位置 替换的值
|
位置不存在会报错
|
在指定位置插入
|
Linsert key 位置 原值 插入值
|
原值是在哪插
|
Jedis jedis = new Jedis("127.0.0.1",6379); jedis.lpush("a","值1","值2","值3"); List<String> a = jedis.lrange("a", 0, -1); for (String s:a){ System.out.println(s); } System.out.println("插入"); //在指定的位置插入 jedis.linsert("a", ListPosition.BEFORE,"值2","值5"); List<String> b = jedis.lrange("a", 0, -1); for (String s:b){ System.out.println(s); }
List小结:
list实际上是一个链表,before Node after(前后) ,left , right 都可以插入
如果key不存在,创建新的链表
如果key存在,新增内容
如果移除了所有的值,空链表,也代表不存在
4.set(集合)
涵义
|
命令
|
注释
|
添加
|
Sadd key val
|
|
查询
|
Smembers key
|
|
判断值是否存在
|
Sismember key val
|
|
获取set大小
|
Scard key
|
|
删除值
|
Srem key val
|
|
随机获取值
|
Srandmember key
|
|
获取指定数量的随机值
|
Srandmember key 数量
|
|
删除随机的key
|
Spop key
|
|
将一个指定的值移动到另一个集合
|
Smove 原key 目标key 移动val
|
|
获取差集
|
Sdiff key1 key2
|
|
获取交集
|
Sinter key1 key2
|
|
获取并集
|
Sunlon key1 key2
|
5.zset(有序集合):
zset是在set的基础上增加了一个排序值,zset k1 排序值 v1
涵义
|
命令
|
注释
|
新增
|
Zadd key 排序 val
|
|
排序从小到大
|
ZrangeBySecore key -inf +inf
|
-inf负无穷,+正无穷
|
排序从大到小
|
Zrevrange key 0 -1
|
|
查询
|
Zrange key
|
|
移除
|
Zrem key val
|
|
获取集合长度
|
Zcard key
|
|
获取指定区间的数量
|
Zcount key 1 3
|
6.geospatial(地理位置):
可以推算地理位置信息,两地之间的距离,方圆几里的人
涵义
|
命令
|
注释
|
添加位置
|
Geoadd key 经度 纬度 城市名称 经度 纬度 城市名称
|
两极无法添加
|
获取指定城市经纬度
|
Geopos key 城市名
|
|
获取两点之间直线距离
|
Geodist key 城市1 城市2 距离单位
|
距离单位:
m : 米
km : 千米
mi : 英里
ft: 英尺
|
获取附近位置
|
Georadius key 经度 纬度 半径 距离单位
|
|
获取指定个数的数据
|
Geradius key 经度 纬度 半径 距离单位 withdist withcoord count 数量
|
例子:
Ceoradius key 100 30 200 km withdist withcoord count 2
|
找出指定位置的数据
|
GeoradiusByMember key 城市名 半径 距离单位
|
|
根据key和城市名获取kash值
|
geohash key 城市名 城市名
|
将二维的经纬度转换为一维的字符串,如果两个字符串越近那么距离越近
|
Geo底层实现原理为zset可以使用zset命令操作Geo的值
7.HyperLogLog:
基数不重复的元素
涵义
|
命令
|
注释
|
新增
|
PFadd key val
|
|
统计(忽略重复数据)
|
PFcount key
|
|
合并
|
PFmerge 新key 被合并key1 被合并key2
|
问题:
一个人访问一个网站多次但是还是算一个人
传统解决:
set集合保存用户id,然后就可以统计set中的元素数量来做判断,但是这个方式如果保存大量的用户id会比较麻烦
用HyperLogLog解决:
优点:
占用的内存是固定的,2^64不同的元素技术,只需要用12kb的内存
缺点:
有0.81%的错误率
8.BitMaps(位存储):
BitMaps位图数据结构,都是操作二进制位来进行记录,就只有0和1两个状态
涵义
|
命令
|
注释
|
添加
|
setbit key 位 值
|
例子:
setbit key 1 a
|
获取值
|
setbit key 位
|
|
统计
|
bitcount key
|
7.redis事务 :
multi
set key val
set key1 val2
get key
exec
执行后会输出结果
取消事务:discard
multi
set key val
set key1 val2
get key
discard
事务队列内的东西都不会执行
当redis内有编译异常时所有操作都不会成功,但是当有运行时异常只有报异常的那个命令不会成功
监控:
悲观锁:
很悲观,感觉什么时候都会出问题,无论做什么都会加锁
乐观锁:
很乐观,感觉什么时候都不会出问题,无论什么时候都不加锁。
更新的时候去判断一下在此期间是否有人修改过这条数据。
加锁:watch key
set qian 100 用户一: watch qian mulit set qian 200 //在这个时候用户二先执行了 exec 执行事务;这个时候会执行失败,因为乐观锁会去对比版本号,版本号对应不上所以执行失败,执行失败后乐观锁会自动解锁 用户二; set qian 10
解锁:unwatch
8.Jedis :
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
2.事务操作
Jedis jedis = new Jedis("127.0.0.1",6379); Transaction multi = jedis.multi(); multi.set("测试的值","测试的值"); multi.exec();
其他的操作和命令是一样的
9.SpringBoot整合Redis:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2.application配置
spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.database=0
3.注入redisTemplate
@Autowired private ReisTemplate redisTemplate; //操作不同的数据类型: //操作字符串:redisTemplate.opsForValue() //操作list:redisTemplate.opsForList() //操作set:redisTemplate.opsForSet() //操作Hash:redisTemplate.opsForHash() //操作ZSet:redisTemplate.opsForZSet() //操作Geo:redisTemplate.opsForGeo() //操作HyperLogLog:redisTemplate.opsForHyperLogLog() //获取redis连接对象: RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); //清除数据库内容 connection.flushDb();
4.解决redis中文乱码问题
![](https://img2020.cnblogs.com/blog/1534700/202101/1534700-20210118105238830-755737201.png)
![](https://img2020.cnblogs.com/blog/1534700/202101/1534700-20210118103355073-1601122320.png)
@Configuration public class RedisConfig { @Bean public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> template = new RedisTemplate<>(); //配置参数序列化方式 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); //对json进行转译 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL) jackson2JsonRedisSerializer.setObjectMapper(om); template.setKeySerializer(jackson2JsonRedisSerializer); //String序列化 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); //设置key采用String方式序列化 template.setKeySerializer(stringRedisSerializer); //设置hash的key采用String方式序列化 template.setHashKeySerializer(stringRedisSerializer); //设置value采用json序列化 template.setValueSerializer(jackson2JsonRedisSerializer); //设置hash的val采用json序列化 template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); //设置连接工厂 template.setConnectionFactory(redisConnectionFactory); return template; } }