一.数据库分类
1.关系型数据库SQL
Oracle:不开源收费,高帅富;
SQL Server:不开源收费,微软自家的产品;
DB2:不开源收费,IBM 的产品;
Sybase:不开源收费,微软的小基友,关系破裂后家境惨淡;
MySQL:大家都在用;
PostgreSQL:学术气息有点重;
Sqlite:嵌入式数据库,适合桌面和移动应用;
2.非关系型数据库NoSQL(No SQL || Not Only SQL)
二、简介
内存数据库,C 语言开发的一个开源的超高性能 key-value 数据库,可以用作数据库、缓存、消息中间件等;
特性
性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS(每秒查询率,Queries-per-second );
单进程单线程,是线程安全的,采用 IO 多路复用机制;
Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value,支持字符串( String )、散列( Hash )、列表( List )、集合( Set )、有序集合( Sorted Set );
支持数据持久化,可以将内存中数据保存在磁盘中,重启时加载;
模式:主从复制,哨兵,高可用;
可以用作分布式锁;
可以作为消息中间件使用,支持发布订阅;
三大 Java 框架
Jedis:是 Redis 的 Java 实现客户端,提供了比较全面的 Redis 命令的支持
Redisson:实现了分布式和可扩展的 Java 数据结构;
Lettuce:高级 Redis 客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器;
三、概念
1.******数据类型
opsForValue:对应 String 字符串;
opsForHash:对应 Hash 哈希;
opsForList:对应 List 列表;
opsForSet:对应 Set 集合;
opsForZSet:对应 ZSet 有序集合;
2.******序列化
GenericToStringSerializer:可以将任何对象泛化为字符串并序列化;
Jackson2JsonRedisSerializer:序列化 Object 对象为 Json 字符串(与 JacksonJsonRedisSerializer 相同);
JdkSerializationRedisSerializer:序列化 Java 对象;
StringRedisSerializer:简单的字符串序列化;
3.缓存级别
页面级别缓存、对象级别缓存;
4.过期时间(设置 key 的有效时间)
设置过期时间:redisTemplate.expire(key, timeOut, TimeUnit.SECONDS);
移除过期时间:persist;
EXPIRE ---- 单位秒;
PEXPIRE ---- 单位毫秒;
EXPIREAT ---- 设置某时间戳,单位秒;
PEXPIREAT ---- 设置某时间戳,单位毫秒;
5.删除策略(key 过期后删除)
一.数据库分类
1.关系型数据库SQL
Oracle:不开源收费,高帅富;
SQL Server:不开源收费,微软自家的产品;
DB2:不开源收费,IBM 的产品;
Sybase:不开源收费,微软的小基友,关系破裂后家境惨淡;
MySQL:大家都在用;
PostgreSQL:学术气息有点重;
Sqlite:嵌入式数据库,适合桌面和移动应用;
2.非关系型数据库NoSQL(No SQL || Not Only SQL)
二、简介
内存数据库,C 语言开发的一个开源的超高性能 key-value 数据库,可以用作数据库、缓存、消息中间件等;
特性
性能优秀,数据在内存中,读写速度非常快,支持并发 10W QPS(每秒查询率,Queries-per-second );
单进程单线程,是线程安全的,采用 IO 多路复用机制;
Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value,支持字符串( String )、散列( Hash )、列表( List )、集合( Set )、有序集合( Sorted Set );
支持数据持久化,可以将内存中数据保存在磁盘中,重启时加载;
模式:主从复制,哨兵,高可用;
可以用作分布式锁;
可以作为消息中间件使用,支持发布订阅;
Jedis:是 Redis 的 Java 实现客户端,提供了比较全面的 Redis 命令的支持;
Redisson:实现了分布式和可扩展的 Java 数据结构;
Lettuce:高级 Redis 客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器;
三、概念
1.******数据类型
opsForValue:对应 String 字符串;
opsForHash:对应 Hash 哈希;
opsForList:对应 List 列表;
opsForSet:对应 Set 集合;
opsForZSet:对应 ZSet 有序集合;
2.******序列化
GenericToStringSerializer:可以将任何对象泛化为字符串并序列化;
Jackson2JsonRedisSerializer:序列化 Object 对象为 Json 字符串(与 JacksonJsonRedisSerializer 相同);
JdkSerializationRedisSerializer:序列化 Java 对象;
StringRedisSerializer:简单的字符串序列化;
3.缓存级别
页面级别缓存、对象级别缓存;
4.过期时间(设置 key 的有效时间)
设置过期时间:redisTemplate.expire(key, timeOut, TimeUnit.SECONDS);
移除过期时间:persist;
EXPIRE ---- 单位秒;
PEXPIRE ---- 单位毫秒;
EXPIREAT ---- 设置某时间戳,单位秒;
PEXPIREAT ---- 设置某时间戳,单位毫秒;
5.删除策略(key 过期后删除)
立即删除:主动删除,在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作,对 Cpu 不友好;
定期删除:主动删除,每隔一段时间,对 Expires 字典进行检查,删除里面的过期键,对 Cpu 不友好;
惰性删除:再次 get 的时候,如果 key 过期,则删除,返回 nil(类似于 null ),存在大量过期 key 占用空间;
定期+惰性+内存淘汰机制 :
每隔一段时间扫描部分 key,删除过期,
其余交给惰性,但这并不能删除干净,
使用内存淘汰机制,选择配置当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key;
四、安装
1.Windows
Redis 官网已经去掉了 Windows 版本链接,直接访问 Releases · microsoftarchive/redis · GitHub
下载 Redis-x64-3.2.100.zip,解压到本地文件夹;
配置
修改 redis.windows.conf 文件
指定访问 ip,建议本机可访问: bind 127.0.0.1
设置保护模式,建议开启:protected-mode yes
设置密码:requirepass ***
启动 Redis Server;
cd /d D:\Program Files\Redis
redis-server.exe redis.windows.conf
redis-server.exe redis.windows.conf
启动 Redis Client;
redis-cli.exe -h 127.0.0.1 -p 6379 || redis-cli.exe -h 127.0.0.1 -p 6379 -a 111111
ping ---- 响应 pong 表示服务端开启成功;
可视化工具:RedisDeskTop;
2.Linux
1.卸载
rpm -qa | grep redis
yum remove ***
yum list installed | grep redis
2.安装
---- 在线安装 ----
exit
get name
set name hujiang
reids-cli
netstat -an | grep 6379
ps -ef | grep redis
systemctl start | enable | status redis
yum install -y redis
3.配置
vi /etc/redis.conf
指定访问 ip,建议本机可访问: bind 127.0.0.1
设置保护模式,建议开启:protected-mode yes
设置密码:requirepass ***
systemctl restart redis
是否开放远程端口,建议不开启;
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
firewall-cmd --zone=public --remove-port=6379/tcp --permanent
firewall-cmd --zone=public --add-port=6379/tcp --permanent
Windows 端
输入 auth ***
redis-cli.exe -h 162.14.115.201 -p 6379
telnet 162.14.115.201 6379
五、命令
COMMAND KEY_NAME ---- 基本语法;
SET Key value ---- 设置 key-value;
get key ---- 查询 key-value;
TYPE key ---- 返回 key 所储存的值的类型;
DEL key ---- 删除 key-value;
DUMP key ---- 序列化给定 key ,并返回被序列化的值;
EXISTS key ---- 检查给定 key 是否存在;
EXPIRE key seconds ---- 为给定 key 设置过期时间,以秒计;
EXPIREAT key timestamp ---- 为给定 key 设置过期时间,时间参数是 UNIX 时间戳(unix timestamp);
PEXPIRE key milliseconds ---- 设置 key 的过期时间以毫秒计;
PEXPIREAT key milliseconds-timestamp ---- 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计;
KEYS pattern ---- 查找所有符合给定模式(pattern)的 key;
MOVE key db ---- 将当前数据库的 key 移动到给定的数据库 db 当中;
PERSIST key ---- 移除 key 的过期时间,key 将持久保持;
PTTL key ---- 以毫秒为单位返回 key 的剩余的过期时间;
TTL key ---- 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live);
RANDOMKEY ---- 从当前数据库中随机返回一个 key;
RENAME key newkey ---- 修改 key 的名称;
RENAMENX key newkey ---- 仅当 newkey 不存在时,将 key 改名为 newkey;
SCAN cursor [MATCH pattern] [COUNT count] ---- 迭代数据库中的数据库键;
set name HymanHu ---- 设置键值对;
get name ---- 根据 key 取值;
del name ---- 删除 key-value;
六、集群
1.环境需求
Redis 集群至少需要 3 个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以 2 个节点无法构成集群;至少6个节点,6个服务器
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以 Redis 集群至少需要 6 台服务器,因为我没有那么多服务器,也启动不了那么多虚拟机,所在这里搭建的是伪分布式集群;
安装 Ruby 语言环境(搭建 Redis 集群需要通过 gem install redis 来安装相关依赖,会用到 Ruby 脚本)
http://dl.bintray.com/oneclick/rubyinstaller/rubyinstaller-2.2.4-x64.exe;
2.主从模式
1.特点
数据库分两类:主数据库(master)、从数据库(slave) ;实例成倍增加
主数据库可以进行读写操作,主数据库会自动将数据同步给从数据库;
从数据库一般都是只读的,并且接收主数据库同步过来的数据;备份
一个 master 可以拥有多个 slave,但是一个 slave 只能对应一个 master;
slave 挂了不影响其他 slave 的读和 master 的读和写,重新启动后会将数据从 master 同步过来;
master 挂了以后,不影响 slave 的读,但 redis 不再提供写服务,master 重启后 redis 将重新对外提供写服务;
master 挂了以后,不会在 slave 节点中重新选一个 master;
主节点挂了后,从节点可以读,但不能写,只有master重启,从节点才能写
3.Windows 集群(一主二仆)
搭建一主二仆集群:master(6379)、slave(6380)、slave(6381);
将 Redis 文件解压为三份:Redis-6379、Redis-6380、Redis-6381;
修改集群配置 redis.windows.conf
6379 ---- 不做修改;
6380
6381
port 6381
slaveof 127.0.0.1 6379
启动 Redis 集群
方法一:由主到从依次启动;
方法二:编写 Windows 脚本启动;
::关闭bai回显,不显示正在执行的批处du理命令及执行的结果等
@echo off
echo redis start......
start "redis_6379" D:\Redis\Redis-6379/redis-server.exe D:\Redis\Redis-6379/redis.windows.conf
start "redis_6380" D:\Redis\Redis-6380/redis-server.exe D:\Redis\Redis-6380/redis.windows.conf
start "redis_6381" D:\Redis\Redis-6381/redis-server.exe D:\Redis\Redis-6381/redis.windows.conf
::让当前程序进程暂停一下,并显示一行信息:请按任意键继续......
::@pause
编辑
启动 6379 客户端查看主从信息:redis-cli.exe -p 7380 ---- info replication
启动 6380 查看客户端信息:redis-cli.exe -p 7380 ---- info replication
读写测试
主节点可读可写,数据同步到子节点,子节点可读不可写;
4.哨兵模式(Sentinel);
sentinel 模式是建立在主从模式的基础上,如果只有一个 Redis 节点,sentinel 就没有任何意义;
当 master 挂了以后,sentinel 会在 slave 中选择一个做为 master,并修改它们的配置文件,其他 slave 的配置文件也会被修改,比如 slaveof 属性会指向新的 master;
当 master 重新启动后,它将不再是 master 而是做为 slave 接收新的 master 的同步数据;
sentinel 因为也是一个进程有挂掉的可能,所以 sentinel 也会启动多个形成一个 sentinel 集群;
多 sentinel 配置的时候,sentinel 之间也会自动监控;
当主从模式配置密码时,sentinel 也会同步将配置信息修改到配置文件中,不需要担心;
一个 sentinel 或 sentinel 集群可以管理多个主从 Redis,多个 sentinel 也可以监控同一个 redis;
sentinel 最好不要和 Redis 部署在同一台机器,不然 Redis 的服务器挂了以后,sentinel 也挂了;
5.串行模式;
Redis 的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台 Redis 服务器都存储相同的数据,很浪费内存,所以在 Redis3.0 上加入了 Cluster 集群模式(分布式),实现了 Redis 的分布式存储,对数据进行分片,也就是说每台 Redis 节点上存储不同的内容;
多个 redis 节点网络互联,数据共享;
所有的节点都是一主一从(也可以是一主多从),其中从不提供服务,仅作为备用;
不支持同时处理多个 key(如MSET/MGET),因为 Redis 需要把 key 均匀分布在各个节点上;
并发量很高的情况下同时创建 Key-Value 会降低性能并导致不可预测的行为;
支持在线增加、删除节点;
客户端可以连接任何一个主节点进行读写;
串行处理:
七、spring Boot 应用
1.pom 依赖
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
2.配置
1.全局配置application.properties
# for Redis
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
#spring.redis.password=111111
spring.redis.timeout=300
# for Lettuce
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=10000
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100
2.RedisConfig.java
重写 redisTemplate :阅读 RedisAutoConfiguration.java 源码,该配置类中为我们配置了 RedisTemplate 和 StringRedisTemplate 两个 Bean,其中 RedisTemplate 泛型是两个 Object,对我们来说操作并不方便,会有类型转换的代码,RedisTemplate 更满足我们的需求,@ConditionalOnMissingBean(name = "redisTemplate") 注解也方便我们自定义 redisTemplate 来替换该 Bean;
定义 key-value 序列化方式:RedisTemplate 中 defaultSerializer 为 JdkSerializationRedisSerializer,并不方便数据传递,Key 采用 StringSerializer,Value 采用 JacksonSerializer 的方式更符合我们的需求,所以,我们需要重新定义 Key-Value 的序列化方式;
重新定义 CacheManager,因为我们改变了 Value 的序列化方式,CacheManager 也需要重新定义;
重新定义缓存 Key 的生成策略;
package com.sfac.springBoot.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Description Redis Config
* @Author HymanHu
* @Date 2021/2/24 13:46
*/
@Configuration
@EnableCaching // 启用缓存,使用 Lettuce,自动注入配置的方式
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport{
/**
* config RedisTemplate
*/
@Bean
@SuppressWarnings("all")
public RedisTemplate redisTemplate (RedisConnectionFactory factory){
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
// String 序列化方式
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// Jackson 序列化方式
Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSerializer.setObjectMapper(objectMapper);
// key 采用 stringSerializer,value 采用 jacksonSerializer
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(jacksonSerializer);
redisTemplate.setHashValueSerializer(jacksonSerializer);
return redisTemplate;
}
/**
* config CacheManager
*/
@Bean
@SuppressWarnings("all")
public CacheManager cacheManager(LettuceConnectionFactory factory) {
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
RedisSerializationContext.SerializationPair pair =
RedisSerializationContext.SerializationPair.fromSerializer(
new Jackson2JsonRedisSerializer(Object.class));
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
// default set
// RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
return new RedisCacheManager(writer, config);
}
// 重新定义缓存 key 的生成策略
@Bean
@Override
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());
Arrays.asList(params).stream().forEach(item -> {
sb.append(item.toString());
});
return sb.toString();
}
};
}
}
3. 应用
1.实现逻辑需求
用户连续错误登录三次,锁定账户15秒
存在哪里----------redis
存储内容? -------
key:username(唯一标识) +"loginErrorCount"
value:连续登录错误次数
如何锁定?
/login ----service
取得redis中的key和value,判断value是否大于三次,大于返回错误Result,无需进行登录
小于3次,进shiro认证和资源授权
如何判断连续登录错误3次
catch 代码块:
对redis该key进行自增1的操作,返回错误信息
判断value值是否大于3,如果大于3给该key设置一个过期时间,15秒。
2.实现
RedisUtils.java ---- 工具类,包装对各种数据类型的操作以及异常处理方法;
package com.sfac.springboot.utils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
/**
* @Description Redis Config
* @Author HymanHu
* @Date 2021/2/24 13:46
*/
@Component
public class RedisUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtils.class);
@Autowired
private RedisTemplate redisTemplate;
/**
* count > 0:从左到右删除等于value的第一个元素
* count = 0:删除等于value的所有元素
* count < 0:从右到左删除等于value的第一个元素
*/
public long removeListItem(String key, long count, Object value) {
try {
return redisTemplate.opsForList().remove(key, count, value);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public boolean updateListItem(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public boolean setList(String key, List list) {
try {
redisTemplate.opsForList().rightPushAll(key, list);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public boolean setListItem(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public Object getListItem(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return null;
}
}
public long getListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public List getListRang(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return null;
}
}
public long removeSetMembers(String key, Object... setValues) {
try {
return redisTemplate.opsForSet().remove(key, setValues);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public long setSetMembers(String key, long timeOut, Object... values) {
try {
long count = redisTemplate.opsForSet().add(key, values);
if (timeOut > 0) {
expire(key, timeOut);
}
return count;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public long setSetMembers(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public long getSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return 0;
}
}
public boolean isSetMember(String key, Object setValue) {
return redisTemplate.opsForSet().isMember(key, setValue);
}
public Set getSet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return null;
}
}
public boolean putHash(String key, Map hashObject,
long timeOut) {
try {
redisTemplate.opsForHash().putAll(key, hashObject);
if (timeOut > 0) {
expire(key, timeOut);
}
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public boolean putHash(String key, Map hashObject) {
try {
redisTemplate.opsForHash().putAll(key, hashObject);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public Map getHash(String key) {
return redisTemplate.opsForHash().entries(key);
}
@SuppressWarnings("all")
public void deleteHashItems(String key, String... hashKeys) {
redisTemplate.opsForHash().delete(key, hashKeys);
}
public boolean haveHahsKey(String key, String hashKey) {
return redisTemplate.opsForHash().hasKey(key, hashKey);
}
public double decrementHash(String key, String hashKey, double delta) {
return redisTemplate.opsForHash().increment(key, hashKey, -delta);
}
public double incrementHash(String key, String hashKey, double delta) {
return redisTemplate.opsForHash().increment(key, hashKey, delta);
}
public boolean putHashValue(String key, String hashKey, Object hashValue, long timeOut) {
try {
redisTemplate.opsForHash().put(key, hashKey, hashValue);
if (timeOut > 0) {
expire(key, timeOut);
}
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public boolean putHashValue(String key, String hashKey, Object hashValue) {
try {
redisTemplate.opsForHash().put(key, hashKey, hashValue);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public Object getHashValue(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
// 设置value递减
public long decrement(String key, long delta) {
if (delta < 1) {
throw new RuntimeException("Increment delta must great than 0.");
}
return redisTemplate.opsForValue().decrement(key, delta);
}
// 设置value递增
public long increment(String key, long delta) {
if (delta < 1) {
throw new RuntimeException("Increment delta must great than 0.");
}
return redisTemplate.opsForValue().increment(key, delta);
}
public boolean set(String key, Object value, long timeOut) {
try {
if (timeOut > 0) {
redisTemplate.opsForValue().set(key, value, timeOut, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().set(key, value);
}
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public Object get(String key) {
return StringUtils.isBlank(key) ? null : redisTemplate.opsForValue().get(key);
}
public void delete(String... key) {
if (null != key && key.length > 0) {
redisTemplate.delete(Stream.of(key).collect(Collectors.toList()));
}
}
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
// 设置过期时间
public boolean expire(String key, long timeOut) {
try {
if (timeOut > 0) {
redisTemplate.expire(key, timeOut, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
LOGGER.debug(e.getMessage());
return false;
}
}
}
注入redisTemplate,调用。
UserServiceImpl.java
4.redis锁定用户的功能
redis ----key,value
我们会对key和value都进行非空判断,当key为空,直接返回null,不会从redis查询;当value为空(从redis查不到数据) ,设置了默认值为0
流程:
service 对应的login方法:try中为正确的操作,catch中为错误的操作
//从redis中获得错误次数,超过最大次数,直接返回错误Resutl
获得subject
包装令牌
try{
subject.login();
subject.checkroles();
包装session数据
//把redis里面的错误次数置为0
返回正确的result
}catch{
//错误次数自增1,并且将结果存到redis
//判断错误次数是不是超过最大值,给redis中的key设置过期时间
返回错误的result
}