Java秒杀方案
全套源码链接:
https://download.csdn.net/download/weixin_43652507/85545680
http://yes
技术点介绍
学习目标
如何设计一个秒杀系统
秒杀,对我们来说,都不是一个陌生的东西。每年的双11,618以及时下流行的直播等等。秒杀然而,这对于我们系统而言是一个巨大的考验。那么,如何才能更好地理解秒杀系统呢?我觉得作为一个程序员,你首先需要从高维度出发,从整体上思考问题。在我看来,秒杀其实主要解决两个问题,一个是并发读,一个是并发写。并发读的核心优化理念是尽量减少用户到服务端来“读”数据,或者让他们读更少的数据;并发写的处理原则也一样,它要求我们在数据库层面独立出来一个库,做特殊的处理。另外,我们还要针对秒杀系统做一些保护,针对意料之外的情况设计兜底方案,以防止最坏的情况发生。 其实,秒杀的整体架构可以概括为“稳、准、快”几个关键字。
所谓“稳”,就是整个系统架构要满足高可用,流量符合预期时肯定要稳定,就是超出预期时也同样不能掉链子,你要保证秒杀活动顺利完成,即秒杀商品顺利地卖出去,这个是最基本的前提。然后就是“准”,就是秒杀 10 台 iPhone,那就只能成交 10 台,多一台少一台都不行。一旦库存不对,那平台就要承担损失,所以“准”就是要求保证数据的一致性。最后再看“快”,“快”其实很好理解,它就是说系统的性能要足够高,否则你怎么支撑这么大的流量呢?不光是服务端要做极致的性能优化,而且在整个请求链路上都要做协同的优化,每个地方快一点,整个系统就完美了。
所以从技术角度上看“稳、准、快”,就对应了我们架构上的高可用、一致性和高性能的要求
高性能。 秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。对应的方案比如
动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化一致性。 秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知高可用。 现实中总难免出现一些我们考虑不到的情况,所以要保证系统的高可用和正确性,我们还要设计一个 PlanB 来兜底,以便在最坏情况发生时仍然能够从容应对。
完整目录
添加依赖
pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.1.RELEASE
com.xxxx
seckill
0.0.1-SNAPSHOT
seckill
seckill
1.8
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
runtime
com.baomidou
mybatis-plus-boot-starter
3.3.1.tmp
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-maven-plugin
application.yml
spring:
# thymeleaf配置
thymeleaf:
# 关闭缓存
cache: false
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/seckill?
useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: root
hikari:
# 连接池名
pool-name: DateHikariCP
# 最小空闲连接数
minimum-idle: 5
# 空闲连接存活最大时间,默认600000(10分钟)
idle-timeout: 180000
# 最大连接数,默认10
maximum-pool-size: 10
# 从连接池返回的连接的自动提交
auto-commit: true
# 连接最大存活时间,0表示永久存活,默认1800000(30分钟)
max-lifetime: 1800000
# 连接超时时间,默认30000(30秒)
connection-timeout: 30000
# 测试连接是否可用的查询语句
connection-test-query: SELECT 1
# Mybatis-plus配置
mybatis-plus:
#配置Mapper映射文件
mapper-locations: classpath*:/mapper/*Mapper.xml
# 配置MyBatis数据返回类型别名(默认别名是类名)
type-aliases-package: com.xxxx.seckill.pojo
## Mybatis SQL 打印(方法接口所在的包,不是Mapper.xml所在的包)
logging:
level:
com.xxxx.seckill.mapper: debug
packagecom.xxxx.seckill.controller;
importorg.springframework.stereotype.Controller;
importorg.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping;
/**
*测试
*
* @author xiao pan
* @since 1.0.0
*/
@Controller
@RequestMapping("/demo")
public class DemoController {
/**
*测试页面跳转
*
* @return
*/
@RequestMapping("/hello")
public String hello(Modelmodel) {
model.addAttribute("name","xxxx");
return"hello";
}
}
hello.html
测试