1、商城项目商品服务三级分类缓存优化

2、新增redis分布式锁
3、新增redisson分布式锁
3、新增redis缓存配置
pull/254/head
xjs 4 years ago
parent 7495a0eca1
commit 77968524a9

@ -52,6 +52,7 @@
<webmagic.version>0.7.5</webmagic.version> <webmagic.version>0.7.5</webmagic.version>
<spring-cloud-alicloud-oss.version>2.2.0.RELEASE</spring-cloud-alicloud-oss.version> <spring-cloud-alicloud-oss.version>2.2.0.RELEASE</spring-cloud-alicloud-oss.version>
<elasticsearch.version>7.12.1</elasticsearch.version> <elasticsearch.version>7.12.1</elasticsearch.version>
<redisson.version>3.12.0</redisson.version>
</properties> </properties>
@ -114,6 +115,13 @@
<version>${elasticsearch.version}</version> <version>${elasticsearch.version}</version>
</dependency> </dependency>
<!--分布式锁,提供分布式对象等功能框架-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.xjs</groupId> <groupId>com.xjs</groupId>
<artifactId>xjs-business-common</artifactId> <artifactId>xjs-business-common</artifactId>

@ -9,26 +9,42 @@
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<name>公共模块-Redis模块</name> <name>公共模块-Redis模块</name>
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
<description> <description>
ruoyi-common-redis缓存服务 ruoyi-common-redis缓存服务
</description> </description>
<dependencies> <dependencies>
<!-- SpringBoot Boot Redis --> <!-- SpringBoot Boot Redis 排除lettuce客户端引入jedis客户端 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<!-- RuoYi Common Core--> <!-- RuoYi Common Core-->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

@ -1,10 +1,14 @@
package com.ruoyi.common.redis.configure; package com.ruoyi.common.redis.configure;
import cn.hutool.core.util.RandomUtil;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -27,7 +31,12 @@ import java.time.Duration;
*/ */
@Configuration @Configuration
@EnableCaching @EnableCaching
@EnableConfigurationProperties(CacheProperties.class)
public class RedisConfig extends CachingConfigurerSupport { public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private CacheProperties cacheProperties;
@Bean @Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"}) @SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
@ -66,10 +75,24 @@ public class RedisConfig extends CachingConfigurerSupport {
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om); jacksonSeial.setObjectMapper(om);
// 定制缓存数据序列化方式及时效 // 定制缓存数据序列化方式及时效
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofDays(1)) //时效1天
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer)) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial));
.disableCachingNullValues();
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
//将配置文件中所有的配置都生效
if (redisProperties.getTimeToLive() != null) {
//定义随机时间值,防止缓存大量过期
long salt = RandomUtil.randomLong(10, 100);
Duration time = redisProperties.getTimeToLive();
Duration plusSeconds = time.plusSeconds(salt);
config = config.entryTtl(plusSeconds);
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build(); RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build();
return cacheManager; return cacheManager;
} }

@ -0,0 +1,44 @@
package com.ruoyi.common.redis.configure;
import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Redisson
*
* @author xiejs
* @since 2022-04-08
*/
@Configuration
@ConfigurationProperties(prefix = "redisson")
@Data
public class RedissonConfig {
private String ip;
private Integer port;
/**
* Redisson 使 RedissonClient
*
* @return RedissonClient
*/
@Bean(destroyMethod = "shutdown",name = "redissonClient")
public RedissonClient redissonClient() {
// 1、创建配置
Config config = new Config();
// Redis url should start with redis:// or rediss://
config.useSingleServer().setAddress("redis://" + ip + ":" + port + "");
// 2、根据 Config 创建出 RedissonClient 实例
return Redisson.create(config);
}
}

@ -13,17 +13,17 @@ public class RedisConst {
/** /**
* key * key
*/ */
public static final String TRAN_DICT = "tianxing:tran_dict"; public static final String TRAN_DICT = "bussiness:tianxing:tran_dict";
/** /**
* key * key
*/ */
public static final String ONE_ENGLISH = "tianxing:one_english"; public static final String ONE_ENGLISH = "bussiness:tianxing:one_english";
/** /**
* key * key
*/ */
public static final String HOT = "tianxing:hot"; public static final String HOT = "bussiness:tianxing:hot";
/** /**
* websocketkey * websocketkey
@ -33,32 +33,32 @@ public class RedisConst {
/** /**
* ipkey * ipkey
*/ */
public static final String IP_INFO = "ip_info"; public static final String IP_INFO = "bussiness:ip_info";
/** /**
* key * key
*/ */
public static final String NOW_WEATHER = "weather:now"; public static final String NOW_WEATHER = "bussiness:weather:now";
/** /**
* key * key
*/ */
public static final String FORECAST_WEATHER = "weather:forecast"; public static final String FORECAST_WEATHER = "bussiness:weather:forecast";
/** /**
* _36wallpaper * _36wallpaper
*/ */
public static final String REPTILE_36_WALLPAPER_COUNT = "reptile:_36wallpaper.count"; public static final String REPTILE_36_WALLPAPER_COUNT = "bussiness:reptile:_36wallpaper.count";
/** /**
* weixin.sougou * weixin.sougou
*/ */
public static final String REPTILE_WEIXIN_SOUGOU_COUNT = "reptile:weixin.sougou.count"; public static final String REPTILE_WEIXIN_SOUGOU_COUNT = "bussiness:reptile:weixin.sougou.count";
/** /**
* weixin.link * weixin.link
*/ */
public static final String REPTILE_WEIXIN_LINK_COUNT = "reptile:weixin.link.count"; public static final String REPTILE_WEIXIN_LINK_COUNT = "bussiness:reptile:weixin.link.count";
//--------------------------mall-key----------------------------------- //--------------------------mall-key-----------------------------------
@ -78,6 +78,11 @@ public class RedisConst {
*/ */
public static final String CATALOG_BEFORE = MALL_PREFIX + "catalog:before"; public static final String CATALOG_BEFORE = MALL_PREFIX + "catalog:before";
/**
* Rediskey
*/
public static final String LOCK = "lock";
//-------------------有效时间----------------------- //-------------------有效时间-----------------------
public static final Integer TRAN_DICT_EXPIRE = 1; //小时 public static final Integer TRAN_DICT_EXPIRE = 1; //小时
@ -92,5 +97,7 @@ public class RedisConst {
public static final Long FORECAST_WHEATHER_EXPIRE = 10L; //分钟 public static final Long FORECAST_WHEATHER_EXPIRE = 10L; //分钟
public static final Long LOCK_EXPIRE = 30L; //秒
} }

@ -46,7 +46,7 @@ public class CopyWritingServiceImpl extends ServiceImpl<CopyWritingMapper, CopyW
*/ */
@Override @Override
//将该方法的查询结果存放阿紫springboot的默认缓存中 cacheNames缓存空间唯一名称 key缓存id //将该方法的查询结果存放阿紫springboot的默认缓存中 cacheNames缓存空间唯一名称 key缓存id
@Cacheable(cacheNames = "copyWriting",key = "#id") @Cacheable(cacheNames = "bussiness:copy_writing",key = "#id")
public CopyWriting selectCopyWritingById(Long id) public CopyWriting selectCopyWritingById(Long id)
{ {
return copyWritingMapper.selectCopyWritingById(id); return copyWritingMapper.selectCopyWritingById(id);
@ -71,7 +71,7 @@ public class CopyWritingServiceImpl extends ServiceImpl<CopyWritingMapper, CopyW
* @return * @return
*/ */
@Override @Override
@CacheEvict(cacheNames = "copyWriting",key = "#ids") @CacheEvict(cacheNames = "bussiness:copy_writing",key = "#ids")
public int deleteCopyWritingByIds(Long[] ids) public int deleteCopyWritingByIds(Long[] ids)
{ {
return copyWritingMapper.deleteCopyWritingByIds(ids); return copyWritingMapper.deleteCopyWritingByIds(ids);
@ -84,7 +84,7 @@ public class CopyWritingServiceImpl extends ServiceImpl<CopyWritingMapper, CopyW
* @return * @return
*/ */
@Override @Override
@CacheEvict(cacheNames = "copyWriting",key = "#id") @CacheEvict(cacheNames = "bussiness:copy_writing",key = "#id")
public int deleteCopyWritingById(Long id) public int deleteCopyWritingById(Long id)
{ {
return copyWritingMapper.deleteCopyWritingById(id); return copyWritingMapper.deleteCopyWritingById(id);

@ -10,6 +10,7 @@ import com.xjs.validation.group.UpdateGroup;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -85,6 +86,7 @@ public class CategoryController {
return R.ok(); return R.ok();
} }
@CacheEvict(value = {"mall:catalog"},key = "'getLevel1Categorys'")
@PutMapping("/update/sort") @PutMapping("/update/sort")
@ApiOperation("修改商品分类排序") @ApiOperation("修改商品分类排序")
@Log(title = "商品分类", businessType = BusinessType.UPDATE) @Log(title = "商品分类", businessType = BusinessType.UPDATE)
@ -99,6 +101,7 @@ public class CategoryController {
* *
*/ */
@DeleteMapping("/delete") @DeleteMapping("/delete")
@CacheEvict(value = {"mall:catalog"},key = "'getLevel1Categorys'")
@ApiOperation("删除") @ApiOperation("删除")
@Log(title = "商品分类", businessType = BusinessType.DELETE) @Log(title = "商品分类", businessType = BusinessType.DELETE)
public R delete(@RequestBody Long[] catIds) { public R delete(@RequestBody Long[] catIds) {
@ -106,6 +109,8 @@ public class CategoryController {
return R.error("请选择删除的分类"); return R.error("请选择删除的分类");
} }
categoryService.removeMenuByIds(Arrays.asList(catIds)); categoryService.removeMenuByIds(Arrays.asList(catIds));
//删除缓存
stringRedisTemplate.delete(Arrays.asList(CATALOG_BEFORE,CATALOG_AFTER));
return R.ok(); return R.ok();
} }

@ -3,6 +3,8 @@ package com.xjs.mall.product.controller.web;
import com.xjs.mall.product.entity.CategoryEntity; import com.xjs.mall.product.entity.CategoryEntity;
import com.xjs.mall.product.service.CategoryService; import com.xjs.mall.product.service.CategoryService;
import com.xjs.mall.product.vo.Catelog2Vo; import com.xjs.mall.product.vo.Catelog2Vo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -24,21 +26,49 @@ public class IndexController {
@Autowired @Autowired
private CategoryService categoryService; private CategoryService categoryService;
@Autowired
private RedissonClient redissonClient;
@GetMapping({"/", "index.html"}) @GetMapping({"/", "index.html"})
public String indexPage(Model model) { public String indexPage(Model model) {
//查出所有一级分类 //查出所有一级分类
List<CategoryEntity> categoryEntityList=categoryService.getLevel1Categorys(); List<CategoryEntity> categoryEntityList = categoryService.getLevel1Categorys();
model.addAttribute("categorys", categoryEntityList); model.addAttribute("categorys", categoryEntityList);
return "index"; return "index";
} }
@GetMapping("/index/json/catalog.json") @GetMapping("/index/json/catalog.json")
@ResponseBody @ResponseBody
public Map<String,List<Catelog2Vo>> getCatalogJson() { public Map<String, List<Catelog2Vo>> getCatalogJson() {
return categoryService.getCatalogJson(); return categoryService.getCatalogJson();
} }
@ResponseBody
@GetMapping("hello")
public String hello() {
//获取一把锁
RLock lock = redissonClient.getLock("my-lock");
//加锁
lock.lock(); //阻塞时等待默认假的锁是30s时间
//锁的自动续期如果业务超长运行期间自动给锁续期30s不用担心业务时间长锁自动过期被删除
//加锁的业务只要 运行完成就不会给当前锁续期即使不手动解锁锁默认在30s以后过期
try {
System.out.println("加锁成功" + Thread.currentThread().getName());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("释放锁" + Thread.currentThread().getName());
lock.unlock();
}
return "hello";
}
} }

@ -17,21 +17,28 @@ import com.xjs.mall.product.service.AttrService;
import com.xjs.mall.product.service.CategoryBrandRelationService; import com.xjs.mall.product.service.CategoryBrandRelationService;
import com.xjs.mall.product.service.CategoryService; import com.xjs.mall.product.service.CategoryService;
import com.xjs.mall.product.vo.Catelog2Vo; import com.xjs.mall.product.vo.Catelog2Vo;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.xjs.consts.RedisConst.CATALOG_AFTER; import static com.xjs.consts.RedisConst.*;
import static com.xjs.consts.RedisConst.CATALOG_BEFORE;
@Service("categoryService") @Service("categoryService")
@Transactional @Transactional
@Log4j2
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService { public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
@Resource @Resource
@ -49,6 +56,9 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
@Autowired @Autowired
private AttrService attrService; private AttrService attrService;
@Resource
private RedissonClient redissonClient;
@Override @Override
public List<CategoryEntity> listWithTree() { public List<CategoryEntity> listWithTree() {
@ -111,7 +121,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
categoryDao.deleteBatchIds(asList); categoryDao.deleteBatchIds(asList);
//删除后清除缓存 //删除后清除缓存
stringRedisTemplate.delete(Arrays.asList(CATALOG_BEFORE,CATALOG_AFTER)); stringRedisTemplate.delete(Arrays.asList(CATALOG_BEFORE, CATALOG_AFTER));
} }
@Override @Override
@ -126,6 +136,7 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
} }
@Override @Override
@CacheEvict(value = {"mall:catalog"},key = "'getLevel1Categorys'")
public void updateCascade(CategoryEntity category) { public void updateCascade(CategoryEntity category) {
//更新自己 //更新自己
super.updateById(category); super.updateById(category);
@ -134,10 +145,11 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
categoryBrandRelationService.updateCategory(category.getCatId(), category.getName()); categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
//删除缓存 //删除缓存
stringRedisTemplate.delete(Arrays.asList(CATALOG_BEFORE,CATALOG_AFTER)); stringRedisTemplate.delete(Arrays.asList(CATALOG_BEFORE, CATALOG_AFTER));
} }
@Override @Override
@Cacheable(value = {"mall:catalog"},key = "#root.method.name",sync = true) //sync同步会锁方法单机锁
public List<CategoryEntity> getLevel1Categorys() { public List<CategoryEntity> getLevel1Categorys() {
LambdaQueryWrapper<CategoryEntity> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<CategoryEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CategoryEntity::getParentCid, 0); wrapper.eq(CategoryEntity::getParentCid, 0);
@ -146,14 +158,19 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
@Override @Override
public Map<String, List<Catelog2Vo>> getCatalogJson() { public Map<String, List<Catelog2Vo>> getCatalogJson() {
/**
* 1穿
* 2
* 3穿
*/
//先查缓存 //先查缓存
String catalogJSON = stringRedisTemplate.opsForValue().get(CATALOG_BEFORE); String catalogJSON = stringRedisTemplate.opsForValue().get(CATALOG_BEFORE);
if (StringUtils.isEmpty(catalogJSON)) { if (StringUtils.isEmpty(catalogJSON)) {
//缓存没有查数据库并且放入
Map<String, List<Catelog2Vo>> catalogJsonFormDb = this.getCatalogJsonFormDb(); return this.getCatalogJsonFormDbWithRedissonLock();
String jsonString = JSON.toJSONString(catalogJsonFormDb);
stringRedisTemplate.opsForValue().set(CATALOG_BEFORE, jsonString);
return catalogJsonFormDb;
} else { } else {
return JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() { return JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() {
}); });
@ -161,13 +178,19 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
} }
//可优化
private Map<String, List<Catelog2Vo>> getCatalogJsonFormDb() { private Map<String, List<Catelog2Vo>> getCatalogJsonFormDb() {
//获取锁之后再去缓存确认,如果没有就继续查询
String catalogJSON = stringRedisTemplate.opsForValue().get(CATALOG_BEFORE);
if (StringUtils.isNotEmpty(catalogJSON)) {
return JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catelog2Vo>>>() {
});
}
//查出所有1级分类 //查出所有1级分类
List<CategoryEntity> level1Categorys = getLevel1Categorys(); List<CategoryEntity> level1Categorys = getLevel1Categorys();
//封装数据 //封装数据
return level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> { Map<String, List<Catelog2Vo>> collect = level1Categorys.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
//每一个的一级分类,查到这个一级分类的二级分类 //每一个的一级分类,查到这个一级分类的二级分类
List<CategoryEntity> categoryEntities = super.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>().eq(CategoryEntity::getParentCid, v.getCatId())); List<CategoryEntity> categoryEntities = super.baseMapper.selectList(new LambdaQueryWrapper<CategoryEntity>().eq(CategoryEntity::getParentCid, v.getCatId()));
@ -195,6 +218,83 @@ public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity
return catelog2Vos; return catelog2Vos;
})); }));
//缓存没有查数据库并且放入
String jsonString = JSON.toJSONString(collect);
stringRedisTemplate.opsForValue().set(CATALOG_BEFORE, jsonString);
return collect;
}
//使用redisson分布式锁
private Map<String, List<Catelog2Vo>> getCatalogJsonFormDbWithRedissonLock() {
RLock lock = redissonClient.getLock(LOCK + ":catalog");
lock.lock();
log.info("获取分布式锁成功");
Map<String, List<Catelog2Vo>> catalogJsonFormDb;
try {
catalogJsonFormDb = getCatalogJsonFormDb();
} finally {
lock.unlock();
}
return catalogJsonFormDb;
}
//使用Java本地可重入锁synchronized
private Map<String, List<Catelog2Vo>> getCatalogJsonFormDbWithSynLock() {
//加锁,解决缓存击穿 (本地锁/单机锁 分布式服务锁不住)
synchronized (this) {
return this.getCatalogJsonFormDb();
}
}
//使用redis分布式锁
private Map<String, List<Catelog2Vo>> getCatalogJsonFormDbWithRedisLock() {
//加锁,解决缓存击穿 分布式锁 去redis占坑
String uuid = UUID.randomUUID().toString(); //添加唯一标识符
Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(LOCK, uuid, LOCK_EXPIRE, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(lock)) {
log.info("获取分布式锁成功:{}", uuid);
Map<String, List<Catelog2Vo>> catalogJsonFormDb = null;
try {
catalogJsonFormDb = this.getCatalogJsonFormDb();
} finally {
//lua脚本解锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Long ret = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(LOCK), uuid);
}
//加锁成功
//设置过期时间必须和加锁同步(原子性)
//stringRedisTemplate.expire(LOCK, LOCK_EXPIRE, TimeUnit.SECONDS);
//删除锁(判断是否是自己的锁)
/*String lockValue = stringRedisTemplate.opsForValue().get(LOCK);
if (uuid.equals(lockValue)) {
stringRedisTemplate.delete(LOCK);
}*/
return catalogJsonFormDb;
} else {
log.warn("获取分布式锁失败:{}", uuid);
//加锁失败...重试 自旋
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.getCatalogJsonFormDbWithRedisLock();
}
} }
//225,25,2 //225,25,2

Loading…
Cancel
Save