Redis是什么
Redis 是一个高性能的开源的、C语言写的Nosql(非关系型数据库),数据保存在内存中(快,容易丢失)。
Redis 是以key-value形式存储的Nosql,和传统的关系型数据库不一样。不一定遵循传统数据库的一些基本要求,比如说,不遵循sql标准,事务,表结构等等,非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
特点(优势)
1.数据保存在内存,存取速度快,并发能力强
2.它支持存储的value类型相对memcached更多,包括string(字符串)、list(链表)、set(集合)、 zset(sorted set --有序集合)和hash(哈希类型)。
3.redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库(如MySQL)起到很好的补充作用。
4.它提供了Java,C/C++,C#,PHP,JavaScript等客户端,使用很方便。
5.Redis支持集群(主从同步)。数据可以主服务器向任意数量从的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。
6.支持持久化,可以将数据保存在硬盘的文件中
7.支持订阅/发布(subscribe/publish)功能 QQ群
8.数据能够支持过期设置
数据存储:
存放到内存中,并且还能不定期持久化到硬盘.
Value类型:
相较于memcached支持Value更多
客户端支持:
支持多种客户端-跨语言
超大并发支持:
支持集群
免费
redis常见数据类型
string==>String
set 设置一个字符串
get 获取一个字符串
mset 设置多个
mget 获取多个
如果设置的字符串的值是数值,可以用命令来进行加减操作
incr、decr、单个增减
incrby 、decrby、多个增减
incrbyfloat 浮点数
字符串在实际项目当中更多的石存JSON格式的字符串,缺点就是存了复杂的JSON字符串之后我们需要进行序列化操作
hash==>HashMap
hash用于存储多个键值对,一个存储空间可以存储多个数据,一般可以使用hash来存储对象信息。
基本操作:
存储数据(增)
语法:hset key field1 value1 field2 value2 ... fieldN valueN
redis4.0之后可以使用hset指令来完成多个属性的同时设置
redis4.0之前使用的hmset的指令来完成多个属性的同时设置,4.0之后,该指令被废弃,使用hset指令替代了。
获取数据(查)
查询单个属性的value的语法:hget key field
查询某个key下的所有属性的语法:hgetall key
一次查询多个属性的value的语法:hmget key field1 field2 ... fieldN
修改数据(改):用到的指令跟新增是一样的
语法:hset key field value
删除数据(删)
语法:hdel key field1 field2 ... fieldN
查看某个key下有多少个属性:hlen key
查看某个key下是否存在某个属性:hexists key field
查看某个key下所有的属性:hkeys key 了解
查看某个key下所有的value:hvals key 了解
hsetnx key field value:判断hash中是否存在某个field,如果存在,不做任何操作,如果不存在,则将键值对保存到hash中。
对数据型数据进行增减操作:
整数
hincrby key field increment
increment指的是要增加或减少的整形数据,值为正,做增加,值为负,做减少
浮点
hincrbyfloat key field increment
increment指的是要增加或减少的浮点数据,值为正,做增加,值为负,做减少
注意:hash类型设计之初就不是为了存储大量对象使用的,不要将其视为专门用于存储对象使用的数据类型。
list==>List
list其实就是类似于java中的list集合(LinkedList),用于存储多个数据。底层使用的是双向链表,对于list来说,着重考虑的是数据进行存储空间和从存储空间中取出数据的顺序。
我们可以使用list来实现队列和栈的效果。
基本操作:
存:
lpush(从左边向list中保存数据)
rpush(从右边向list中保存数据)
语法:
lpush key value1 value2 ... valueN
rpush key value1 value2 ... valueN
取:
取单个数据的语法:lindex key i,从list左边向外去获取数据,i,指的是list中保存的数据的下标
取多个数据的语法:lrange key start stop,start:从哪个下标开始,stop:到哪个下标结束,取值为-1时,表示要获取list中所有的数据
在获取的同时删除掉某个数据:
lpop key:从左边开始从list中获取第一个数据,并将该数据从list中删除掉
rpop key:从右边开始从list中获取第一个数据,并将该数据从list中删除掉
以上两条指令是会有返回值的。
从左向右,删除list中的指定数据:lrem key count value
count:要删除几个
value:要删除的值
该指令不会将被删除的数据返回出来,返回的是指令执行时实际删除的数据的个数。
set==>HashSet
set也是用于存储多个数据的。
list和set的区别:
list底层是双向链表,set的底层为hash,查询效率上来说,set优于list;
list是有序的,set是无序的;
list中元素是可重复出现的,set元素不允许重复;
基本操作:
存:
语法:sadd key member1 member2 ... memberN
取:
取全部:smembers key
删:
语法:srem key member1 member2 ... memberN
查看set中存储了多少个数据: scard key
查看set中是否存在某个元素:sismember key member
随机获取set中的元素(1个或多个):srandmember key [count] 了解
count是一个整数值,是可选的,如果设置了,则随机对应数值个数的数据
如果不设置,则默认随机获取set某一个元素
随机从set中获取并移除一个或多个元素:spop key [count]
spop指令的执行结果是对应的set中元素,并会将被匹配到的元素从set中移除掉。
zset(sorted set)==>TreeSet
zset是基于set的实现,在set的基础上增加了score(分值)属性用于进行排序。
基础操作:
存:
zadd key score1 member1 score2 member2 ... scoreN memberN
取:获取时,是按照score分值数值进行排序
升序:zrange key start stop [withscores]
加上withscores,返回时会显示score分值
降序:zrevrange key start stop [withscores]
查询score的值在某个范围内的元素:
升序:
zrangebyscore key min max [withscores] [limit offset count]
min:要查询的最小分值
max:要查询的最大分值
offset:从哪个下标开始
count:要查询几个元素
降序:
zrevrangebyscore key max min [withscores] [limit offset count]
注意:zset在排序时是按score的值进行排序的。
删:
zrem key member1 member2 ... memberN
删除分值在某个区间之内的元素:
按分值进行删除:
zremrangebyscore key min max
min和max还是指定的分值score
按索引进行删除:
zremrangebyrank key start stop
start和stop是指定的下标区间
统计:
zcard key:统计zset中的元素个数
zcount key min max:统计指定score分值区间内的元素个数
获取索引:了解
升序:
zrank key member
降序:
zrevrank key member
还有许多的数据类型,建议参考官网。
使用场景
1. 中央缓存(记住)
经常查询数据,不经常变化的数据,放到读速度很快的空间(内存),以便下次访问减少时间。减轻压力(数据库的压力),减少访问时间.而redis就是存放在内存中的。
Hibernte二级缓存,mybatis二级缓存,这些缓存默认都不支持在集群环境使用.redis中央缓存就OK.
2. 计数器应用
网站通常需要统计注册用户数,网站总浏览次数等等
新浪微博转发数、点赞数
3. 实时防攻击系统
暴力破解:使用工具不间断尝试各种密码进行登录。防:ip(账号)--->num,到达5次以后自动锁定IP,30分钟后解锁
解决方案:
1、存数据库
登录操作的访问量非常大
2、static Map<String,int> longinFailNumMap;
Map存储空间有限,大批量就不行,并且断电以后数据丢失。
问题:
1、每次查询数据库,查询速度慢,多次写 内存
2、断电会丢失数据,多个节点,不能共用 redis集群,容量可以无限大,可以共享数据、并且支持过期
4. 排行榜
总积分榜,今日积分榜,周积分,月积分,季度积分
方案:从数据库中查出来计算.
问题:
1、实时查询,查询速度慢
2、还要进行各种计算。
5. 设定有效期的应用
设定一个数据,到一定的时间失效。 自动解锁,购物券
6. 自动去重应用
Uniq 操作,获取某段时间所有数据排重值 这个使用 Redis 的 set 数据结构最合适了,只需要不断地将数据往 set 中扔就行了,set 意为 集合,所以会自动排重。
7. 队列
构建队列系统 使用 list 可以构建队列系统,使用 sorted set 甚至可以构建有优先级的队列系统。
秒杀:可以把名额放到内存队列(redis),内存就能处理高并发访问。
价格低,数量有限,有约束的时间:访问的多,服务器压力很大.
8. 消息订阅系统
Pub/Sub 构建实时消息系统 Redis 的 Pub/Sub 系统可以构建实时的消息系统,比如很多用 Pub/Sub 构建的实时聊天系统 的例子。
比如QQ群消息
集成spring-boot
Redisson
1.导入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.19.1</version>
</dependency>
2.配置
spring:
redis:
host: localhost
port: 6379
spring-data-redis
spring-data-redis是spring-data项目其中的一块,专门用于操作redis的。
优势:了解
-
连接池进行自动管理,提供了一个高封装度的RedisTemplate。
-
将大量的api进行了封装,将同类型的操作封装到一个叫operation接口中;
ValueOperations:简单的k-v操作(String)
ListOperations:针对redis中list类型相关操作
HashOperations:针对redis中hash类型相关操作
SetOperations:针对redis中set类型相关操作
ZSetOperations:针对redis中zset类型相关操作
-
序列化/反序列化,提供了多种序列化策略:
JdkSerializationRedisSerializer:jdk的序列化策略,pojo对象的存储场景,默认策略
StringRedisSerializer:key或者是value都是字符串
Jackson2JsonRedisSerializer:提供了javabean和json之间的转换能力
OxmSerializer:提供了javabean和xml之间的转换能力
boot项目中使用spring-data-redis的步骤:
-
引入相关依赖(spring-boot-starter-data-redis)
<!--引入spring-data-redis 后期需要做两个配置: redis的主机 redis的端口 配置主机的原因: redis是安装在linux上, 而springboot自动配置中, 主机配置的是localhost 配置端口的原因:我们在linux上启动的端口号是6380, 而自动配置中, 端口的默认配置是6379 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
在业务层中装配Redistemplate
//泛型: //1.是key的数据类型 //2.是value的数据类型 @Resource private RedisTemplate<String,User> redisTemplate;
此处要注意,不要使用@Autowried注解去装配,而应该使用@Resource去完成装配
-
在业务方法中通过Redistemplate对象,去获取操作指定数据类型的operation对象
//1.通过redistemplate对象去获取操作redis的相应接口对象(ListOperations) //redistemplate有相关的api专门用于获取操作某种数据类型的对象 //redistemplate.opsFor***() ***指的是数据类型 ListOperations<String,User> listOperations = redisTemplate.opsForList();
-
通过operation对象支调用相关的api完成对redis的增删改查
//假设redis中保存了热点数据, 是一个list,key是users //查询 List<User> users = listOperations.range("users", 0, -1); //新增 listOperations.leftPushAll("users",list);//将热点数据保存到redis中
-
如果linux上redis启动的端口不是6379,则在springboot配置文件中应该配置端口号,除此以外,由于是远程连接的redis,在配置文件中还需要配置redis的主机。
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.90.10:3306/test?characterEncoding=utf-8&useSSL=false username: root password: root redis: port: 6380 host: 192.168.90.10 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-
使用redis的桌面应用rdm去测试远程连接linux的redis,需要关闭掉linux上的redis的受保护模式
## 查看redis的受保护模式是否开启,yes开启,no关闭 config get protected-mode ## 关闭redis的受保护模式 config set protected-mode no
除此以外,如果还是不能连接,则需要将redis.conf配置文件中的bind绑定的主机改为0.0.0.0
Spring-Cache(with redisson)
1.加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.改配置
spring:
cache:
type: redis
redis:
time-to-live: 60S
3.加注解
@EnableCaching 加在启动类上
public class xxxxApplication{}
@Override
@Cacheable(cacheNames = "accountCache",key = "#accountId")
public Account findById(Integer accountId) {
log.info("从数据库中查询用户:{}",accountId);
return getById(accountId);
}
@CachePut(cacheNames = "accountCache",key = "#account.accountId")
public Account modify(Account account){
log.info("修改数据库:{}",account);
updateById(account);
return account;
}
@CacheEvict(cacheNames = "accountCache",key = "#accountId")
public void delAccount(Integer accountId){
log.info("删除用户:{}",accountId);
}
4.redisson的sprign-cache 可单独写配置文件,针对某一个缓存
@Configuration
public class CacheAppConfig {
@Bean
CacheManager cacheManager(RedissonClient redissonClient) {
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
// 创建一个名称为"testMap"的缓存,过期时间ttl为24分钟,同时最长空闲时maxIdleTime为12分钟。
config.put("userCache", new CacheConfig(20*1000, 15*1000));
return new RedissonSpringCacheManager(redissonClient, config);
}
}