java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot 分布式锁与并发控制

Spring Boot 分布式锁与并发控制的应用场景

作者:星辰徐哥

本章主要介绍了SpringBoot分布式锁与并发控制的核心概念与使用方法,包括分布式锁的定义与特点、并发控制的定义与特点、SpringBoot与分布式锁的集成、SpringBoot的实际应用场景,感兴趣的朋友跟随小编一起看看吧

Spring Boot 分布式锁与并发控制

30.1 学习目标与重点提示

学习目标:掌握Spring Boot分布式锁与并发控制的核心概念与使用方法,包括分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景,学会在实际开发中处理分布式锁与并发控制问题。
重点:分布式锁的定义与特点并发控制的定义与特点Spring Boot与分布式锁的集成Spring Boot的实际应用场景

30.2 分布式锁与并发控制概述

分布式锁与并发控制是Java开发中的重要组件,用于处理分布式系统中的并发访问问题。

30.2.1 分布式锁的定义

定义:分布式锁是一种用于在分布式系统中实现资源共享访问控制的机制,确保在同一时间只有一个进程或线程能够访问共享资源。
作用

常见的分布式锁

✅ 结论:分布式锁是一种用于在分布式系统中实现资源共享访问控制的机制,作用是防止资源的并发修改、确保数据的一致性、提高系统的可靠性。

30.2.2 并发控制的定义

定义:并发控制是指在多进程或多线程环境中,控制对共享资源的访问,防止数据不一致和并发冲突。
作用

常见的并发控制技术

✅ 结论:并发控制是指在多进程或多线程环境中,控制对共享资源的访问,作用是防止数据不一致、防止并发冲突、提高系统的性能。

30.3 Spring Boot与分布式锁的集成

Spring Boot与分布式锁的集成是Java开发中的重要内容。

30.3.1 集成Redis分布式锁的步骤

定义:集成Redis分布式锁的步骤是指使用Spring Boot与Redis分布式锁集成的方法。
步骤

  1. 创建Spring Boot项目。
  2. 添加所需的依赖。
  3. 配置Redis。
  4. 创建分布式锁工具类。
  5. 创建业务层。
  6. 创建控制器类。
  7. 测试应用。

示例
pom.xml文件中的依赖:

<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Redis依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application.properties文件中的配置:

# 服务器端口
server.port=8080
# Redis连接信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

分布式锁工具类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class RedisLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private static final String LOCK_KEY = "product-lock";
    private static final long LOCK_EXPIRE_TIME = 30; // 锁的过期时间,单位秒
    public boolean tryLock(String lockValue) {
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(result);
    }
    public void releaseLock(String lockValue) {
        String value = stringRedisTemplate.opsForValue().get(LOCK_KEY);
        if (lockValue.equals(value)) {
            stringRedisTemplate.delete(LOCK_KEY);
        }
    }
}

实体类:

public class Product {
    private Long id;
    private String productId;
    private String productName;
    private double price;
    private int stock;
    public Product() {
    }
    public Product(Long id, String productId, String productName, double price, int stock) {
        this.id = id;
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.stock = stock;
    }
    // Getter和Setter方法
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getProductId() {
        return productId;
    }
    public void setProductId(String productId) {
        this.productId = productId;
    }
    public String getProductName() {
        return productName;
    }
    public void setProductName(String productName) {
        this.productName = productName;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public int getStock() {
        return stock;
    }
    public void setStock(int stock) {
        this.stock = stock;
    }
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + '\'' +
                ", productName='" + productName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }
}

Repository接口:

import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Repository
public class ProductRepository {
    private List<Product> products = new ArrayList<>();
    public ProductRepository() {
        products.add(new Product(1L, "P001", "手机", 1000.0, 100));
        products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
        products.add(new Product(3L, "P003", "电视", 3000.0, 80));
        products.add(new Product(4L, "P004", "手表", 500.0, 200));
        products.add(new Product(5L, "P005", "耳机", 300.0, 150));
    }
    public List<Product> getAllProducts() {
        return products;
    }
    public Product getProductById(Long id) {
        return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
    }
    public void addProduct(Product product) {
        product.setId((long) (products.size() + 1));
        products.add(product);
    }
    public void updateProduct(Product product) {
        Product existingProduct = getProductById(product.getId());
        if (existingProduct != null) {
            existingProduct.setProductId(product.getProductId());
            existingProduct.setProductName(product.getProductName());
            existingProduct.setPrice(product.getPrice());
            existingProduct.setStock(product.getStock());
        }
    }
    public void deleteProduct(Long id) {
        products.removeIf(product -> product.getId().equals(id));
    }
}

Service类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private RedisLock redisLock;
    public List<Product> getAllProducts() {
        return productRepository.getAllProducts();
    }
    public Product getProductById(Long id) {
        return productRepository.getProductById(id);
    }
    public void addProduct(Product product) {
        productRepository.addProduct(product);
    }
    public void updateProduct(Product product) {
        productRepository.updateProduct(product);
    }
    public void deleteProduct(Long id) {
        productRepository.deleteProduct(id);
    }
    public boolean reduceStock(Long id, int quantity) {
        String lockValue = UUID.randomUUID().toString();
        try {
            if (redisLock.tryLock(lockValue)) {
                Product product = productRepository.getProductById(id);
                if (product != null && product.getStock() >= quantity) {
                    product.setStock(product.getStock() - quantity);
                    productRepository.updateProduct(product);
                    return true;
                }
                return false;
            }
            return false;
        } finally {
            redisLock.releaseLock(lockValue);
        }
    }
}

控制器类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
    @GetMapping("/{id}")
    public Product getProductById(@PathVariable Long id) {
        return productService.getProductById(id);
    }
    @PostMapping("/add")
    public void addProduct(@RequestBody Product product) {
        productService.addProduct(product);
    }
    @PutMapping("/edit/{id}")
    public void editProduct(@PathVariable Long id, @RequestBody Product product) {
        product.setId(id);
        productService.updateProduct(product);
    }
    @DeleteMapping("/delete/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
    }
    @PostMapping("/reduceStock/{id}/{quantity}")
    public boolean reduceStock(@PathVariable Long id, @PathVariable int quantity) {
        return productService.reduceStock(id, quantity);
    }
}

应用启动类:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisLockApplication.class, args);
    }
}

测试类:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RedisLockApplicationTests {
    @LocalServerPort
    private int port;
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void contextLoads() {
    }
    @Test
    void testGetAllProducts() {
        List products = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
        assertThat(products).hasSize(5);
    }
    @Test
    void testReduceStock() {
        boolean result = restTemplate.postForObject("http://localhost:" + port + "/api/products/reduceStock/1/10", null, Boolean.class);
        assertThat(result).isTrue();
    }
}

✅ 结论:集成Redis分布式锁的步骤包括创建Spring Boot项目、添加所需的依赖、配置Redis、创建分布式锁工具类、创建业务层、创建控制器类、测试应用。

30.4 Spring Boot的实际应用场景

在实际开发中,Spring Boot分布式锁与并发控制的应用场景非常广泛,如:

示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
@Service
class ProductService {
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private RedisLock redisLock;
    public List<Product> getAllProducts() {
        return productRepository.getAllProducts();
    }
    public Product getProductById(Long id) {
        return productRepository.getProductById(id);
    }
    public void addProduct(Product product) {
        productRepository.addProduct(product);
    }
    public void updateProduct(Product product) {
        productRepository.updateProduct(product);
    }
    public void deleteProduct(Long id) {
        productRepository.deleteProduct(id);
    }
    public boolean reduceStock(Long id, int quantity) {
        String lockValue = UUID.randomUUID().toString();
        try {
            if (redisLock.tryLock(lockValue)) {
                Product product = productRepository.getProductById(id);
                if (product != null && product.getStock() >= quantity) {
                    product.setStock(product.getStock() - quantity);
                    productRepository.updateProduct(product);
                    return true;
                }
                return false;
            }
            return false;
        } finally {
            redisLock.releaseLock(lockValue);
        }
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
class RedisLock {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    private static final String LOCK_KEY = "product-lock";
    private static final long LOCK_EXPIRE_TIME = 30;
    public boolean tryLock(String lockValue) {
        Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(LOCK_KEY, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(result);
    }
    public void releaseLock(String lockValue) {
        String value = stringRedisTemplate.opsForValue().get(LOCK_KEY);
        if (lockValue.equals(value)) {
            stringRedisTemplate.delete(LOCK_KEY);
        }
    }
}
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Repository
class ProductRepository {
    private List<Product> products = new ArrayList<>();
    public ProductRepository() {
        products.add(new Product(1L, "P001", "手机", 1000.0, 100));
        products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
        products.add(new Product(3L, "P003", "电视", 3000.0, 80));
        products.add(new Product(4L, "P004", "手表", 500.0, 200));
        products.add(new Product(5L, "P005", "耳机", 300.0, 150));
    }
    public List<Product> getAllProducts() {
        return products;
    }
    public Product getProductById(Long id) {
        return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
    }
    public void addProduct(Product product) {
        product.setId((long) (products.size() + 1));
        products.add(product);
    }
    public void updateProduct(Product product) {
        Product existingProduct = getProductById(product.getId());
        if (existingProduct != null) {
            existingProduct.setProductId(product.getProductId());
            existingProduct.setProductName(product.getProductName());
            existingProduct.setPrice(product.getPrice());
            existingProduct.setStock(product.getStock());
        }
    }
    public void deleteProduct(Long id) {
        products.removeIf(product -> product.getId().equals(id));
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
    @GetMapping("/{id}")
    public Product getProductById(@PathVariable Long id) {
        return productService.getProductById(id);
    }
    @PostMapping("/add")
    public void addProduct(@RequestBody Product product) {
        productService.addProduct(product);
    }
    @PutMapping("/edit/{id}")
    public void editProduct(@PathVariable Long id, @RequestBody Product product) {
        product.setId(id);
        productService.updateProduct(product);
    }
    @DeleteMapping("/delete/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
    }
    @PostMapping("/reduceStock/{id}/{quantity}")
    public boolean reduceStock(@PathVariable Long id, @PathVariable int quantity) {
        return productService.reduceStock(id, quantity);
    }
}
@SpringBootApplication
public class RedisLockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisLockApplication.class, args);
    }
}
// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RedisLockApplicationTests {
    @LocalServerPort
    private int port;
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void contextLoads() {
    }
    @Test
    void testGetAllProducts() {
        List products = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
        assertThat(products).hasSize(5);
    }
    @Test
    void testReduceStock() {
        boolean result = restTemplate.postForObject("http://localhost:" + port + "/api/products/reduceStock/1/10", null, Boolean.class);
        assertThat(result).isTrue();
    }
}

输出结果

✅ 结论:在实际开发中,Spring Boot分布式锁与并发控制的应用场景非常广泛,需要根据实际问题选择合适的分布式锁和并发控制方法。

总结

本章我们学习了Spring Boot分布式锁与并发控制,包括分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景,学会了在实际开发中处理分布式锁与并发控制问题。其中,分布式锁的定义与特点、并发控制的定义与特点、Spring Boot与分布式锁的集成、Spring Boot的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。

到此这篇关于Spring Boot 分布式锁与并发控制的应用场景的文章就介绍到这了,更多相关Spring Boot 分布式锁与并发控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文