在 Spring Boot 项目里,运用 Redisson 实现分布式锁来处理销售扣减库存和入库增加库存,且同时操作一个库存值,可按以下步骤完成:

1、添加依赖

pom.xml文件里添加 Redisson 和 Spring Boot Data Redis 的依赖:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<dependencies>
    <!-- Redisson -->
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson-spring-boot-starter</artifactId>
        <version>3.16.2</version>
    </dependency>
    <!-- Spring Boot Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

2、配置 Redisson

application.yml文件里配置 Redis:

1
2
3
4
spring: 
  redis: 
    host: localhost
    port: 6379

3、在service中使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class InventoryService {

    @Autowired
    private RedissonClient redissonClient;

    // 库存键名
    private static final String INVENTORY_KEY = "product:inventory:1";

    /**
     * 销售扣减库存
     * @param quantity 扣减数量
     * @return 是否成功
     */
    public boolean deductInventory(int quantity) {
        // 获取分布式锁
        RLock lock = redissonClient.getLock(INVENTORY_KEY);
        try {
            // 尝试加锁,等待10秒,自动释放锁时间为30秒
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 模拟从Redis获取当前库存
                Integer currentInventory = getInventoryFromRedis();
                if (currentInventory != null && currentInventory >= quantity) {
                    // 扣减库存
                    int newInventory = currentInventory - quantity;
                    // 更新Redis中的库存
                    updateInventoryInRedis(newInventory);
                    return true;
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return false;
    }

    /**
     * 入库增加库存
     * @param quantity 增加数量
     */
    public void addInventory(int quantity) {
        // 获取分布式锁
        RLock lock = redissonClient.getLock(INVENTORY_KEY);
        try {
            // 尝试加锁,等待10秒,自动释放锁时间为30秒
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 模拟从Redis获取当前库存
                Integer currentInventory = getInventoryFromRedis();
                if (currentInventory != null) {
                    // 增加库存
                    int newInventory = currentInventory + quantity;
                    // 更新Redis中的库存
                    updateInventoryInRedis(newInventory);
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 从Redis获取当前库存
     * @return 当前库存
     */
    private Integer getInventoryFromRedis() {
        // 这里需要根据实际情况实现从Redis获取库存的逻辑
        return 100;
    }

    /**
     * 更新Redis中的库存
     * @param newInventory 新的库存数量
     */
    private void updateInventoryInRedis(int newInventory) {
        // 这里需要根据实际情况实现更新Redis库存的逻辑
    }
}

代码解释

  • 获取分布式锁:借助redissonClient.getLock(INVENTORY_KEY)获取分布式锁。
  • 加锁操作:运用tryLock方法尝试加锁,并且设置了等待时间和自动释放锁的时间。
  • 业务逻辑处理:在加锁成功之后,对库存进行扣减或者增加操作。
  • 释放锁:在finally块中释放锁,以此保证锁一定会被释放。

4、使用服务类

在控制器或者其他服务类中注入InventoryService并调用相应的方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class InventoryController {

    @Autowired
    private InventoryService inventoryService;

    @GetMapping("/deduct")
    public String deductInventory(@RequestParam int quantity) {
        if (inventoryService.deductInventory(quantity)) {
            return "扣减库存成功";
        }
        return "扣减库存失败";
    }

    @GetMapping("/add")
    public String addInventory(@RequestParam int quantity) {
        inventoryService.addInventory(quantity);
        return "增加库存成功";
    }
}