商品秒杀是一个非常常见的场景,今天我们就使用Redis来实现商品秒杀功能。
为什么使用Redis?
- Redis是一款非关系数据库,数据存储在内存中,存取数据速度非常快!
- Redis是单线程的,即使在同一时间有多条命令操作数据库,这些命令依然只能排队等候。
SpringDataRedis
SpringDataRedis是一款Java语言实现的Redis数据库的操作API,它是SpringData系列的框架之一,专门用于操作Redis,而且可以和SpringBoot进行无缝整合。
怎么实现?
Redis可以存储五种数据结构,我们使用列表数据来实现商品秒杀功能。
- 我们将商品信息作为列表结构的key值,给列表push商品库存个数的value。
- 当商品秒杀的时候,我们使用pop命令从列表中取出数据即可。
具体实现
搭建开发环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> </parent>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </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>
|
SpringBoot项目的启动类
1 2 3 4 5 6
| @SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class); } }
|
Dao层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public interface CommodityDao {
void addStock(String key,String value);
String spike(String key); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @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层
1 2 3 4 5 6 7 8 9 10 11 12 13
| public interface CommodityService {
void addStock(int stock);
String spike() ; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @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); } }
|
测试功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| @SpringBootTest @RunWith(SpringRunner.class) public class RedisTest {
@Autowired private CommodityService commodityService;
@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; } } } }
|