当前位置 博文首页 > wyn-365:会会大厂面试官四-----Redis-Springboot+redisson【实
1.JVM层面的锁
2.分布式微服务架构,拆分后各个微服务之间为了避免冲突和数据故障而加入的一种锁。
3.显示方案:zookeeper mysql redis【推荐】–redlock----redisson lock/unlock
使用场景:多个服务之间,同一时刻,同一个用户只能有一个请求,防止关键业务数据冲突和并发错误。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pools</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
# 第一个模块的配置,第二个修改端口号就好2222
server.port=1111
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
@Configuration
public class RedisConfig{
@Bean
public RedisTemplate<String,Serializable> redisTemplate(lettuceConnectionFactory connectionFactory){
new RedisTemplate<String,Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
@RestController
public class GoodController{
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Value("${server.port}")
private String serverPort;
@GetMapping("/buy_Goods")
public String buy_Goods(){
// 1.查看库存数量
String result = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNumber = result == null ? 0 : Interger.parseInt(result);
// 2.卖商品
if(goodsNumber > 0){
int realNumber = goodsNumber - 1;
// 3.成功买入,库存减少一件
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNumber));
return "成功买入商品,库存还剩下:"+realNumber+"服务端口:"+serverPort;
}else{
System.out.println("商品卖完"+"服务端口:"+serverPort);
}
return "商品卖完!"+"服务端口:"+serverPort;
}
}
# 放入001库存100个
set goods:001 100
单机版没有枷锁100%故障的,没有原子性,多线程下没有枷锁是不可以的。
关键字,拿不到商品不走,容易造成线程积压,卡在外面,时间比较久。
@GetMapping("/buy_Goods")
public String buy_Goods(){
// 加锁
synchronized(this){
// 1.查看库存数量
String result = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNumber = result == null ? 0 : Interger.parseInt(result);
// 2.卖商品
if(goodsNumber > 0){
int realNumber = goodsNumber - 1;
// 3.成功买入,库存减少一件
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNumber));
return "成功买入商品,库存还剩下:"+realNumber+"服务端口:"+serverPort;
}else{
System.out.println("商品卖完"+"服务端口:"+serverPort);
}
return "商品卖完!"+"服务端口:"+serverPort;
}
}
类 ,try lock,时间内抢的到就去抢,抢不到就走人。
private final Lock lock = new ReentrantLock();
@GetMapping("/buy_Goods")
public String buy_Goods(){
// 加锁,抢锁3S小规模等待
try(lock.tryLock(3L,TimUnit.SECONDS)){
lock.lock();
...
}finally{
lock.unlock();
}else{
}
}
单机版的解决不了的,需要加入分布式锁
# 权重一半一半
vi nginx.conf
测试访问nginx
192.168.11.147/buy_goods
似乎轮询策略没有发现神魔问题。
压测:1S中100个线程进行并发访问
结果:发现了严重的超卖现象,单机版的锁是控制不住问题的。
Redis性能极高,岁分布式锁的支持比较优秀。
public static final String REDIS_LOCK = "atguiguLock";
@GetMapping("/buy_Goods")
public String buy_Goods(){
String value = UUID.randomUUID().toString()+Thread.currentThread().getName();
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(REDIS_LOCK,value);
// 加锁不成功
if(!flag){
return "抢锁失败";
}
String result = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNumber = result == null ? 0 : Interger.parseInt(result);
// 2.卖商品
if(goodsNumber > 0){
int realNumber = goodsNumber - 1;
// 3.成功买入,库存减少一件
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNumber));
// 4.解锁
stringRedisTemplate.delete(REDIS_LOCK);
return "成功买入商品,库存还剩下:"+realNumber+"服务端口:"+serverPort;
}else{
System.out.println("商品卖完"+"服务端口:"+serverPort);
}
return "商品卖完!"+"服务端口:"+serverPort;
}