**测试代码**
```
@Autowired
private CustomerService customerService;
private static final CountDownLatch COUNT_DOWN_LATCH = new CountDownLatch(1000);
private static final CountDownLatch AWAIT = new CountDownLatch(1000);
private static final ExecutorService THREAD_POOL = Executors.newFixedThreadPool(1000);
@Test
public void test() throws InterruptedException {
repository.save(new Customer("Jack", "Bauer", new BigDecimal(1000)));
for (int i = 0; i < 1000; i++) {
COUNT_DOWN_LATCH.countDown();
THREAD_POOL.execute(new CustomerServiceTest(customerService));
}
AWAIT.await();
THREAD_POOL.shutdownNow();
System.out.println(repository.findById(1));
}
```
```
@Slf4j
class CustomerServiceTest implements Runnable {
private final CustomerService customerService;
public CustomerServiceTest(CustomerService customerService) {
this.customerService = customerService;
}
@Override
public void run() {
try {
CustomerRepositoryTest.COUNT_DOWN_LATCH.await();
customerService.deductionPrice(1, new BigDecimal(30));
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
CustomerRepositoryTest.AWAIT.countDown();
}
}
}
```
## 一、手撸版
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
```
```
spring:
redis:
database: 0
host: xxx
port: xxx
password: xxx
timeout: 6000ms
lettuce:
pool:
max-active: 20
max-wait: -1ms
max-idle: 10
min-idle: 0
```
**RedisUtils.java**
```
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final Long SUCCESS = 1L;
/**
* 获取锁
*
* @param lockKey
* @param value
* @param expireTime:单位-秒
* @return
*/
public boolean getLock(String lockKey, String value, int expireTime) {
String script = "if redis.call('setNx',KEYS[1],ARGV[1]) then if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('expire',KEYS[1],ARGV[2]) else return 0 end end";
return ((Long) redisTemplate.execute(
(RedisConnection connection) -> connection.eval(
script.getBytes(),
ReturnType.INTEGER,
1,
lockKey.getBytes(),
value.getBytes(),
(String.valueOf(expireTime)).getBytes())
)).equals(SUCCESS);
}
/**
* 释放锁
*
* @param lockKey
* @param value
* @return
*/
public boolean releaseLock(String lockKey, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
return ((Long) redisTemplate.execute(
(RedisConnection connection) -> connection.eval(
script.getBytes(),
ReturnType.INTEGER,
1,
lockKey.getBytes(),
value.getBytes())
)).equals(SUCCESS);
}
```
```
@Autowired
private RedisUtils redisUtils;
@Override
public Customer deductionPrice(Integer customerId, BigDecimal price) {
String stepLockKey = "key";
String stepLockValue = UUID.randomUUID().toString();
try {
// 上锁
while (!redisUtils.getLock(stepLockKey, stepLockValue, 5)) {
try {
Thread.sleep(100);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
Customer byId = customerRepository.findById(customerId);
if (byId == null) {
return null;
}
byId.setPrice(byId.getPrice().subtract(price));
return customerRepository.save(byId);
} finally {
redisUtils.releaseLock(stepLockKey, stepLockValue);
}
}
```
## 二、spring-integration版
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
```
```
spring:
redis:
database: 0
host: xxx
port: xxx
password: xxx
timeout: 6000ms
lettuce:
pool:
max-active: 20
max-wait: -1ms
max-idle: 10
min-idle: 0
```
```
@Bean
public RedisLockRegistry redisLockRegistry(LettuceConnectionFactory lettuceConnectionFactory) {
return new RedisLockRegistry(lettuceConnectionFactory, "lock");
}
```
```
@Autowired
private RedisLockRegistry redisLockRegistry;
@Override
public Customer deductionPrice(Integer customerId, BigDecimal price) {
Lock obtain = redisLockRegistry.obtain("key");
try {
obtain.lock();
Customer byId = customerRepository.findById(customerId);
if (byId == null) {
return null;
}
byId.setPrice(byId.getPrice().subtract(price));
return customerRepository.save(byId);
} finally {
obtain.unlock();
}
}
```
## 三、redisson版
```
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.13.4</version>
</dependency>
```
```
spring:
redis:
database: 0
host: xxx
port: xxx
password: xxx
timeout: 6000ms
```
```
@Autowired
private RedissonClient redissonClient;
@Override
public Customer deductionPrice(Integer customerId, BigDecimal price) {
RLock lock= redissonClient.getLock("key");
try {
lock.lock(5, TimeUnit.SECONDS);
Customer byId = customerRepository.findById(customerId);
if (byId == null) {
return null;
}
byId.setPrice(byId.getPrice().subtract(price));
return customerRepository.save(byId);
} finally {
obtain.unlock();
}
}
```
**先这样吧,后面有空再写写。**

SpringBoot Redis 分布式锁