本文是向大家介绍项目中如何快速使用redis实现分布式锁,落地实现步骤。
简介
实现分布式锁有多种方式,常见redis,zookeeper,数据库等多种方式实现,由于redis实现相对简单快捷,所以本次分享聚焦redis分布式锁实现方式,下面我们介绍下在我们实际项目已经正式落地的实现方式。具体方案见如下。
方案1. spring-integration中redis分布锁
spring-integration对redis分布锁的支持,底层应该也是lua脚本的实现,可完美解决线程挂掉造成的死 锁,以及执行时间过长锁释放掉,误删别人的锁。不适用redis集群,(可用于阿里云redis,阿里云redis相当于单机)
使用步骤:
第一步:引入jar
<!-- redis分布式锁 begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <!-- redis分布式锁 end-->
第二步:配置redisLockRegistry
@Configuration public class RedisLockConfiguration { @Bean public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) { return new RedisLockRegistry(redisConnectionFactory, "mfbizcore:redis_lock"); } }
第三步:配置文件
#Redis服务器地址 spring.redis.host=127.0.1.1 #Redis服务器连接密码 spring.redis.password=123456 #Redis服务器连接端口 spring.redis.port=30079 spring.redis.database=1 #连接池最大连接数 spring.redis.pool.maxActive=8 #连接池最大阻塞等待时间 spring.redis.pool.maxWait=-1 #连接池中的最大空闲连接 spring.redis.pool.maxIdle=8 #连接池中的最小空闲连接 spring.redis.pool.minIdle=0 #连接超时时间(毫秒) spring.redis.timeout=10000
第四步:分布式锁使用示例
@Autowired private RedisLockRegistry redisLockRegistry; // 省略 Lock lock = redisLockRegistry.obtain(redisLockKey); if(!lock.tryLock()){ //加锁失败 LOGGER.info("当前用户:{},已有扣款流程正在处理中,redis锁key{}",userId,redisLockKey); return false; } try{ // 省略业务 }finally{ if (lock != null) { //释放锁 lock.unlock(); LOGGER.info("当前用户:{},扣款流程结束,进行锁释放操作,redis锁key:{}",userId,redisLockKey); } }
方案2. Redission分布式锁 (可用于集群)
Redission是Redis官方推荐的客户端,提供了一个RLock的锁,RLock继承自juc的Lock接口,提供了中断,超时,尝试获取锁等操作,支持可重入,互斥等特性。
使用步骤:
第一步:引入依赖包
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.11.2</version> </dependency>
第二步:配置redission
@Configuration public class RedissonConfig { @Autowired private RedisConfigProperties redisConfigProperties; //添加redisson的bean @Bean public Redisson redisson() { //redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加 List<String> clusterNodes = new ArrayList<>(); for (int i = 0; i < redisConfigProperties.getCluster().getNodes().size(); i++) { clusterNodes.add("redis://" + redisConfigProperties.getCluster().getNodes().get(i)); } Config config = new Config(); ClusterServersConfig clusterServersConfig = config.useClusterServers() .addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()])); clusterServersConfig.setPassword(redisConfigProperties.getPassword());//设置密码 return (Redisson) Redisson.create(config); } } @Component @ConfigurationProperties(prefix = "spring.redis") public class RedisConfigProperties { private String password; private cluster cluster; public static class cluster { private List<String> nodes; public List<String> getNodes() { return nodes; } public void setNodes(List<String> nodes) { this.nodes = nodes; } } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public RedisConfigProperties.cluster getCluster() { return cluster; } public void setCluster(RedisConfigProperties.cluster cluster) { this.cluster = cluster; } }
第三步:使用示例
@Autowired private Redisson redisson; @GetMapping("/test4") public void test4() { String stockKey = "product_1001"; RLock lock = redisson.getLock(stockKey); try { // 加锁 lock.lock(); int stock = Integer.parseInt(redisTemplate.opsForValue().get("stock")); if (stock > 0) { int realStock = stock -1; redisTemplate.opsForValue().set("stock", String.valueOf(realStock)); System.out.println("扣减成功,剩余库存:" + realStock); } else { System.out.println("扣减失败,库存不足"); } } finally { // 释放锁 lock.unlock(); } }
本文含有隐藏内容,请 开通VIP 后查看