spring-redis使用

导包 

注入调用           opsForValue()     opsForList()

 

 

redisTemplate   配置 ,为了   对key采用string序列化方式                 对value采用json序列化方式

参数的配置

# Redis 配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.10.128
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=123qwe
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

使用Redis做缓存

使用Spring Cache注解 设置过期时间

 

在service层加上cache注解

@Cacheable  为存取缓存     @CachePut 为修改缓存      @CacheEvict 为删除缓存

 各个注解中的value参数是一个key的前缀

对于key的生成规则用调用者本身对象的ID属性保证它的唯一性如下 注册进

然后在需要cache的地方调用Redis  CRUD 方法

 

1.为什么使用redis  性能 并发

2.单线程的redis为什么这么快

redis是单线程工作模型

(一)纯内存操作
(二)单线程操作,避免了频繁的上下文切换
(三)采用了非阻塞I/O多路复用机制

参照上图,简单来说,就是。我们的redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。

3、redis的数据类型,以及每种数据类型的使用场景(五种)

String    一些复杂的计数功能的缓存。

hash     单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

list     做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。

set   全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。
另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能

sorted set   set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。另外,参照另一篇《分布式之延时任务方案解析》,该文指出了sorted set可以用来做延时任务。最后一个应用就是可以做范围查找

4、redis的过期策略以及内存淘汰机制

redis采用的是定期删除+惰性删除策略。

定期删除 默认100ms   惰性删除 在请求key的时候判断过期时间

如果既没删掉,又没访问惰性删除,内存要爆掉了怎么办,只能采用内存淘汰机制

 

在redis.conf中有一行配置
# maxmemory-policy volatile-lru   在设置过期时间的键中移出最少使用的key  不推荐

 

allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。推荐使用,目前项目在用这种。

 

5、redis和数据库双写一致性问题

数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存

采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。https://www.cnblogs.com/rjzheng/p/9041659.html

 

6 如何解决redis的并发竞争key问题

(1)如果对这个key操作,不要求顺序
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。
(2)如果对这个key操作,要求顺序
假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.
期望按照key1的value值按照 valueA-->valueB-->valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下

系统A key 1 {valueA  3:00}
系统B key 1 {valueB  3:05}
系统C key 1 {valueC  3:10}

那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

其他方法,比如利用队列,将set方法变成串行访问也可以。总之,灵活变通。

 

redis-cli 启动

set name(key) "value"(value)
get name
1.key不要太长,尽量不要超过1024字节,这不仅消耗内存,而且会降低查找的效率;
2.key也不要太短,太短的话,key的可读性会降低;
3.在一个项目中,key最好使用统一的命名模式,例如user:10000:passwd。
incr name 给某个值加1 (INCR、INCRBY、DECR、DECRBY)全部具有原子操作不需担心事务
2.存list
lpush mylist "1"
lpush(左插)rpush(右插)
lrange mylist 0 1
2.存set
asdd myset "one"
smembers myset 列出
sismember myset "one" 判断是否存在
sunion myset yourset 合并
有序集合(zsets)
zadd myzset 3 value 赋予他的序号为3
3.存Hash
HMSET user:001(key) username antirez password P1pp0 age 34 (value)
HGETALL user:001
HSET user:001 password 12345

redis提供了两种持久化的方式分别是RDB(Redis DataBase)和AOF(Append Only File)

RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上

如果每5分钟都持久化一次,当redis故障时,仍然会有近5分钟的数据丢失


AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了
通过配置redis.conf中的appendonly yes就可以打开AOF功能
默认的AOF持久化策略是每秒钟fsync(缓存中的指令记录到磁盘中)一次 之丢失1s
直接执行BGREWRITEAOF命令,那么redis会生成一个全新的AOF文件

关闭RDB和AOF方式 redis将变成一个纯内存数据库,就像memcache一样。


1.MULTI用来组装一个事务;
2.EXEC用来执行一个事务;
3.DISCARD用来取消一个事务;
4.WATCH用来监视一些key,一旦这些key在事务执行之前被改变,则取消事务的执行

redis-check-aof工具来修复 不完整指令信息


redis.conf配置
include /other.conf 引入其他配置文件
1.通用(general)
2.快照(snapshotting)
3.复制(replication)
4.安全(security)
5.限制(limits)
6.追加模式(append only mode)
7.LUA脚本(lua scripting)
8.慢日志(slow log)
9.事件通知(event notification)


2快照
save 60 10000 //表示每60秒至少有10000个key改变,就触发一次持久化
不设置save或save "" 禁用RDB持久化

当RDB持久化失败 —>拒绝写请求
等待成功后,自动恢复
stop-writes-on-bgsave-error yes 关闭强行接受

rdbcompression yes 是否关闭压缩快照
rdbchecksum yes 快照存储后是否关闭快照数据校验
dbfilename dump.rdb 设置快照名称
dir ./ 目录


3.redis配置 – 复制

slaveof <masterip> <masterport> 主从同步
masterauth <master-password> 设置主的密码(主设置密码 requirepass设置)

主从同步时 客户端 只读slave-read-only yes

只读的从redis并不适合直接暴露给不可信的客户端 名字起得牛点,难以直接调用
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52

repl-backlog-size 1mb 设置同步队列长度 队列长度(backlog)是主redis中的一个缓冲区在与从redis断开连接期间,主redis会用这个缓冲区来缓存应该发给从redis的数据。这样的话,当从redis重新连接上之后,就不必重新全量同步数据,只需要同步这部分增量数据即可。

repl-backlog-ttl 3600 设置等待时间,等不到我就清除了

slave-priority 100 设置优先级 ,越小越高 如果主不工作了,谁来当主


5.限制
maxclients 10000
maxmemory <bytes>
达到内存上限后 移除规则可以通过maxmemory-policy来指定。
移除规则
1.volatile-lru:使用LRU算法移除过期集合中的key
2.allkeys-lru:使用LRU算法移除key
3.volatile-random:在过期集合中移除随机的key
4.allkeys-random:移除随机的key
5.volatile-ttl:移除那些TTL值最小的key,即那些最近才过期的key。
6.noeviction:不进行移除。针对写操作,只是返回错误信息。


6.追加模式
appendonly no

no-appendfsync-on-rewrite no


Redis 和 Memcached 的区别
http://www.importnew.com/26921.html

使用redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<gson>
spring.redis.database=0
spring.redis.host=192.168.0.58
spring.redis.port=6379
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0


@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@Bean
public KeyGenerator objectId() {
return new KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
try {
sb.append(params[0].getClass().getMethod("getId", null)
.invoke(params[0],null).toString());
} catch (NoSuchMethodException no) {
no.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return sb.toString();
}
};
}

@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//设置缓存过期时间
//rcm.setDefaultExpiration(60);//秒
return rcm;
}

@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}

}
@Autowired
private RedisTemplate redisTemplate;

redisTemplate.opsForValue().set

Gson gson = new Gson();
gson.tojson
user = gson.fromJson(userJson, User.class);

spring.cache.type = redis 进行配置

@Cacheble() @CachePut @CacheEvict 删除 @Caching

@CacheEvict: 失效缓存

@Cacheable: 插入缓存
value: 缓存名称
key: 缓存键,一般包含被缓存对象的主键,支持Spring EL表达式
unless: 只有当查询结果不为空时,才放入缓存

session 也可以放到redis中
共享Session-spring-session-data-redis
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}

 


Redis常用命令
1 连接操作命令

quit:关闭连接(connection)
auth:简单密码认证
help cmd: 查看cmd帮助,例如:help quit
2 持久化

save:将数据同步保存到磁盘
bgsave:将数据异步保存到磁盘
lastsave:返回上次成功将数据保存到磁盘的Unix时戳
shutdown:将数据同步保存到磁盘,然后关闭服务
3 远程服务控制

info:提供服务器的信息和统计
monitor:实时转储收到的请求
slaveof:改变复制策略设置
config:在运行时配置Redis服务器
4 对key操作的命令

exists(key):确认一个key是否存在
del(key):删除一个key
type(key):返回值的类型
keys(pattern):返回满足给定pattern的所有key
randomkey:随机返回key空间的一个
keyrename(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 i的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的子串
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

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 Hash

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

具体察看

posted @ 2018-02-27 18:36  jojoworld  阅读(566)  评论(0编辑  收藏  举报