Redis(Remote Dictionary Server即远程字典服务)是NoSQL类型的键值对存储数据库。
String(整形、浮点型、字符串,统称为元素)
List(实现队列,元素不唯一,先入先出原则)
Hash(key唯一,可以看作Map<String,String>)
Set(各不相同的元素)
Sort set(有序集合)
- 下载地址
- 解压后安装,在安装目录运行CMD
redis_dictionary>redis-server.exe redis.windows.conf
-
\\[10272] 15 Mar 08:48:38.095 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo \\[10272] 15 Mar 08:48:38.097 # Redis version=5.0.10, bits=64, commit=1c047b68, modified=0, pid=10272, just started \\[10272] 15 Mar 08:48:38.103 # Configuration loaded Redis 5.0.10 (1c047b68/0) 64 bit Running in standalone mode Port: 6379 PID: 10272 http://redis.io \\[10272] 15 Mar 08:48:38.152 # Server initialized \\[10272] 15 Mar 08:48:38.461 * DB loaded from append only file: 0.306 seconds \\[10272] 15 Mar 08:48:38.464 * Ready to accept connections
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
tar -zvxf redis-5.0.7.tar.gz
mv redis-5.0.7 /usr/local/redis
cd /usr/local/redis/
make
Hint: It's a good idea to run 'make test' ;)
make[1]: Leaving directory `/usr/local/redis/src'
[root@iz2ze9fctagto4qymjy32mz redis]#
make PREFIX=/usr/local/redis install
INSTALL install
INSTALL install
make[1]: Leaving directory `/usr/local/redis/src'
[root@iz2ze9fctagto4qymjy32mz redis]#
./bin/redis-server& ./redis.conf
30450:M 15 Mar 2021 09:16:14.642 * Ready to accept connections
[root@iz2ze9fctagto4qymjy32mz redis]#
##与Spring整合 目前项目中已经使用JEDIS开发,因此以下使用对JedisAPI高度封装过的SpringDataRedis-RedisTemplate。 RedisTemplate相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用如:SpringCache等。
- Pom.xml
<dependencies>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- conn pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>
- application.yml
spring :
cache:
#cache-names: cache1,cache2,cache3
redis :
timeout: 0
cache-manager: #配置了@EnableCaching注解就不用在这配置了
database : 0
host : 127.0.0.1
port : 6379
password :
pool :
max-active : 8 #连接数
max-wait : -1 #连接等待
max-idle : 8 #空闲
min-idle : 0
- 创建配置类Config.java继承CachingConfigurerSupport
3.1 我们主要使用的对象为org.springframework.data.redis.core下面的RedisTemplate和StringRedisTemplate 所以创建配置类的目的也是为了或者这两个类的Bean,以及在使用之前的配置.
/** * REDIS 配置 */ @Configuration @EnableCaching public class Config extends CachingConfigurerSupport { }
@Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory, RedisSerializer jackson2JsonRedisSerializer) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>(); redisTemplate.setConnectionFactory(redisConnectionFactory); RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer);//key序列化 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//value序列化 redisTemplate.setHashKeySerializer(stringSerializer);//Hash key序列化 redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);//Hash value序列化 redisTemplate.afterPropertiesSet(); return redisTemplate; } @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory, RedisSerializer jackson2JsonRedisSerializer) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory); RedisSerializer stringSerializer = new StringRedisSerializer(); stringRedisTemplate.setKeySerializer(stringSerializer);//key序列化 stringRedisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//value序列化 stringRedisTemplate.setHashKeySerializer(stringSerializer);//Hash key序列化 stringRedisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);//Hash value序列化 stringRedisTemplate.afterPropertiesSet(); return stringRedisTemplate; }
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作 SetOperations:set类型数据操作 ZSetOperations:zset类型数据操作 HashOperations:针对map类型的数据操作 ListOperations:针对list类型的数据操作
- 提供了对key的“bound”(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,即BoundKeyOperations:
BoundValueOperations BoundSetOperations BoundListOperations BoundSetOperations BoundHashOperations
- 将事务操作封装,有容器控制。
multi discard exec watch unwatch
- 针对数据的“序列化/反序列化”,提供了多种可选择策略(RedisSerializer)
JdkSerializationRedisSerializer: POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作, 最终redis-server中将存储字节序列。是目前最常用的序列化策略。 StringRedisSerializer: Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string, 是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。 JacksonJsonRedisSerializer: jackson-json工具提供了javabean与json之间的转换能力, 可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。 因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。 需要jackson-mapper-asl工具支持 OxmSerializer: 提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans; redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。 需要spring-oxm模块的支持
持久化分为快照方式(RDB)和日志方式(AOF)两种
RDB 是 Redis 默认的持久化方案。
在指定的时间间隔内,执行指定次数的写操作,将内存中的数据写入到磁盘中。
在指定目录下生成一个RedisDatabase File。
Redis 重启会通过加载dump.rdb文件恢复数据
####使用方式
- 配置文件redis.conf
dbfilename dump.rdb
#save <seconds> <keyChanges>
save 900 1
save 300 10
save 60 10000
- 直接使用SAVE 立即执行,阻塞所有请求 和BGSAVE BackgroundSAVE命令
AOF是采用日志的形式来记录每个写操作,并追加到文件appendonly.aof中。
Redis重启后根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。默认关闭。
它的出现是为了弥补RDB的不足(数据的不一致性)
####使用方式
- 配置文件redis.conf
appendfilename "appendonly.aof"
# no/yes
appendonly no
# fsync函数同步内存中所有已修改的文件数据到储存设备。
# no/always/everysec
appendfsync everysec
优 | 劣 | |
---|---|---|
RDB | 单一文件, 单独fork进程,无多余IO 恢复大数据比AOF快 |
定时策略,可能丢失两次操作中间的数据 |
AOF | 频繁:每秒或者每次操作 写入速度快 可读 |
文件大, QPS(Query Per Second)低 |
Redis数据库是由一个整数标识,而不是由一个数据库名称。 默认一个客户端连接到数据库db0。 配置文件redis.conf中的databases参数来控制数据库总数,每库都有自己的命名空间,重复key不会冲突
为了保持其独立性,同一个实例不适宜存储不同应用程序的数据。
Redis非常轻量级,一个空Redis实例占用的内在只有1M左右,多个Redis实例不会额外占用很多内存。
如可使用db0存储A应用生产环境中的数据,使用db1存储A应用测试环境中的数据,
不宜使用db0存储A应用的数据而使用db1存储B应用的数据,不同的应用应该使用不同的Redis实例存储数据。
执行exec时取消队列,已经执行的命令无法回滚。低可靠, 高性能 Redis的事务中,启用的是乐观锁,使用watch命令负责监控key有没有被改动过, 在事务中,如果任意一个监控的key有改变,则事务取消。
@Test
public void test() {
Jedis jedis = new Jedis("localhost");
try {
Transaction transaction = jedis.multi();
transaction.lpush("key", "11");
transaction.lpush("key", "22");
int a = 6 / 0;
transaction.lpush("key", "33");
List<Object> list = transaction.exec();
} catch (Exception e) {
}
}
Redis与 mysql事务的对比:
| | Mysql | redis | | ----------|:------------------|:--------------| |开启事务 |start transaction | multi | |执行语句 |SQL | redis cmd | |失败 |rollback | discard | |成功 |commit | exec |
缓存:高频读、低频写。大数据量、低访问频率的业务不适
计数器:如使用increment方法;限制单一IP频繁访问,每次访问后incr,到达限值后拒绝
消息队列:Publish&Subscribe
排行榜:ZSet进行rank排序,优于order by
关系计算:set的集合命令union,diff
Session共享:集群之间用户Session共享,省去重复出现登录操作
com.dev.redis.demo.cache.test.DictCacheTest.java
@Cacheable:缓存-DB-缓存
@CachePut:将方法的返回值放到缓存中。
@CacheEvict:删除缓存中的数据。
com.dev.redis.demo.cache.test.DictCacheTest.java
常用的通过代码写到项目里, 启动自动加载
做一个页面, 启动之后手动刷新
每次缓存访问做日志记录,count多的做缓存;
后台县城定时查询排名并作记录--存到list或sort set中选择排名高的
-查询一个一定不存在的缓存key 1.缓存数据库有数据的k->set 2.缓存空结果
-并发查询一个刚刚失效的key 分布锁, 悲观锁(lua脚本或者setNX)-com.dev.redis.demo.lock.RedisLockTest
-与上一条连锁 ..
key在过期时会触发一个callback, 在java中可以监听到
com.dev.redis.demo.message.expired.KeyExpiredListener
127.0.0.1:6379> info server
# Server
redis_version:5.0.10
redis_git_sha1:1c047b68
redis_git_dirty:0
redis_build_id:76de97c74f6945e9
redis_mode:standalone
os:Windows
arch_bits:64
multiplexing_api:WinSock_IOCP
atomicvar_api:pthread-mutex
process_id:10948
run_id:ece51cfefd79305db8d44df7af722dc07344a5ec
tcp_port:6379
uptime_in_seconds:5141
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:5183100
executable:E:\program_flies\Redis\redis-server.exe
config_file:E:\program_flies\Redis\redis.windows.conf
-
所有设置的缓存一定要有过期时间,否则会满
- 淘汰策略,
- 从已设置过期时间的数据集(server.db[i].expires)中:
- volatile-lru:最少使用
- volatile-ttl:将要过期
- volatile-random:随机选择
- 从数据集(server.db[i].dict)中:
- allkeys-lru:最少使用
- allkeys-random:随机选择
- no-enviction(驱逐):禁止,新写入操作会报错。
- 从已设置过期时间的数据集(server.db[i].expires)中:
- 默认
maxmemory-policy noeviction
不会继续服务写请求 (DEL和GET可以继续进行)。
- 淘汰策略,
-
一个key中最好不要存储过大量数据,比如超过了1G就应该考虑自己去做拆分存储
-
命令复杂度的参考表 KEYS*
String
命令 时间复杂度 set 0(1) get 0(1) del 0(k),k是键的个数 mset 0(k),k是键的个数 mget 0(k),k是键的个数 incr 0(1) decr 0(1) incryby 0(1) decryby 0(1) incrybyfloat 0(1) append 0(1) strlen 0(1) setrange 0(n),n为更改字符串长度 getrange 0(n),n为获取字符串长度 Hash
命令 时间复杂度 hset 0(1) hget 0(1) hdel 0(k),k是键的个数 hlen O(1) hgetall 0(k),k是field的个数 hmget 0(k),k是field的个数 hmset 0(k),k是field的个数 hexists O(1) hkeys 0(k),k是field的个数 hvals 0(k),k是field的个数 hsetnx O(1) hincrby O(1) hincrbyfloat O(1) hstrlen O(1) List
命令 时间复杂度 rpush 0(k),k是field的个数 lpush 0(k),k是field的个数 linsert 0(n),n是插入位置距离表头或表尾的距离 lrange O(s+n),s是start的偏移量,n是start到end的范围 lindex O(n),n是索引的偏移量 llen O(1) lpop O(1) rpop O(1) lrem O(n),n是列表的长度 ltrim O(n),n是要裁剪的元素总数 lset O(n),n是索引的偏移量 blpop O(1) Set
命令 时间复杂度 sadd O(k),k为元素个数 srem O(k),k为元素个数 scard O(1) sismember O(1) srandmember O(count) spop O(1) smembers O(n),n为元素总数 sinter O(m*k),k为多个集合中元素较少的个数,m是键个数 suinon O(k),k为多个集合元素个数和 sdiff O(k),k为多个集合元素个数和 ZSet
命令 时间复杂度 zadd O(k*log(n)),k为添加 成员个数,n为当前成员个数 zcard O(1) zscore O(1) zrank
zrevrank
O(log(n)),n为当前成员个数 zrem O(k*log(n)),k为删除成员个数,n为当前成员个数 zincrby O(log(n)),n为当前成员个数 zrange
zrevrange
O(log(n)+k),k为要获取成员个数,n为当前成员个数 zrangebyscore
zrevrangebyscore
O(log(n)+k),k为要获取成员个数,n为当前成员个数 zcount O(log(n)+k),k为要获取成员个数,n为当前成员个数 zremrangebyrank O(log(n)+k),k为要删除成员个数,n为当前成员个数 zremrangebyscore O(log(n)+k),k为要删除成员个数,n为当前成员个数 zinterstore O(n*k) + O(m*log(m)),
n是成员数最小的有序集合的成员个数,
k是有序集合的个数,
m是结果集中成员个数zunionstore O(n) + O(m*log(m)),
n是所有有序集合成员个数和,
m是结果集中成员个数
.
.
.# jdev-redis