文章目录
1.redis安装与测试
1.1 安装redis
下载Redis源码:
yum install wget
wget http://download.redis.io/releases/redis-6.0.5.tar.gz
解压:tar -zxf redis-6.0.5.tar.gz
进入解压目录:cd redis-6.0.5
因为新版的redis需要gcc较高版本 需要先安装或则升级gcc版本,在使用make编译
安装:yum -y install gcc
升级:
安装centos-release-scl
yum install centos-release-scl
安装 devtoolset
yum install devtoolset-9-gcc*
激活:
scl enable devtoolset-9 bash
通过gcc -v查看一下确认版本是9之后再去make
1.2 启动与连接
解压之后进入Redis目录,进入src目录下,使用 ./redis-server
启动,但是这样启动不会在后台运行,所以一般用以下方法启动:
在redis根目录创建一个config文件夹 mkdir config
把配置文件内容复制到config目录里面:
cat redis.conf | grep -v "#" | grep -v "^$" >> config/redis.conf //排除有#号的行和空行
打开redis.conf
修改: bing 0.0.0.0 //可以通过局域网(windows这边)去连接服务器了
daemonize yes //可以在后台运行
logfile "../config/redis.log" //日志文件
进行上述设置后,进入src目录下,使用 ./redis-server ../config/redis.conf
启动,现在会一直在后台运行,可以使用 ps -ef | grep redis
查看进程号,再使用 kill -9 进程号
关闭Redis。
使用 ./redis-cli -h IP -p 端口
连接服务器,可以不跟-h以及-P,默认就是本机IP以及6379端口。
windows连接Redis需要开放端口或者关闭防火墙
防火墙相关命令
查看防火墙状态 systemctl status firewalld
开启防火墙 systemctl start firewalld
查看所有已开放的临时端口 firewall-cmd --list-ports
查看所有已开放的临时端口 firewall-cmd --list-ports
查看所有永久开放的端口 firewall-cmd --list-ports --permanent
添加临时开放端口 firewall-cmd --add-port=80/tcp
添加永久开放的端口 firewall-cmd --add-port=80/tcp --permanent
关闭临时端口 firewall-cmd --remove-port=80/tcp
关闭永久端口 firewll-cmd --remove-port=80/tcp --permanent
配置结束后需要输入重载命令并重启防火墙以生效配置
firewall-cmd --reload
systemctl restart firewalld
2.redis命令
2.1 redis概述
Redis 是一个高性能的开源的、C语言写的Nosql(非关系型数据库),数据保存在内存中(快,容易丢失)。
Redis 是以key-value形式存储的Nosql,和传统的关系型数据库不一样。不一定遵循传统数据库的一些基本要求,比如说,不遵循sql标准,事务,表结构等等,非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
2.2 redis常用命令及场景
key命令
- set key value
- keys
- del
- rename
- keys
- exists
- persist
- 过期时间
- expire 设置过期时间
- persist 取消过期时间
- ttl(time to live) / pttl 查询过期时间
String命令
-
set 设置一个字符串
-
get 获取一个字符串
-
mset 设置多个
-
mget 获取多个
-
如果设置的字符串的值是数值,可以用命令来进行加减操作
incr、incrby 、decr、decrby、incrbyfloat -
strlen,substr …
使用场景:
- 存对象 json
- 计数器(访问人数、转发评论点赞、分布式自增id生成器)
- 倒数(秒杀、限速器)
- 分布式锁 http://redis.cn/topics/distlock.html
Hash命令
hash用于存储多个键值对,一个存储空间可以存储多个数据,一般可以使用hash来存储对象信息。
- hset key field1 value1 field2 value2 …
- hget key field
- hgetall key
- hmget key field1 field2 … fieldN
- hdel key field1 field2 … fieldN
- hlen key 查看某个key下有多少个属性
- hexists key field 查看某个key下是否存在某个属性
- hkeys key
- hvals key
使用场景:
- 短网址生成器
- 用户登录会话存储
- 存储对象
set命令
set也是用于存储多个数据的。
list和set的区别:
- list底层是双向链表,set的底层为hash,查询效率上来说,set优于list;
- list是有序的,set是无序的;
- list中元素是可重复出现的,set元素不允许重复;
- sadd
- srem / spop
- smembers
- sismember
- scard 长度
- sinter 交集 store
- sdiff 差集 store
- sunion 并集 store
- srandmember
使用场景:
- 随机展示 srandmember
- 黑名单/白名单
- 添加 sadd
- 是否在名单中 sismember
- 关注模型:
- 我的关注 sadd / smembers
- 我和好友的共同关注 交集 sinter(4)
- 我关注的人也关注了 差集 sdiff
- 唯一计数器:去重复的计数器
- sadd, scard
- 点赞、投票
- 随机点名
- 可以重复点名 srandmember
- 不会重复点名 spop
//共同关注例子
@RestController
@Api(tags = "关注相关接口")
public class AttentionController {
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/my")
@ApiOperation("关注某人")
public Result myFocus(String name){
SetOperations<String, String> sets = stringRedisTemplate.opsForSet();
sets.add("my",name);
return Result.success(200, "关注成功", null);
}
@GetMapping("/getMy")
@ApiOperation("我的所有关注")
public Result getMy(){
SetOperations<String, String> sets = stringRedisTemplate.opsForSet();
Set<String> my = sets.members("my");
return Result.success(200,"查询成功",my);
}
@GetMapping("/same")
@ApiOperation("共同关注")
public Result getSame(){
SetOperations<String, String> sets = stringRedisTemplate.opsForSet();
sets.intersectAndStore("my", "he", "same");
Set<String> same = sets.members("same");
return Result.success(200,"共同关注查询成功",same);
}
}
list命令
我们可以使用list来实现队列和栈的效果。
- lpush
- rpush
- lpop
- rpop
- lindex
- lrange
- lrem
- lset
- llen
使用场景:
- 队列:先进先出 FIFO
- 入队:LPUSH /RPUSH
- 出队:RPOP / LPOP
- 分页 lrange
- 微信朋友圈点赞 LPUSH
SortedSet命令(zset)
zset是基于set的实现,在set的基础上增加了score(分值)属性用于进行排序。
- zadd key score1 member1 score2 member2
- 取:是按照score分值数值进行排序
- 升序:zrange key start stop [withscores] 加上withscores,返回时会显示score分值
- 降序:zrevrange key start stop [withscores]
- zrem key member1 member2 …
- zremrangebyscore key min max 删除分值在某个区间之内的元素,min,max是分值
- zremrangebyrank key start stop 按索引进行删除
- zcard key 统计zset中的元素个数
使用场景
- 点击量最大的前十
- 添加 zadd
- 加分数 zincrby
- 查询排行 zrevrange
- 七日搜索榜单
- 时间线
- 优先级任务队列
3.集成SpringBoot
3.1 spring-data-redis
//1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
//2.配置
spring:
redis:
port: 6379
host: 192.168.152.136
//3.使用
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/my")
public Result myFocus(String name){
SetOperations<String, String> sets = stringRedisTemplate.opsForSet();
sets.add("my",name);
return Result.success(200, "关注成功", null);
}
3.2 redisson
1.单redis实例锁
加锁:
- set key value EX NX(必须是新增,如果该key存在则新增失败)
- key : 业务模块:ID 例如余额修改: balance:mod:1
- value: ip+线程号,确保解锁者是加锁者
- EX 设置过期时间,一定时间间隔后释放锁,防止死锁
- NX 限制为新增,达到锁效果
解锁:
- 先获取到锁,并且判定是否为当前加锁者,若是,则del key解锁
- 若否,抛异常让业务回滚
if( get(key).equals(ip+currentThreadId)){
//时间差,存在获取时是我的锁,删除时已经是别人的锁
del key
}else{
rollback;}
使用redis内置的lua脚本实现判断和删除的逻辑。因为redis执行lua脚本是阻塞的。保证操作的原子性。
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
2.多redis实例锁(redlock算法)
3.redisson分布式锁
//1.依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.19.1</version>
</dependency>
//2.配置
spring:
redis:
port: 6379
host: 192.168.152.136
//3.实现
@RestController
@Slf4j
public class LockController {
@Resource
private RedissonClient redissonClient;
@GetMapping("/charge")
public void charge(Integer mont) {
Integer userId = 1;
RLock lock = redissonClient.getLock("balance:mod:" + userId);
try {
log.info("尝试获取锁1");
lock.lock();
log.info("1加锁");
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
log.info("1解锁");
}
}
@GetMapping("/charge2")
public void charge1(Integer mont) {
Integer userId = 1;
RLock lock = redissonClient.getLock("balance:mod:" + userId);
try {
log.info("尝试获取锁2");
lock.lock();
log.info("2加锁");
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
log.info("2解锁");
}
}
}
3.3 spring-cache
//1.依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
//2.配置
spring
cache: #spring-cache配置
type: redis
redis:
time-to-live: 60s
//3.实现
@SpringBootApplication
@MapperScan(basePackages = {"com.woniuxy.dao"})
@EnableCaching
public class Linuxspringboot01Application {
public static void main(String[] args) {
SpringApplication.run(Linuxspringboot01Application.class, args);
}
}
@RestController
public class AccountController {
@Resource
private AccountService accountService;
@GetMapping("/account/{id}")
public Account getById(@PathVariable("id")Integer accountId){
Account account = accountService.findById(accountId);
return account;
}
@GetMapping("/modify/{id}")
public void modify(@PathVariable("id")Integer accountId,String nickName){
Account account = accountService.findById(accountId);
account.setAccountNickname(nickName);
accountService.modify(account);
}
@GetMapping("/del/{id}")
public void delAccount(@PathVariable("id")Integer accountId){
accountService.delAccount(accountId);
}
}
@Service
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountDao, Account> implements AccountService {
@Resource
private AccountDao accountDao;
//一定要有返回值,缓存是以返回值作为缓存的内容
@Cacheable(cacheNames = "userCache",key = "#accountId")
public Account findById(Integer accountId) {
log.info("从数据库查询用户:{}",accountId);
return this.getById(accountId);
}
@CachePut(cacheNames = "userCache",key = "#account.accountId")
public Account modify(Account account){
log.info("修改数据库:{}",account);
this.updateById(account);
return account;
}
@CacheEvict(cacheNames = "userCache",key = "#accountId")
public void delAccount(Integer accountId){
log.info("删除账号:{}",accountId);
}
}
4.上述过期时间都统一,可以用配置类单独修改
@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(200*1000, 60*1000));
return new RedissonSpringCacheManager(redissonClient, config);
}
}