redis分散式鎖學習之路1-RedisTemplate實現分散式鎖
阿新 • • 發佈:2020-08-12
1. pom檔案
1 <parent> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-parent</artifactId> 4 <version>2.1.4.RELEASE</version> 5 <relativePath/> <!-- lookup parent from repository --> 6 </parent> 7View Code8 <dependencies> 9 <dependency> 10 <groupId>org.springframework.boot</groupId> 11 <artifactId>spring-boot-starter-web</artifactId> 12 </dependency> 13 <dependency> 14 <groupId>org.springframework.boot</groupId> 15<artifactId>spring-boot-starter-test</artifactId> 16 <scope>test</scope> 17 </dependency> 18 <dependency> 19 <groupId>org.springframework.boot</groupId> 20 <artifactId>spring-boot-starter-data-redis</artifactId> 21</dependency> 22 </dependencies>
2. SpringBoot配置.
1 server: 2 port: 8081 3 # Redis資料庫索引(預設為0) 4 spring: 5 redis: 6 database: 0 7 # Redis伺服器地址 8 host: 127.0.0.1 9 # Redis伺服器連線埠 10 port: 6379 11 # Redis伺服器連線密碼(預設為空) 12 #password: 13 jedis: 14 pool: 15 max-idle: 8 16 # 連線池最大阻塞等待時間(使用負值表示沒有限制) 17 max-wait: -1 18 # 連線池中的最大空閒連線 19 # 連線池中的最小空閒連線 20 min-idle: 0 21 # 連線超時時間(毫秒) 22 timeout: 100000View Code
3.話不多說,直接程式碼擼起
1 package com.hy.redis.controller; 2 3 import org.springframework.data.redis.core.RedisTemplate; 4 import org.springframework.scheduling.annotation.Async; 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.ResponseBody; 8 9 import javax.annotation.Resource; 10 import java.util.Objects; 11 import java.util.UUID; 12 import java.util.concurrent.Executors; 13 import java.util.concurrent.ScheduledExecutorService; 14 import java.util.concurrent.TimeUnit; 15 16 /** 17 * 18 * redis 加鎖的方式 實現高併發小分散式事務的處理 19 * 20 * @author huheng 21 * @date 2020/08/03 22 **/ 23 @Controller 24 public class DeductStockController { 25 26 @Resource 27 private RedisTemplate redisTemplate; 28 29 @RequestMapping("/deduct-stock") 30 @ResponseBody 31 public String deductStock() { 32 String clientId = UUID.randomUUID().toString(); 33 String lockKey = "lockKey"; 34 try { 35 // 先加鎖 36 Boolean flag = redisTemplate.opsForValue().setIfAbsent("lockKey", clientId, 10, TimeUnit.SECONDS); 37 38 // 加鎖成功 執行扣除庫存 39 if (flag) { 40 // 執行定時器 判斷鎖是否存在 存在 則延長失效時間 41 timer(lockKey, clientId); 42 43 // 讀取庫存 44 Integer stock = (Integer) redisTemplate.opsForValue().get("stock"); 45 if (stock != null && stock > 0) { 46 redisTemplate.opsForValue().set("stock", stock - 1); 47 System.out.println("搶購成功--扣除庫存成功" + "-----原庫存:" + stock + "剩餘庫存:" + (stock - 1)); 48 } 49 } 50 } finally { 51 // 釋放鎖 52 String verfiy = (String) redisTemplate.opsForValue().get(lockKey); 53 // 判斷是否為當前執行緒加的鎖 54 if (Objects.equals(verfiy, clientId)) { 55 redisTemplate.delete(lockKey); 56 } 57 } 58 return "end"; 59 } 60 61 /** 62 * 5秒鐘一次 63 * @param lockKey 64 * @param clientId 65 */ 66 @Async 67 public void timer(String lockKey, String clientId) { 68 ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); 69 // 引數:1、任務體 2、首次執行的延時時間 70 // 3、任務執行間隔 4、間隔時間單位 71 service.scheduleAtFixedRate(()->{ 72 String result = (String) redisTemplate.opsForValue().get(lockKey); 73 if (result != null && result.equals(clientId)) { 74 redisTemplate.expire(lockKey, 10 , TimeUnit.SECONDS); 75 } else { 76 service.shutdown(); 77 } 78 }, 0, 5, TimeUnit.SECONDS); 79 } 80 }View Code