您现在的位置是:首页 >其他 >springboot使用redisson实现分布式锁网站首页其他
springboot使用redisson实现分布式锁
简介springboot使用redisson实现分布式锁
一、前言
在实际项目中,某些场景下可能需要使用到分布式锁功能,那么实现分布式锁有多种方式,常见的如mysql分布式锁、zookeeper分布式锁、redis分布式锁,从效率上讲,redis无疑是性能最好的,但也会存在一些问题
1.获取锁的线程在执行任务的过程中挂掉,来不及释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来,因此我们需要给key加个过期时间,保证这把锁要在一定时间后自动释放。
2.高并发情况下redis分布式锁永久失效 的问题(一个线程可能删除了别的线程的锁)
假设线程 A 可能某些原因执行的很慢很慢,到达过期时间都没执行完,这时候锁过期自动释放,此时线程 B 得到了锁;
随后,线程 A 执行完了任务,线程 A 随之释放锁。但这时候线程 B 还没执行完,线程A实际上 删除的是线程 B加的锁
解决方法:
可以在 释放锁之前做一个判断,验证当前的锁是不是自己加的锁
3.可能出现并发情况
当线程 A 执行的很慢很慢,到达过期时间都没执行完,这时候锁过期自动释放,线程 B得到了锁。此时就有多个线程在访问同步代码块。
解决方法:我们可以使用redisson实现,内部实现锁续期功能。
二、实现
1.在springboot中引入redisson依赖包
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.10.6</version>
</dependency>
2.配置redisson,代码如下:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
@Configuration
public class RedissonConfig {
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException{
//RedissonClient redisson = Redisson.create(Config.fromYAML(new //ClassPathResource("redisson-single.yml").getInputStream()));
Config config = new Config();
config.useSingleServer()
.setAddress("redis://192.168.6.52:6379").setPassword("123456")
.setRetryInterval(5000)
.setTimeout(10000)
.setConnectTimeout(10000);
return Redisson.create(config);
}
}
3.我们以商品库存为例:
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.suntree.entity.Price;
import com.suntree.mapper.PriceMapper;
@Service
public class ProductService {
@Autowired
RedissonClient redissonClient;
@Autowired
ProductMapper productMapper;
@Transactional
public String descreaseProduct(String productId,Integer quanlity) {
String key="des_product_lock:"+productId;
RLock lock=redissonClient.getLock(key);
lock.lock();
Product product =productMapper.selectById(productId);
if(product ==null) {
return "产品未找到";
}
String result="";
try {
if(product .getQuanlity()==0) {
return "当前数量为0,不能再扣了!!";
}
product .setQuanlity(product .getQuanlity()-1);
productMapper.updateById(product );
result = "当前数量:" + product .getQuanlity();
System.err.println(result);
}catch (Exception e) {
System.err.println(e.getMessage());
throw new RuntimeException("扣库存操作失败了");
}finally {
lock.unlock();
}
return result;
}
}
这就是实现分布式锁常见场景。
4.接着我们可以在controller层调用,我们可以模拟多线程操作,看扣库存是否会有问题。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.suntree.service.ProductService ;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
ProductService productService ;
@GetMapping("/descrease")
public String descreaseProduct() {
return productService .descreaseProduct("2020-2020", 200);
}
}
大家可以自己尝试下。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。