商品秒杀是一个非常常见的场景,今天我们就使用Redis来实现商品秒杀功能。
为什么使用Redis?
- Redis是一款非关系数据库,数据存储在内存中,存取数据速度非常快!
- Redis是单线程的,即使在同一时间有多条命令操作数据库,这些命令依然只能排队等候。
SpringDataRedis
SpringDataRedis是一款Java语言实现的Redis数据库的操作API,它是SpringData系列的框架之一,专门用于操作Redis,而且可以和SpringBoot进行无缝整合。
怎么实现?
Redis可以存储五种数据结构,我们使用列表数据来实现商品秒杀功能。
- 我们将商品信息作为列表结构的key值,给列表push商品库存个数的value。
- 当商品秒杀的时候,我们使用pop命令从列表中取出数据即可。
具体实现
搭建开发环境
<!--SpringBoot为父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
</parent>
<dependencies>
<!--测试功能的启动器,用于整合junit测试功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Spring-Data-Redis的启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lombox插件的依赖,SpringBoot内置,无须标注版本号-->
<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>
SpringBoot项目的启动类
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class);
}
}
Dao层
- Dao层接口
public interface CommodityDao {
/**
* 将商品加入库存
* @param key
* @param value
*/
void addStock(String key,String value);
/**
* 秒杀商品
* @param key
* @return
*/
String spike(String key);
}
- Dao层实现
@Repository
public class CommodityDaoImpl implements CommodityDao {
@Autowired
private RedisTemplate redisTemplate;
@Override
public void addStock(String key,String value) {
redisTemplate.boundListOps(key).leftPush(value);
}
@Override
public String spike(String key) {
return (String) redisTemplate.boundListOps(key).leftPop();
}
}
Service层
- Service层接口
public interface CommodityService {
/**
* 将商品加入库存
* @param stock
*/
void addStock(int stock);
/**
* 秒杀商品
* @return
*/
String spike() ;
}
- Service层实现
@Service
public class CommodityServiceImpl implements CommodityService {
@Autowired
private CommodityDao commodityDao;
private final static String KEY = "commodity";
@Override
public void addStock(int stock) {
for(int i = 0; i < stock; i++) {
commodityDao.addStock(KEY,"智能手表");
}
}
@Override
public String spike() {
return commodityDao.spike(KEY);
}
}
测试功能
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTest {
@Autowired
private CommodityService commodityService;
/**
* 执行商品秒杀前,将商品存入数据库中,已存入5件商品
*/
@Before
public void addStock() {
commodityService.addStock(5);
}
/**
* 商品秒杀测试,使用两个线程一起秒杀
*/
@Test
public void spike() {
ExecutorService es = Executors.newFixedThreadPool(3);
Object obj = new Object();
es.submit(() -> {
System.out.println(Thread.currentThread().getName() + "正在秒杀");
while (true) {
String commodity = commodityService.spike();
if (commodity != null) {
System.out.println(Thread.currentThread().getName() + "抢到了商品" + commodity);
} else {
System.out.println("商品被抢完了");
break;
}
}
});
es.submit(() -> {
System.out.println(Thread.currentThread().getName() + "正在秒杀");
while (true) {
String commodity = commodityService.spike();
if (commodity != null) {
System.out.println(Thread.currentThread().getName() + "抢到了商品" + commodity);
} else {
System.out.println("商品被抢完了");
break;
}
}
});
}
/**
* 单线程环境秒杀
*/
@Test
public void del() {
while (true) {
String commodity = commodityService.spike();
if (commodity != null) {
System.out.println(Thread.currentThread().getName() + "抢到了商品" + commodity);
} else {
System.out.println("商品被抢完了");
break;
}
}
}
}
转载:https://blog.csdn.net/qq_45193304/article/details/104960492
查看评论