Spring Boot + Redisson 分布式鎖示例案例
下面為你提供一個完整的 Spring Boot + Redisson 分布式鎖示例項目結構,包含:
- Maven 依賴配置
- Redisson 配置類(支持單機/集群)
- 分布式鎖工具封裝
- 控制器示例(模擬并發(fā)場景)
- 測試方法建議
你可以直接復制到你的項目中使用。
?? 項目結構概覽
src/
├── main/
│ ├── java/
│ │ └── com.example.redissonlock/
│ │ ├── RedissonLockApplication.java
│ │ ├── config/
│ │ │ └── RedissonConfig.java
│ │ ├── service/
│ │ │ ├── OrderService.java
│ │ │ └── impl/
│ │ │ └── OrderServiceImpl.java
│ │ └── controller/
│ │ └── OrderController.java
│ └── resources/
│ ├── application.yml
│ └── application-dev.yml (可選)
└── test/
└── java/
└── com.example.redissonlock/
└── RedissonLockTest.java1?? Maven 依賴(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version> <!-- 支持 JDK 17+ -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>redisson-lock-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redisson Starter (自動配置 RedissonClient) -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.25.2</version> <!-- 檢查最新版:https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter -->
</dependency>
<!-- Lombok (可選,簡化日志/Getter/Setter) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>? 注意:
redisson-spring-boot-starter已包含spring-boot-starter-data-redis和redisson核心包。
2?? 配置文件(application.yml)
spring:
application:
name: redisson-lock-demo
# Redis 連接配置(單機模式)
redis:
host: localhost
port: 6379
database: 0
timeout: 2000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# Redisson 自定義配置(可選,如需調(diào)整看門狗等)
# 如果不配置,Redisson 會自動使用 spring.redis 下的連接信息?? 集群模式示例(替換 spring.redis):
spring:
redis:
cluster:
nodes:
- 192.168.1.10:7000
- 192.168.1.10:7001
- 192.168.1.10:7002
password: your_password
timeout: 2000ms3?? Redisson 配置類(可選,用于自定義)
?? 如果只用單機 Redis,其實不需要寫這個類!
redisson-spring-boot-starter會自動創(chuàng)建RedissonClient。
但如果你需要自定義(如修改看門狗超時、啟用 codec),可以添加:
// src/main/java/com/example/redissonlock/config/RedissonConfig.java
package com.example.redissonlock.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + redisHost + ":" + redisPort)
.setTimeout(3000)
.setConnectionPoolSize(10);
// 可選:調(diào)整看門狗超時(默認30秒)
// config.setLockWatchdogTimeout(60000); // 60秒
return Redisson.create(config);
}
}4?? 業(yè)務服務層(帶分布式鎖)
// src/main/java/com/example/redissonlock/service/OrderService.java
package com.example.redissonlock.service;
public interface OrderService {
void createOrder(String userId, String orderId);
}// src/main/java/com/example/redissonlock/service/impl/OrderServiceImpl.java
package com.example.redissonlock.service.impl;
import com.example.redissonlock.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
private final RedissonClient redissonClient;
public OrderServiceImpl(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
@Override
public void createOrder(String userId, String orderId) {
// 鎖 key 建議包含業(yè)務唯一標識,避免全局鎖
String lockKey = "order:create:" + orderId;
RLock lock = redissonClient.getLock(lockKey);
try {
// 嘗試加鎖:最多等待 3 秒,持有鎖 30 秒(看門狗會自動續(xù)期)
boolean isLocked = lock.tryLock(3, 30, TimeUnit.SECONDS);
if (!isLocked) {
log.warn("獲取分布式鎖失敗,orderId={}", orderId);
throw new RuntimeException("系統(tǒng)繁忙,請稍后再試");
}
log.info("線程 {} 獲取鎖成功,開始處理訂單 {}", Thread.currentThread().getName(), orderId);
// 模擬業(yè)務耗時(即使超過30秒也不會丟鎖?。?
Thread.sleep(5000);
// TODO: 真實業(yè)務邏輯(如扣庫存、寫DB)
log.info("訂單 {} 創(chuàng)建成功", orderId);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("訂單處理被中斷", e);
throw new RuntimeException(e);
} finally {
// 安全釋放鎖(Redisson 會校驗線程ID)
if (lock.isHeldByCurrentThread()) {
lock.unlock();
log.info("線程 {} 釋放鎖,orderId={}", Thread.currentThread().getName(), orderId);
}
}
}
}5?? 控制器(用于測試)
// src/main/java/com/example/redissonlock/controller/OrderController.java
package com.example.redissonlock.controller;
import com.example.redissonlock.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/create-order")
public String createOrder(@RequestParam String userId,
@RequestParam String orderId) {
orderService.createOrder(userId, orderId);
return "Order created: " + orderId;
}
}6?? 啟動類
// src/main/java/com/example/redissonlock/RedissonLockApplication.java
package com.example.redissonlock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedissonLockApplication {
public static void main(String[] args) {
SpringApplication.run(RedissonLockApplication.class, args);
}
}?? 如何測試并發(fā)效果?
方法 1:使用 JMeter / Postman Runner
- 發(fā)起多個并發(fā)請求到:
GET http://localhost:8080/create-order?userId=U1&orderId=O1001 - 觀察日志:同一 orderId 的請求會串行執(zhí)行
方法 2:單元測試(模擬多線程)
// src/test/java/com/example/redissonlock/RedissonLockTest.java
@Test
void testConcurrentOrderCreation() throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
executor.submit(() -> {
try {
orderService.createOrder("U1", "O1001"); // 相同 orderId
} finally {
latch.countDown();
}
});
}
latch.await(); // 等待所有線程完成
executor.shutdown();
}? 關鍵優(yōu)勢總結
| 特性 | 說明 |
|---|---|
| 自動續(xù)期 | Watchdog 默認每 10s 續(xù)期一次,不怕業(yè)務超時 |
| 安全釋放 | 基于線程 ID 校驗,不會誤刪其他線程的鎖 |
| 可重入 | 同一線程可多次加鎖 |
| 無死鎖風險 | 即使應用 crash,鎖也會在 watchdog 超時后釋放 |
| Spring Boot 集成簡單 | starter 自動配置,開箱即用 |
?? 注意事項
- 鎖 key 設計:務必帶上業(yè)務唯一標識(如
order:{orderId}),避免鎖粒度太大。 - 不要在鎖內(nèi)做遠程調(diào)用:如 HTTP 請求、MQ 發(fā)送,可能因網(wǎng)絡延遲導致鎖持有時間過長。
- 監(jiān)控鎖狀態(tài):可通過 Redis CLI 查看:
KEYS *order*、TTL your_lock_key - 生產(chǎn)環(huán)境 Redis 高可用:建議使用 Redis Cluster 或 Sentinel。
到此這篇關于完整的 Spring Boot + Redisson 分布式鎖示例的文章就介紹到這了,更多相關Spring Boot Redisson 分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot基于docx4j實現(xiàn)DOCX轉PDF的具體方案
在日常項目開發(fā)中,我們經(jīng)常遇到用戶上傳 Word( .docx)文件,希望后臺自動生成 PDF,用于下載、歸檔或在線預覽,本文將介紹一個完全開源、部署簡單、純 Java 的實現(xiàn)方案,感興趣的小伙伴可以跟著小編一起來看看2025-11-11
java:程序包org.apache.ibatis.annotations不存在報錯解決
這篇文章主要給大家介紹了關于java:程序包org.apache.ibatis.annotations不存在報錯的解決方法,這個錯誤是我在直接導入springboot項目的時候報錯的,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-04-04
SpringBoot實現(xiàn)簡單的登錄注冊的項目實戰(zhàn)
本文主要介紹了SpringBoot實現(xiàn)簡單的登錄注冊的項目實戰(zhàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
詳解java中finalize的實現(xiàn)與相應的執(zhí)行過程
在常規(guī)的java書籍中,即會描述 object的finalize方法是用于一些特殊的對象在回收之前再做一些掃尾的工作,但是并沒有說明此是如何實現(xiàn)的.本篇從java的角度(不涉及jvm以及c++),有需要的朋友們可以參考借鑒。2016-09-09

