Redis实现商品秒杀

商品秒杀是一个非常常见的场景,今天我们就使用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;
            }
        }
    }
}
发布了64 篇原创文章 · 获赞 67 · 访问量 6872

猜你喜欢

转载自blog.csdn.net/qq_45193304/article/details/104960492