1. 程式人生 > 實用技巧 >redis分散式鎖學習之路1-RedisTemplate實現分散式鎖

redis分散式鎖學習之路1-RedisTemplate實現分散式鎖

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>
 7
8 <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>
View Code

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: 100000
View 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