``先聊一下概念: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); } }
}`數據庫