mirror of
https://gitee.com/52itstyle/spring-boot-seckill.git
synced 2025-12-30 10:22:26 +00:00
:ambulance:多线程模拟秒杀无法获取 request 的问题
This commit is contained in:
@@ -1,26 +1,26 @@
|
||||
package com.itstyle.seckill;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
/**
|
||||
* 启动类
|
||||
* 创建者 科帮网
|
||||
* 创建时间 2018年5月12日
|
||||
* API接口测试:http://localhost:8080/seckill/swagger-ui.html
|
||||
* 跑之前 一定要看文库:https://gitee.com/52itstyle/spring-boot-seckill/wikis
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(Application.class);
|
||||
/**
|
||||
* 1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁
|
||||
* 4. redis 订阅监听;5.kafka消息队列
|
||||
* 启动前 请配置application.properties中相关redis、zk以及kafka相关地址
|
||||
*/
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
SpringApplication.run(Application.class, args);
|
||||
LOGGER.info("项目启动 ");
|
||||
}
|
||||
package com.itstyle.seckill;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
/**
|
||||
* 启动类
|
||||
* 创建者 科帮网
|
||||
* 创建时间 2018年5月12日
|
||||
* API接口测试:http://localhost:8080/seckill/swagger-ui.html
|
||||
* 跑之前 一定要看文库:https://gitee.com/52itstyle/spring-boot-seckill/wikis
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(Application.class);
|
||||
/**
|
||||
* 1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁
|
||||
* 4. redis 订阅监听;5.kafka消息队列
|
||||
* 启动前 请配置application.properties中相关redis、zk以及kafka相关地址
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
LOGGER.info("项目启动");
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ public class IPUtils {
|
||||
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
|
||||
*/
|
||||
public static String getIpAddr() {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String ip = null;
|
||||
try {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
ip = request.getHeader("x-forwarded-for");
|
||||
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
|
||||
@@ -1,284 +1,294 @@
|
||||
package com.itstyle.seckill.web;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.itstyle.seckill.common.entity.Result;
|
||||
import com.itstyle.seckill.common.entity.SuccessKilled;
|
||||
import com.itstyle.seckill.queue.disruptor.DisruptorUtil;
|
||||
import com.itstyle.seckill.queue.disruptor.SeckillEvent;
|
||||
import com.itstyle.seckill.queue.jvm.SeckillQueue;
|
||||
import com.itstyle.seckill.service.ISeckillService;
|
||||
@Api(tags ="秒杀")
|
||||
@RestController
|
||||
@RequestMapping("/seckill")
|
||||
public class SeckillController {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(SeckillController.class);
|
||||
|
||||
private static int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||
//创建线程池 调整队列数 拒绝服务
|
||||
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize+1, 10l, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(1000));
|
||||
|
||||
@Autowired
|
||||
private ISeckillService seckillService;
|
||||
|
||||
@ApiOperation(value="秒杀一(最low实现)",nickname="科帮网")
|
||||
@PostMapping("/start")
|
||||
public Result start(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀一(会出现超卖)");
|
||||
for(int i=0;i<skillNum;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckil(killId, userId);
|
||||
if(result!=null){
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
}else{
|
||||
LOGGER.info("用户:{}{}",userId,"哎呦喂,人也太多了,请稍后!");
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀二(程序锁)",nickname="科帮网")
|
||||
@PostMapping("/startLock")
|
||||
public Result startLock(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀二(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilLock(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀三(AOP程序锁)",nickname="科帮网")
|
||||
@PostMapping("/startAopLock")
|
||||
public Result startAopLock(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀三(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilAopLock(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀四(数据库悲观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDBPCC_ONE")
|
||||
public Result startDBPCC_ONE(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀四(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilDBPCC_ONE(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀五(数据库悲观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDPCC_TWO")
|
||||
public Result startDPCC_TWO(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀五(正常、数据库锁最优实现)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilDBPCC_TWO(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀六(数据库乐观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDBOCC")
|
||||
public Result startDBOCC(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀六(正常、数据库锁最优实现)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//这里使用的乐观锁、可以自定义抢购数量、如果配置的抢购人数比较少、比如120:100(人数:商品) 会出现少买的情况
|
||||
//用户同时进入会出现更新失败的情况
|
||||
Result result = seckillService.startSeckilDBOCC(killId, userId,1);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀柒(进程内队列)",nickname="科帮网")
|
||||
@PostMapping("/startQueue")
|
||||
public Result startQueue(long seckillId){
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀柒(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SuccessKilled kill = new SuccessKilled();
|
||||
kill.setSeckillId(killId);
|
||||
kill.setUserId(userId);
|
||||
try {
|
||||
Boolean flag = SeckillQueue.getMailQueue().produce(kill);
|
||||
if(flag){
|
||||
LOGGER.info("用户:{}{}",kill.getUserId(),"秒杀成功");
|
||||
}else{
|
||||
LOGGER.info("用户:{}{}",userId,"秒杀失败");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.info("用户:{}{}",userId,"秒杀失败");
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀柒(Disruptor队列)",nickname="科帮网")
|
||||
@PostMapping("/startDisruptorQueue")
|
||||
public Result startDisruptorQueue(long seckillId){
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀八(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SeckillEvent kill = new SeckillEvent();
|
||||
kill.setSeckillId(killId);
|
||||
kill.setUserId(userId);
|
||||
DisruptorUtil.producer(kill);
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
package com.itstyle.seckill.web;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.itstyle.seckill.common.entity.Result;
|
||||
import com.itstyle.seckill.common.entity.SuccessKilled;
|
||||
import com.itstyle.seckill.queue.disruptor.DisruptorUtil;
|
||||
import com.itstyle.seckill.queue.disruptor.SeckillEvent;
|
||||
import com.itstyle.seckill.queue.jvm.SeckillQueue;
|
||||
import com.itstyle.seckill.service.ISeckillService;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@Api(tags ="秒杀")
|
||||
@RestController
|
||||
@RequestMapping("/seckill")
|
||||
public class SeckillController {
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(SeckillController.class);
|
||||
|
||||
private static int corePoolSize = Runtime.getRuntime().availableProcessors();
|
||||
//创建线程池 调整队列数 拒绝服务
|
||||
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize+1, 10l, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue<Runnable>(1000));
|
||||
|
||||
@Autowired
|
||||
private ISeckillService seckillService;
|
||||
|
||||
@ApiOperation(value="秒杀一(最low实现)",nickname="科帮网")
|
||||
@PostMapping("/start")
|
||||
public Result start(long seckillId){
|
||||
int skillNum = 10;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀一(会出现超卖)");
|
||||
/**
|
||||
* 开启新线程之前,将RequestAttributes对象设置为子线程共享
|
||||
* 这里仅仅是为了测试,否则 IPUtils 中获取不到 request 对象
|
||||
* 用到限流注解的测试用例,都需要加一下两行代码
|
||||
*/
|
||||
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
RequestContextHolder.setRequestAttributes(sra, true);
|
||||
for(int i=0;i<skillNum;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckil(killId, userId);
|
||||
if(result!=null){
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
}else{
|
||||
LOGGER.info("用户:{}{}",userId,"哎呦喂,人也太多了,请稍后!");
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀二(程序锁)",nickname="科帮网")
|
||||
@PostMapping("/startLock")
|
||||
public Result startLock(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀二(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilLock(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀三(AOP程序锁)",nickname="科帮网")
|
||||
@PostMapping("/startAopLock")
|
||||
public Result startAopLock(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀三(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilAopLock(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀四(数据库悲观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDBPCC_ONE")
|
||||
public Result startDBPCC_ONE(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀四(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilDBPCC_ONE(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀五(数据库悲观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDPCC_TWO")
|
||||
public Result startDPCC_TWO(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀五(正常、数据库锁最优实现)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Result result = seckillService.startSeckilDBPCC_TWO(killId, userId);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀六(数据库乐观锁)",nickname="科帮网")
|
||||
@PostMapping("/startDBOCC")
|
||||
public Result startDBOCC(long seckillId){
|
||||
int skillNum = 1000;
|
||||
final CountDownLatch latch = new CountDownLatch(skillNum);//N个购买者
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀六(正常、数据库锁最优实现)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//这里使用的乐观锁、可以自定义抢购数量、如果配置的抢购人数比较少、比如120:100(人数:商品) 会出现少买的情况
|
||||
//用户同时进入会出现更新失败的情况
|
||||
Result result = seckillService.startSeckilDBOCC(killId, userId,1);
|
||||
LOGGER.info("用户:{}{}",userId,result.get("msg"));
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
latch.await();// 等待所有人任务结束
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀柒(进程内队列)",nickname="科帮网")
|
||||
@PostMapping("/startQueue")
|
||||
public Result startQueue(long seckillId){
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀柒(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SuccessKilled kill = new SuccessKilled();
|
||||
kill.setSeckillId(killId);
|
||||
kill.setUserId(userId);
|
||||
try {
|
||||
Boolean flag = SeckillQueue.getMailQueue().produce(kill);
|
||||
if(flag){
|
||||
LOGGER.info("用户:{}{}",kill.getUserId(),"秒杀成功");
|
||||
}else{
|
||||
LOGGER.info("用户:{}{}",userId,"秒杀失败");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.info("用户:{}{}",userId,"秒杀失败");
|
||||
}
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
@ApiOperation(value="秒杀柒(Disruptor队列)",nickname="科帮网")
|
||||
@PostMapping("/startDisruptorQueue")
|
||||
public Result startDisruptorQueue(long seckillId){
|
||||
seckillService.deleteSeckill(seckillId);
|
||||
final long killId = seckillId;
|
||||
LOGGER.info("开始秒杀八(正常)");
|
||||
for(int i=0;i<1000;i++){
|
||||
final long userId = i;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SeckillEvent kill = new SeckillEvent();
|
||||
kill.setSeckillId(killId);
|
||||
kill.setUserId(userId);
|
||||
DisruptorUtil.producer(kill);
|
||||
}
|
||||
};
|
||||
executor.execute(task);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
Long seckillCount = seckillService.getSeckillCount(seckillId);
|
||||
LOGGER.info("一共秒杀出{}件商品",seckillCount);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
package com.itstyle.seckill.web;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.jms.Destination;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.itstyle.seckill.common.entity.Result;
|
||||
import com.itstyle.seckill.common.entity.Seckill;
|
||||
import com.itstyle.seckill.common.utils.HttpClient;
|
||||
import com.itstyle.seckill.common.utils.IPUtils;
|
||||
import com.itstyle.seckill.queue.activemq.ActiveMQSender;
|
||||
import com.itstyle.seckill.service.ISeckillService;
|
||||
|
||||
@Api(tags = "秒杀商品")
|
||||
@RestController
|
||||
@RequestMapping("/seckillPage")
|
||||
public class SeckillPageController {
|
||||
|
||||
@Autowired
|
||||
private ISeckillService seckillService;
|
||||
|
||||
@Autowired
|
||||
private ActiveMQSender activeMQSender;
|
||||
|
||||
@Autowired
|
||||
private HttpClient httpClient;
|
||||
@Value("${qq.captcha.url}")
|
||||
private String url;
|
||||
@Value("${qq.captcha.aid}")
|
||||
private String aid;
|
||||
@Value("${qq.captcha.AppSecretKey}")
|
||||
private String appSecretKey;
|
||||
|
||||
|
||||
@ApiOperation(value = "秒杀商品列表", nickname = "小柒2012")
|
||||
@PostMapping("/list")
|
||||
public Result list() {
|
||||
//返回JSON数据、前端VUE迭代即可
|
||||
List<Seckill> List = seckillService.getSeckillList();
|
||||
return Result.ok(List);
|
||||
}
|
||||
|
||||
@RequestMapping("/startSeckill")
|
||||
public Result startSeckill(String ticket,String randstr,HttpServletRequest request) {
|
||||
HttpMethod method =HttpMethod.POST;
|
||||
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
|
||||
params.add("aid", aid);
|
||||
params.add("AppSecretKey", appSecretKey);
|
||||
params.add("Ticket", ticket);
|
||||
params.add("Randstr", randstr);
|
||||
params.add("UserIP", IPUtils.getIpAddr(request));
|
||||
String msg = httpClient.client(url,method,params);
|
||||
/**
|
||||
* response: 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required]
|
||||
* evil_level:[0,100],恶意等级[optional]
|
||||
* err_msg:验证错误信息[optional]
|
||||
*/
|
||||
//{"response":"1","evil_level":"0","err_msg":"OK"}
|
||||
JSONObject json = JSONObject.parseObject(msg);
|
||||
String response = (String) json.get("response");
|
||||
if("1".equals(response)){
|
||||
//进入队列、假数据而已
|
||||
Destination destination = new ActiveMQQueue("seckill.queue");
|
||||
activeMQSender.sendChannelMess(destination,1000+";"+1);
|
||||
return Result.ok();
|
||||
}else{
|
||||
return Result.error("验证失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.itstyle.seckill.web;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.jms.Destination;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.itstyle.seckill.common.entity.Result;
|
||||
import com.itstyle.seckill.common.entity.Seckill;
|
||||
import com.itstyle.seckill.common.utils.HttpClient;
|
||||
import com.itstyle.seckill.common.utils.IPUtils;
|
||||
import com.itstyle.seckill.queue.activemq.ActiveMQSender;
|
||||
import com.itstyle.seckill.service.ISeckillService;
|
||||
|
||||
@Api(tags = "秒杀商品")
|
||||
@RestController
|
||||
@RequestMapping("/seckillPage")
|
||||
public class SeckillPageController {
|
||||
|
||||
@Autowired
|
||||
private ISeckillService seckillService;
|
||||
|
||||
@Autowired
|
||||
private ActiveMQSender activeMQSender;
|
||||
|
||||
@Autowired
|
||||
private HttpClient httpClient;
|
||||
@Value("${qq.captcha.url}")
|
||||
private String url;
|
||||
@Value("${qq.captcha.aid}")
|
||||
private String aid;
|
||||
@Value("${qq.captcha.AppSecretKey}")
|
||||
private String appSecretKey;
|
||||
|
||||
|
||||
@ApiOperation(value = "秒杀商品列表", nickname = "小柒2012")
|
||||
@PostMapping("/list")
|
||||
public Result list() {
|
||||
//返回JSON数据、前端VUE迭代即可
|
||||
List<Seckill> List = seckillService.getSeckillList();
|
||||
return Result.ok(List);
|
||||
}
|
||||
|
||||
@RequestMapping("/startSeckill")
|
||||
public Result startSeckill(String ticket,String randstr,HttpServletRequest request) {
|
||||
HttpMethod method =HttpMethod.POST;
|
||||
MultiValueMap<String, String> params= new LinkedMultiValueMap<String, String>();
|
||||
params.add("aid", aid);
|
||||
params.add("AppSecretKey", appSecretKey);
|
||||
params.add("Ticket", ticket);
|
||||
params.add("Randstr", randstr);
|
||||
params.add("UserIP", IPUtils.getIpAddr());
|
||||
String msg = httpClient.client(url,method,params);
|
||||
/**
|
||||
* response: 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required]
|
||||
* evil_level:[0,100],恶意等级[optional]
|
||||
* err_msg:验证错误信息[optional]
|
||||
*/
|
||||
//{"response":"1","evil_level":"0","err_msg":"OK"}
|
||||
JSONObject json = JSONObject.parseObject(msg);
|
||||
String response = (String) json.get("response");
|
||||
if("1".equals(response)){
|
||||
//进入队列、假数据而已
|
||||
Destination destination = new ActiveMQQueue("seckill.queue");
|
||||
activeMQSender.sendChannelMess(destination,1000+";"+1);
|
||||
return Result.ok();
|
||||
}else{
|
||||
return Result.error("验证失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user