Redis常见问题整理(持续更新)

redis是什么?
Redis 是一个基于内存的高性能key-value数据库,将数据加载到内存中,读写效率高于硬盘。

Nosql数据库的优势
1)易扩展
这些类型的数据存储不需要固定的模式,无需多余的操作就可以进行横向的扩展。相对于关系型数据库可以减少表和字段特别多的情况。也无型之间在架构的层面上带来了可扩展的能力
2)大数据量提高性能
3)多样灵活的数据模型

使用redis有哪些好处?
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2)支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

** 支持数据类型**
支持的数据类型:字符串、hash、列表List、set、sorted set
①、字符串:
存:set 键 值
取:get 键
重点方法:
setnx 键 值 →分布式锁重要的方法:当改建不存在时候,进行写操作返回1.当改键存在时,不进行写操作,返回值为0

②、Hash:
存:HMSET 键 字段1 值1 字段2 值2 。。。。。。
取:HGETALL 键
③、List:
存:lpush 键 值1 值2 。。。。。
lpush 键 值3
取:lrange 键 开始下标(从0开始) 结束下标
④、Set:
存:sadd 键 值1 值2 。。。。。
sadd 键 值3
取:smembers 键
⑤、sorted Set
存:zadd 键 下标 值
zadd 键 下标 值
取:zrange 键 起始位置(从0开始) 结束位置 withscores

什么是Redis持久化
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

**
分布式锁
java锁在分布式系统中并不是完全有效的,那么要解决高并发的线程安全问题就需要用分布式锁。

①setnx key  值
②用户1  执行操作  setnx返回值为1  说明该键不存在,可以进行mysql的更新操作
③用户2  自行操作  setnx返回值为0  已经有用户正在执行操作,不能进行mysql更新操作
④用户1 执行完之后  删除  键 key  (del key)让用户2可以继续操作

上面是一个Redis分布式锁的一个简单的操作

***会遇到的问题(死锁):如果用户1在执行操作的时候 程序挂掉了,没有进行 删除键的操作,让后续用户无法正常进行。怎么办?

在②步中:
(1)如果直接获取了锁,就进行后续操作
(2)如果没有获取到锁,需要判断这个锁是否为死锁

把这个锁的值变成 long类型的 currentTime(当前时间) ,给这个锁定义一个死锁时间(超时时间),比如1000ms
(执行一个操作最多1秒钟)

具体方法→①用户1拿到锁的时候 setnx key(锁) currentTime +1000ms 把key 的值 设置成 当前时间加一个自己定义的超时时间 *(currentTime +1000ms = timeout ) *
②用户2 如果拿不到锁(返回值为0) get key(锁) =long timeout 拿到这个值
③和当前系统时间比较 如果 currentTime >= timeout ;说明锁已经出现死锁

④执行 get key(锁)= new timeout 并且 set key(锁)=currentTime + 1000ms
如果 new timeout >当前时间currentTime 说明这个锁已经被其他用户拿走,被其他用户get到并且重新set了一个超时时间,继续循环;
如果 new timeout <当前时间currentTime 说明这个锁还是死锁,我是在死锁后面的第一个用户,我可以拿走并进行数据库的操作然后 删除 键 key ;

有点难理解,拿个图来解释

timeout  =  currentTime  +  1000ms =1000

用户2
if(setnx key = 0 拿不到锁){
		get key  =long timeout = 1000;
		currentTime  = 1500;
		if(currentTime >= timeout){
					get key = timeout = 1000;
					set key = currenTime(1500) + 1000ms = 此时的 new timeout等于2500
						if(  new timeout> timeout){
								2500 > 1000
									拿到锁并且执行走出这个循环 执行数据库的操作 然后删除key;
						}
		}
}

用户3
if(setnx key = 0 拿不到锁){
		get key  =long timeout = 1000;
		currentTime  = 1500; //设定极端情况与上一个用户同一时间抢锁
		if(currentTime >= timeout){
		get key = new timeout = 2500  //此时的new timout  已经被上个用户修改成2500
		set key = currenTime(1500) + 1000ms = 此时的 new timeout等于2500
					if(new timeout> timeout){
						2500  >  2500 不成立所以 拿不到锁 继续循环
				}
		}
}

**
Session共享

pom中引入该依赖

		<dependency>  
				<groupId>org.springframework.boot</groupId>  
				<artifactId>spring-boot-starter-redis</artifactId>
				<version>1.4.0.RELEASE</version>
		</dependency>  
		<dependency>  
				<groupId>org.springframework.session</groupId>  
				<artifactId>spring-session-data-redis</artifactId>  
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session</artifactId>
			<version>1.3.3.RELEASE</version>
		</dependency>

添加redis配置
在这里插入图片描述

添加一个配置类

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3000)
public class SessionConfig {
}

简单的Controller 测试类

@RestController  
@RequestMapping(value = "/")
public class Hello {  
    @RequestMapping(value = "/set", method = RequestMethod.GET)  
    public Map<String, Object> firstResp (HttpServletRequest request){           
        request.getSession().setAttribute("Testkey", "Session");

        Map<String, Object> map = new HashMap<>(); 
        map.put("Testkey", "Session");  
        return map;
    }
  
    @RequestMapping(value = "/query", method = RequestMethod.GET)  
    public Object sessions (HttpServletRequest request){
        Map<String, Object> map = new HashMap<>();
        map.put("sessionId", request.getSession().getId());
        map.put("Testkey", request.getSession().getAttribute("Testkey"));
        return map;
    }
} 

**
Redis缓存

POM依赖

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
   <exclusions>
    <exclusion>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </exclusion>
    <exclusion>
        <groupId>io.lettuce</groupId>
        <artifactId>lettuce-core</artifactId>
    </exclusion>
   </exclusions>
 </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!--  cache -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <!--  redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>

application配置

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=123456
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=10
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=5
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=1
# 连接超时时间(毫秒)
spring.redis.timeout=2000
#开启缓存
spring.cache.type=redis

spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.url=jdbc:mysql://localhost:3306/permission?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

Service层

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    UserMapper userMapper;

    @Cacheable(cacheNames = "userById",key="#userId")
    @Override
    public User selectById(int userId) {
        return userMapper.selectById(userId);
    }
}

启动类

@EnableCaching
@SpringBootApplication
@MapperScan("com.miro.dao")
public class SpringbootRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootRedisApplication.class, args);
    }

}

Controller层

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserServiceImpl userService;

    @RequestMapping("getUser")
    public User getUser(int userId){

        return userService.selectById(userId);
    }

}

在这里插入图片描述
再进行增删改操作的时候加CacheEvict(cacheNames=“”,allEntries=true) 会将缓存数据删除,下次查询时会从数据库查询数据


缓存穿透
当查询到一个数据在缓存中一定不存在时,如果对这个数据进行高频率的读操作,相当于大量请求进入到了数据库。当查询出的数据为NULL时,就把这个NULL作为数据缓存到redis中。

缓存击穿
访问量巨大的热点数据失效
利用其它缓存再缓存一次数据,例如mybatis缓存额外缓存一下。

缓存雪崩
指所有的缓存数据同时失效,所有的请求直接进入数据库,造成数据库宕机。
解决方案:可以将缓存数据的失效时间设置为不一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用提到了Redis启动的闪退问题,引用介绍了两种启动Redis的方法,但都会导致闪退。下面我将总结一些常见的Redis启动问题。 1. Redis配置错误:启动Redis时,如果配置文件有错误或者缺少必要的配置,可能会导致启动失败。可以检查redis.conf文件中的配置是否正确,并确保所有必要的配置项都被设置。 2. 端口被占用:如果Redis要使用的端口已经被其他程序占用,那么Redis启动时会失败。可以通过检查端口占用情况,或者修改Redis配置文件中的端口号来解决该问题。 3. 内存不足:Redis需要一定的内存来运行,如果系统内存不足,可能会导致Redis启动失败。可以通过增加系统内存或者减少Redis的内存使用来解决该问题。 4. 权限问题:如果Redis的执行文件或者配置文件没有足够的权限,可能会导致启动失败。可以检查文件的权限设置,并确保Redis所在的目录对当前用户有足够的访问权限。 5. 版本兼容性问题:在某些情况下,Redis的版本与操作系统或其他依赖软件之间存在兼容性问题,可能会导致启动失败。可以尝试升级或降级Redis版本,或者解决相关的依赖冲突来解决该问题。 需要注意的是,这只是一些常见的Redis启动问题,具体问题可能因环境和配置的不同而有所差异。如果还遇到其他问题,建议查看Redis的文档或社区中的解决方案,或者尝试搜索类似的问题和解决方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [windows下Redis启动闪退问题解决经验汇总](https://blog.csdn.net/httpmc2018/article/details/121082182)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [redis 常见问题](https://blog.csdn.net/u013743253/article/details/124093790)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值