redis07

redis的整合

 

引入依赖

1 <dependency>
2     <groupId>redis.clients</groupId>
3     <artifactId>jedis</artifactId>
4 </dependency>

 

redis的工具类,将redis的池初始化到spring容器中

 1 public class RedisUtil {
 2 
 3     private JedisPool jedisPool;
 4 
 5     public void initPool(String host,int port ,int database){
 6         JedisPoolConfig poolConfig = new JedisPoolConfig();
 7         poolConfig.setMaxTotal(200);
 8         poolConfig.setMaxIdle(30);
 9         poolConfig.setBlockWhenExhausted(true);
10         poolConfig.setMaxWaitMillis(10*1000);
11         poolConfig.setTestOnBorrow(true);
12         jedisPool=new JedisPool(poolConfig,host,port,20*1000);
13     }
14 
15     public Jedis getJedis(){
16         Jedis jedis = jedisPool.getResource();
17         return jedis;
18     }
19 
20 }

 

spring整合redis的配置类

 1 @Configuration
 2 public class RedisConfig {
 3     //读取配置文件中的redis的ip地址
 4     @Value("${spring.redis.host:disabled}")
 5     private String host;
 6     @Value("${spring.redis.port:0}")
 7     private int port ;
 8     @Value("${spring.redis.database:0}")
 9     private int database;
10     @Bean
11     public RedisUtil getRedisUtil(){
12         if(host.equals("disabled")){
13             return null;
14         }
15         RedisUtil redisUtil=new RedisUtil();
16         redisUtil.initPool(host,port,database);
17         return redisUtil;
18     }
19 }

 

application.properties

spring.redis.host=192.168.239.139

spring.redis.port=6379

spring.redis.database=0

 

 

缓存击穿

是某一个热点key在高并发访问的情况下,突然失效,导致大量的并发,引起mysql数据库压力瞬间增大,造成过大压力

 

击穿:在正常的访问情况下,如果缓存失效,如果保护mysql,重启缓存的过程,使用redis数据库的分布式锁,解决mysql的访问压力问题。

 

第一种分布式锁:redis自带一个分布式锁,set px nx

set sku:108:lock 1 px 600000 nx 

px 600000   过期时间

nx    分布式锁参数,只有不存在才能返回成功

 

第二种分布式锁:redisson框架,一个redis的带有juc的lock功能的客户端的实现(既有jedis的功能,又有juc的锁功能)

 

例:通过skuId查询skuInfo

 1  @Override
 2     public PmsSkuInfo getSkuById(String skuId) {
 3 
 4         PmsSkuInfo pmsSkuInfo = new PmsSkuInfo();
 5 
 6 
 7         //连接缓存,查询缓存
 8         Jedis jedis = redisUtil.getJedis();
 9 
10 
11         //没有缓存,查询mysql
12         String skuKey = "sku:"+skuId+":info";
13         String skuJson = jedis.get(skuKey);
14 
15         if (StringUtils.isNotBlank(skuJson)){
16             pmsSkuInfo = JSON.parseObject(skuJson, PmsSkuInfo.class);
17         }else {
18 
19             //设置分布式锁
20             String token = UUID.randomUUID().toString();
21             String OK = jedis.set("sku:" + skuId + ":lock", token, "nx", "px", 10*1000);
22             if (StringUtils.isNotBlank(OK)&&OK.equals("OK")){
23                 //设置成功,有权在10s内访问数据库
24                 pmsSkuInfo = getSkuByIdFromDb(skuId);
25 
26                 try {
27                     Thread.sleep(2000);
28                 } catch (InterruptedException e) {
29                     e.printStackTrace();
30                 }
31 
32                 if (pmsSkuInfo != null){
33                     //mysql存入redis
34                     jedis.set("sku:"+skuId+":info",JSON.toJSONString(pmsSkuInfo));
35                 }else {
              //数据库不存在该sku
36 //防止缓存穿透,值设为空字符串或null 37 jedis.setex("sku:"+skuId+":info",60*3,JSON.toJSONString("")); 38 } 39 40 String lockToken = jedis.get("sku:" + skuId + ":lock"); 41 if(StringUtils.isNotBlank(lockToken)&&lockToken.equals(token)){ //用token确认删除的是自己的锁 42 43 //在访问mysql后,将mysql的分布式锁删除 44 jedis.del("sku:" + skuId + ":lock"); 45 46 } 47 48 }else { 49 //设置失败,自旋(该线程在睡眠几秒后,重新尝试本方法) 50 return getSkuById(skuId); 51 } 52 53 } 54 jedis.close(); 55 56 return pmsSkuInfo; 57 58 }

49行中,如改为,则是错误的自旋

1                 //设置失败,自旋(该线程在睡眠几秒后,重新尝试本方法)
2                 try {
3                     Thread.sleep(3000);
4                 } catch (InterruptedException e) {
5                     e.printStackTrace();
6                 }
7                 
8                 getSkuById(skuId);

getSkuId(skuId) 表示又开新辟的线程重新进行访问,与原线程形成父子线程,

加入 return 后 ,return getSkuById(skuId) 表原线程重新进行访问

 

posted @ 2019-10-02 22:43  曲阳阳  阅读(160)  评论(0编辑  收藏  举报