``先聊一下概念:java
redis雪崩:redis中大面积的key同时过时,致使请求越过redis到mysql 数据库收到高流量冲击,挂掉mysql
redis穿透:redis 和mysql 都不存在查询的key,致使请求越过redis到mysql 数据库收到高流量冲击,挂掉redis
redis 击穿:redis 中key过时,,致使请求越过redis到mysql 数据库收到高流量冲击,挂掉spring
如何解决能够利用setnx 命令,下面的demo 用的是springData RedisTemplatesql
package com.test.one.springboottestpne.utils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /** * setNx 悲观锁 解决雪崩 击穿 穿透问题 * 事物+监听 解决秒杀 库存卖超问题。 */ @Component public class RedisLockTest extends Thread {
@Override public void run() { try { setNx(); } catch (InterruptedException e) { e.printStackTrace(); } } @Autowired StringRedisTemplate stringRedisTemplate; public String setNx() throws InterruptedException { System.out.println(Thread.currentThread().getName()+"开始获取缓存数据"); String key = stringRedisTemplate.opsForValue().get("key"); if (StringUtils.isNotBlank(key)){ System.out.println(Thread.currentThread().getName()+"开始获取缓存数据成功,返回"); return key; } System.out.println(Thread.currentThread().getName()+"获取缓存数据失败"); Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent("1", "1"); if (aBoolean){ System.out.println(Thread.currentThread().getName()+"拿到锁成功,从新设置缓存"); stringRedisTemplate.expire("1",1, TimeUnit.MINUTES); //处理业务逻辑 key = stringRedisTemplate.opsForValue().get("key"); if (StringUtils.isNotBlank(key)){ System.out.println(Thread.currentThread().getName()+"---------返回缓存数据"); stringRedisTemplate.delete("1"); return stringRedisTemplate.opsForValue().get("key"); } //模拟查询数据库 Thread.sleep(2000); stringRedisTemplate.opsForValue().set("key","11111111"); stringRedisTemplate.delete("1"); System.out.println(Thread.currentThread().getName()+"。。。。。。返回缓存数据"); return stringRedisTemplate.opsForValue().get("key"); }else { Thread.sleep(500); setNx(); } return null; }
package com.test.one.springboottestpne; import com.test.one.springboottestpne.utils.RedisLockTest; import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.test.context.junit4.SpringRunner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @RunWith(SpringRunner.class) @SpringBootTest(value = {"classpath:application.properties"}) public class RedisTest { @Autowired RedisLockTest redisLockTest; @Test public void redisLock() throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(100); for (int i = 0;i<100;i++){ executorService.submit(redisLockTest); } Thread.sleep(1000000); } }
}`数据库