Redis官网:http://www.redis.cn/ Redis线程:Redis 属于单线程还是多线程?不同的版本有什么区别?_redis is single threaded-优快云博客
Redis下载:https://github.com/redis/redis/tags | Index of /releases/
Tendis官网:Tendis存储版
??#### 什么是Redis
redis是一个nosql(not only sql不仅仅只有sql)数据库,翻译成中文叫做非关系型型数据库。 关系型数据库:以二维表形式存储数据 非关系型数据库:以键值对形式存储数据(key, value形式) 是一家意大利的创业公司出的,后来这家公司被VMware赞助。redis底层用C语句编写。
redis是将数据存放到内存中,由于内容存取速度快所以redis被广泛应用在互联网项目中, redis优点:存取速度快,官方称读取会达到30万次每秒,写在10万次每秒,具体限制于硬件。 缺点:对持久化支持不够良好, 所以redis一般不作为数据的主数据库存储,一般配合传统的关系型数据库使用。
redis应用领域
分布式缓存 分布式session 论坛、评论首页或前几页 秒杀,抢购 总之是用在数据访问量大,并发量高的情况下
怎么用
redis主要就是使用命令来进行操作,java端在代码中可以使用Jedis来操作redis服务器 redis数据类型 字符串String 列表list redis中使用的是双向循环链表来实现的list,在redis中更像栈 散列Hash 一般应用于将redis作为分布式缓存,存储数据库中的数据对象 集合set set中数据是无序的并且不允许重复 有序集合zset redis会根据分数自动排序,这里可以使用在学生成绩排序,或者是手机应用商店流行软件排名等需求中
redis持久化方案:
rdb:可以设置间隔多长时间保存一次(Redis不用任何配置默认的持久化方案)(dump.rdb) 优点:让redis的数据存取速度变快 缺点:服务器断电时会丢失部分数据(数据的完整性得不到保证) aof:可以设置实时保存(修改配置文件将appendonly改为yes)(appendonly.aof) 优点:持久化良好,能保证数据的完整性 缺点:大大降低了redis系统的存取速度
Redis 4.0 混合持久化
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志的性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。
Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。如图 1-3 所示,将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此得到大幅提升。
Redis和Memcached的区别:
1、存储方式上:memcache会把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。redis有部分数据存在硬盘上,这样能保证数据的持久性。
2、数据支持类型上:memcache对数据类型的支持简单,只支持简单的key-value,,而redis支持六种数据类型。
3、使用底层模型不同:它们之间底层实现方式以及与客户端之间通信的应用协议不一样。redis直接自己构建了VM机制,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
4、value的大小:redis可以达到1GB,而memcache只有1MB
启动
windows版本可以去gitee搜索redis-windows下载,解压可用
打开一个cmd窗口,使用cd命令切换到解压目录(D:\app\redis | D:\Program Files\Redis) 运行 redis-server.exe redis.conf 或者 双击redis-server.exe
重新打开一个cmd窗口,使用cd命令切换到指定目录 运行 redis-cli.exe -h 192.168.174.133 -p 6379 -a 123456 其中192.168.174.133是ip,6379是redis服务端的端口,密码默认空,不输入ip和端口默认本机6379
Redis常用命令集
1)连接操作命令
ping:检查连接 quit:关闭连接(connection) auth:简单密码认证 help cmd: 查看cmd帮助,例如:help quit
2)持久化
save: 将数据同步保存到磁盘 bgsave: 将数据异步保存到磁盘 lastsave:返回上次成功将数据保存到磁盘的Unix时戳 shutdown:将数据同步保存到磁盘,然后关闭服务 flushdb: 清除当前数据库的所有keys flushall:清除所有数据库的所有keys
3)远程服务控制
info: 提供服务器的信息和统计 monitor:实时转储收到的请求 slaveof:改变复制策略设置 config: 在运行时配置Redis服务器
4)对value操作的命令
keys * // 查看所有keys keys prefix_* // 查看前缀为"prefix_"的所有keys exists(key):确认一个key是否存在 del(key):删除一个key type(key):返回值的类型 keys(pattern):返回满足给定pattern的所有key randomkey:随机返回key空间的一个 rename(oldname, newname):重命名key dbsize:返回当前数据库中key的数目 expire:设定一个key的活动时间(s) ttl:获得一个key的活动时间 select(index):按索引查询 move(key, dbindex):移动当前数据库中的key到dbindex数据库 flushdb:删除当前选择数据库中的所有key flushall:删除所有数据库中的所有key
5)String
set(key, value):给数据库中名称为key的string赋予值value get(key):返回数据库中名称为key的string的value getset(key, value):给名称为key的string赋予上一次的value mget(key1, key2,…, key N):返回库中多个string的value setnx(key, value):添加string,名称为key,值为value setex(key, time, value):向库中添加string,设定过期时间time mset(key N, value N):批量设置多个string的值 msetnx(key N, value N):如果所有名称为key的string都不存在 incr(key):名称为key的string增1操作 incrby(key, integer):名称为key的string增加integer decr(key):名称为key的string减1操作 decrby(key, integer):名称为key的string减少integer append(key, value):名称为key的string的值附加value substr(key, start, end):返回名称为key的string的value的子串
NX是Not eXists的缩写,如SETNX命令就应该理解为:SET if not exists。
6)List:存集合,可重复
rpush(key, value):在名称为key的list尾添加一个值为value的元素 lpush(key, value):在名称为key的list头添加一个值为value的 元素 llen(key):返回名称为key的list的长度 lrange(key, start, end):返回名称为key的list中start至end之间的元素 ltrim(key, start, end):截取名称为key的list lindex(key, index):返回名称为key的list中index位置的元素 lset(key, index, value):给名称为key的list中index位置的元素赋值(修改) lrem(key, count, value):删除count个key的list中值为value的元素 lpop(key):返回并删除名称为key的list中的首元素 rpop(key):返回并删除名称为key的list中的尾元素 blpop(key1, key2,… key N, timeout):lpop命令的block版本。 brpop(key1, key2,… key N, timeout):rpop的block版本。 rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部
7)Set:存集合,不可重复
对象是所有属性值相同认为重复,重写hashcode和equals只对程序有效,所以数据可以在取出来之后去重的
sadd(key, member):向名称为key的set中添加元素member srem(key, member) :删除名称为key的set中的元素member spop(key) :随机返回并删除名称为key的set中一个元素 smove(srckey, dstkey, member) :移到集合元素 scard(key) :返回名称为key的set的基数 sismember(key, member) :member是否是名称为key的set的元素 sinter(key1 key2 …key N) :求交集 sinterstore(dstkey (keys)) :求交集并将交集保存到dstkey的集合 sunion(key1 (keys)) :求并集 sunionstore(dstkey (keys)) :求并集并将并集保存到dstkey的集合 sdiff(key1 (keys)) :求差集 sdiffstore(dstkey (keys)) :求差集并将差集保存到dstkey的集合 smembers(key) :返回名称为key的set的所有元素 srandmember(key) :随机返回名称为key的set的一个元素
8)ZSet:有序集合,不可重复
zadd(key score member):添加元素(score用来指定排序规则,数字越小代表值越小) zrange(key start stop [WITHSCORES]) :获取索引区间内的元素,WITHSCORES显示score值 ZRANGE zset 0 -1 WITHSCORES:显示整个有序集成员 ZRANGE zset 1 2 WITHSCORES:显示有序集下标区间 1 至 2 的成员 zrangebyscore :获取分数区间内的元素 zrangebyscore zset -inf +inf :显示整个有序集成员(zrangebyscore zset 8 8显示score值为8的元素) zrem :删除元素 zcard :获取集合中元素个数 zincrby :增减元素的score zcount : 获取分数区间内元素个数 zrank : 获取项在zset中的索引 zscore :获取元素的分数 zrevrange :获取索引区间内的元素 zrevrangebyscore:获取分数区间内的元素 zremrangebyrank:删除索引区间内的元素 zremrangebyscore:删除分数区间内的元素 zinterstore:交集 zunionstore:并集
9)Hash:存对象 hset user id 1 | hset user name admin
hset(key, field, value):向名称为key的hash中添加元素field hget(key, field):返回名称为key的hash中field对应的value hmget(key, (fields)):返回名称为key的hash中field i对应的value hmset(key, (fields)):向名称为key的hash中添加元素field hincrby(key, field, integer):将名称为key的hash中field的value增加integer hexists(key, field):名称为key的hash中是否存在键为field的域 hdel(key, field):删除名称为key的hash中键为field的域 hlen(key):返回名称为key的hash中元素个数 hkeys(key):返回名称为key的hash中所有键 hvals(key):返回名称为key的hash中所有键对应的value hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
10)Stream:(Redis 5.0 新增)
主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
我们后面有专业的消息队列ActiveMQ、RabbitMQ、RocketMQ等。
消息队列相关命令: XADD - 添加消息到末尾 XTRIM - 对流进行修剪,限制长度 XDEL - 删除消息 XLEN - 获取流包含的元素数量,即消息长度 XRANGE - 获取消息列表,会自动过滤已经删除的消息 XREVRANGE - 反向获取消息列表,ID 从大到小 XREAD - 以阻塞或非阻塞方式获取消息列表 消费者组相关命令: XGROUP CREATE - 创建消费者组 XREADGROUP GROUP - 读取消费者组中的消息 XACK - 将消息标记为"已处理" XGROUP SETID - 为消费者组设置新的最后递送消息ID XGROUP DELCONSUMER - 删除消费者 XGROUP DESTROY - 删除消费者组 XPENDING - 显示待处理消息的相关信息 XCLAIM - 转移消息的归属权 XINFO - 查看流和消费者组的相关信息; XINFO GROUPS - 打印消费者组的信息; XINFO STREAM - 打印流信息
Redis高级应用
1、安全性 设置客户端连接后进行任何操作指定前需要密码,一个外部用户可以再一秒钟进行150W次访问,具体操作密码修改设置redis.conf里面的requirepass属性给予密码
2、主从复制 做这个操作的时候准备多个不同的配置启动多台服务器 通过主从复制可以允许多个slave server拥有和master server相同的数据库副本
如果没有主从同步那么就检查一下是不是防火墙的问题
3、事务处理 redis对事务的支持还比较简单,redis只能保证一个client发起的事务中的命令可以连续执行,而中间不会插入其他client的命令。当一个client在一个连接中发出multi命令时,这个连接会进入一个事务的上下文,连接后续命令不会立即执行,而是先放到一个队列中,当执行exec命令时,redis会顺序的执行队列中的所有命令。 比如我下面的一个例子 set age 100 multi set age 10 set age 20 exec get age --这个内容就应该是20 multi set age 20 set age 10 exec get age --这个时候的内容就成了10,充分体现了一下按照队列顺序执行的方式 discard 取消所有事务,也就是事务回滚 不过在redis事务执行有个别错误的时候,事务不会回滚,会把不错误的内容执行,错误的内容直接放弃
4、持久化机制 redis是一个支持持久化的内存数据库 snapshotting快照方式,默认的存储方式,默认写入dump.rdb的二进制文件中,可以配置redis在n秒内如果超过m个key被修改过就自动做快照 save 900 1 #900秒内有至少1个键被更改则进行快照 save 300 10 #300秒内有至少10个键被更改则进行快照 save 60 10000 #60秒内有至少10000个键被更改则进行快照
append-only file aof方式,使用aof时候redis会将每一次的修改都追加到文件中
Redis-cli参数
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]] -h <hostname> Server hostname (default: 127.0.0.1) -p <port> Server port (default: 6379) -s <socket> Server socket (overrides hostname and port) -a <password> Password to use when connecting to the server -r <repeat> Execute specified command N times -i <interval> When -r is used, waits <interval> seconds per command. It is possible to specify sub-second times like -i 0.1 -n <db> Database number -x Read last argument from STDIN -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \n) -c Enable cluster mode (follow -ASK and -MOVED redirections) --raw Use raw formatting for replies (default when STDOUT is not a tty) --latency Enter a special mode continuously sampling latency --slave Simulate a slave showing commands received from the master --pipe Transfer raw Redis protocol from stdin to server --bigkeys Sample Redis keys looking for big keys --eval <file> Send an EVAL command using the Lua script at <file> --help Output this help and exit --version Output version and exit
Redis多个数据库
注意:Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念
Redis是一个字典结构的存储服务器,而实际上一个Redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系数据库实例中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。
每个数据库对外都是一个从0开始的递增数字命名,Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库,如要选择1号数据库:
redis> SELECT 1 OK redis [1] > GET foo (nil)
然而这些以数字命名的数据库又与我们理解的数据库有所区别。首先Redis不支持自定义数据库的名字,每个数据库都以编号命名,开发者必须自己记录哪些数据库存储了哪些数据。另外Redis也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问全部数据库,要么连一个数据库也没有权限访问。最重要的一点是多个数据库之间并不是完全隔离的,比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。综上所述,这些数据库更像是一种命名空间,而不适宜存储不同应用程序的数据。比如可以使用0号数据库存储某个应用生产环境中的数据,使用1号数据库存储测试环境中的数据,但不适宜使用0号数据库存储A应用的数据而使用1号数据库B应用的数据,不同的应用应该使用不同的Redis实例存储数据。由于Redis非常轻量级,一个空Redis实例占用的内在只有1M左右,所以不用担心多个Redis实例会额外占用很多内存。
Redis桌面管理工具:
redis-desktop-manager (开源自己编译免费,或者去百度下载)
官网(收费):https://redisdesktop.com/download
码云:redisdesktop 标签 - Gitee.com(源码)
AnotherRedisDesktopManager(免费开源):https://github.com/qishibo/AnotherRedisDesktopManager/releases
程序操作Redis:
注意pojo实体类必须实现序列化
纯Java连接Redis:
Jedis:https://www.cnblogs.com/c-xiaohai/p/8376364.html
SpringBoot+Redis:
SpringBoot1.x:
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency>
spring: redis: database: 0 host: localhost port: 6379 password: 123456 timeout: 60 pool: max-active: 10 max-wait: -1 max-idle: 5 min-idle: 3
SpringBoot2.x:
<!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <!-- spring-boot-starter-data-redis-reactive也可以 --> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
spring: redis: host: 192.168.174.131 port: 6379 username: admin #6.x新增acl password: 123456 database: 0 timeout: 10s # 数据库连接超时时间,2.x中该参数的类型为Duration,在配置的时候需要指明单位 # 连接池配置,2.x中直接使用jedis或者lettuce配置连接池 jedis: # 也可以使用[lettuce] pool: max-idle: 50 # 最大空闲连接数 min-idle: 10 # 最小空闲连接数 max-wait: -1s # 等待可用连接的最大时间,负数为不限制 max-active: -1 # 最大活跃连接数,负数为不限制 #哨兵(注释上面host、port,注意缩进,错了不报错默认连接localhost:6379) sentinel: master: mymaster #只配哨兵不需要配主从服务器地址(三个哨兵集群地址) nodes: 192.168.174.130:26379,192.168.174.131:26379,192.168.174.132:26379 #纯集群(注释上面host、port、sentinel) cluster: nodes: - 192.168.174.131:6001 - 192.168.174.131:6002 - 192.168.174.131:6003 - 192.168.174.131:6004 - 192.168.174.131:6005 - 192.168.174.131:6006
一、Spring注解管理缓存:
@Cacheable、@CachePut、@CacheEvict,必须使用@EnableCaching开启,CacheManager可选
使用参数id作为键,方法返回值作为值,而且忽略空值存入缓存,下次调用根据键取值,如果有直接返回而不调用该方法,condition表示满足条件才执行缓存: @Cacheable放在一个类上时则表示该类所有的方法都是支持缓存的,条件不满足直接执行方法
//参数为对象 key="#user.id" (#对象名.属性名) @Cacheable(value="user", key="#id", unless="#result==null", condition="#id%2==0") public Users getUser(int id) { System.out.println("UsersService:"); Users u = usersDao.findById(id); return u; }
注意: 1、返回对象的时候报java.lang.ClassCastException是和热部署冲突!去掉SpringBoot热部署就可以了 2、CacheManager(disableCachingNullValues()) 必须匹配 unless="#result==null"
@CachePut类似@Cacheable,不同的是它不会查看缓存是否存在,而是直接保存到缓存 @CacheEvict是用来标注在需要清除缓存元素的方法或类上的,可以指定的属性有value、key、condition、 allEntries和beforeInvocation allEntries表示是否需要清除缓存中的所有元素。默认为false,表示不需要。 beforeInvocation默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。
//CacheManager: @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { //默认缓存管理器 @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisCacheManager cacheManager = RedisCacheManager.create(factory); return cacheManager; } //缓存管理器 @Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { System.out.println("CacheManager......"); //改序列化方式为json ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance , ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); serializer.setObjectMapper(om); //设置缓存配置 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); RedisCacheConfiguration config1 = config.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofSeconds(300)) //缓存时间,秒 .disableCachingNullValues() //不缓存空值 .prefixKeysWith("user"); //前缀userssss+#id(userssss2) RedisCacheConfiguration config2 = config.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofHours(1)) //缓存时间,小时 .disableCachingNullValues() //不缓存空值 .prefixKeysWith("news"); //缓存区间 //对每个缓存空间应用不同的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("user", config1); //user匹配@Cacheable的value属性值user configMap.put("news", config2); //初始化一个RedisCacheWriter RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); //初始化RedisCacheManager RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, config, configMap); return cacheManager; } }
在SpringBoot中使用Spring Cache可以轻松实现缓存,是Spring框架提供的对缓存使用的抽象类,支持多种缓存,比如Redis、EhCache等,每种类型只能返回一个CacheManager,如果返回多个或者配置了多个不同Cache默认都会异常!
二、SpringBoot使用的模板类:
RedisTemplate和StringRedisTemplate的区别:
-
两者的关系是StringRedisTemplate继承RedisTemplate。
-
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
-
SDR默认序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
-
修改默认序列化策略
@Bean(name = "redisTemplate") public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setConnectionFactory(factory); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.activateDefaultTyping( LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); Jackson2JsonRedisSerializer js = new Jackson2JsonRedisSerializer(Object.class); js.setObjectMapper(objectMapper); // key的序列化类型 redisTemplate.setKeySerializer(new StringRedisSerializer()); // value的序列化类型 redisTemplate.setValueSerializer(js); return redisTemplate; }
性能总结: JdkSerializationRedisSerializer序列化后长度最小,Jackson2JsonRedisSerializer效率最高。GenericJackson2JsonRedisSerializer序列化时间最长,序列化后的长度也最长,StringRedisSerializer直接就是字符串。
如果综合考虑效率和可读性,牺牲部分空间,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用Jackson2JsonRedisSerializer
如果空间比较敏感,效率要求不高,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用JdkSerializationRedisSerializer