1.创建springboot项目
2.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>
<groupId>com.nbug</groupId>
<artifactId>springboot-redis-cache-lock</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-redis-cache-lock</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.application.yml
spring:
redis:
host: localhost
port: 6379
cache:
type: redis
4.CacheTest
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class CacheTest {
@Autowired
public RedisCache redisCache;
@RequestMapping("/getList")
public List get(){
return redisCache.get();
}
@RequestMapping("/delete")
public int delete(){
return redisCache.delete();
}
}
5.LockTest
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
@Slf4j
public class LockTest {
@Autowired
private RedisLock redisLock;
private static final int TIMEOUT = 10 * 1000; //超时时间 10s
//库存
//private AtomicInteger count = new AtomicInteger(100);
private int count =100;
//抢购成功数
private int success=0;
@RequestMapping("/testLock")
public String testLock() {
long time = System.currentTimeMillis() + TIMEOUT;
//加锁
boolean islock = redisLock.lock("key", String.valueOf(time));
//没有获取到锁
if (!islock){
log.info("服务器忙,请重试");
return "服务器忙,请重试";
}
//获取锁之后
if (count==0){
redisLock.unlock("key",String.valueOf(time));
log.info("抢完了,成功数为:{}",success);
return "抢完了";
}
//因为获取到的锁的线程只有一个,所以这里计数也不会出错
//库存减去1
count--;
/* if (count.get()==0){
redisLock.unlock("key",String.valueOf(time));
log.info("抢完了,成功数为:{}",success);
return "抢完了";
}
count.getAndDecrement();*/
//解锁
redisLock.unlock("key",String.valueOf(time));
success++;
log.info("抢购成功 成功数为:{} 库存剩余为:{}",success,count);
return "抢购成功";
}
}
6.RedisCache
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@CacheConfig(cacheNames = "/getList")
@Slf4j
public class RedisCache {
//该方法开启缓存
@Cacheable(key = "'list'")
public List get() {
String a = "aaaaaaa";
String b = "aaaaaaabbbbccccccccc";
String c = "aaaaaaaccc";
List list = new ArrayList();
list.add(a);
list.add(b);
list.add(c);
log.info("执行了get方法,没有使用缓存");
return list;
}
//如果数据库数据进行了更新,在这行该方法后,删除指定key的缓存
@CacheEvict(key = "'list'")
public int delete() {
log.info("删除了list缓存");
return 1;
}
}
7.RedisLock
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
@Slf4j
public class RedisLock {
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
if(redisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
//currentValue=A 这两个线程的value都是B 其中一个线程拿到锁
String currentValue = redisTemplate.opsForValue().get(key);
//如果锁过期
if (!StringUtils.isEmpty(currentValue)
&& Long.parseLong(currentValue) < System.currentTimeMillis()) {
//获取上一个锁的时间
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
}
/**
* 解锁
* @param key
* @param value
*/
public void unlock(String key, String value) {
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e) {
log.error("【redis分布式锁】解锁异常, {}", e);
}
}
}
8.启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class SpringbootRedisCacheLockApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootRedisCacheLockApplication.class, args);
}
}
9.测试 http://localhost:8080/testLock
测试缓存 http://localhost:8080/getList