对于业务中库存超卖测试
2015-06-29 17:03
281 查看
多并发时,用相应的锁方案保证库存不发生超卖。实现这个方案后,要有相应的场景测试方案。
很多时候,验证方案非常重要。
java可以利用CountDownLatch测试多并发。CountDownlatch通常用于某个业务线程需要等待其它多个线程完成某个条件后才进行相应操作。
CountDownLatch有countDown及await方法,分别对应减少计数器及当计数器大于0时阻塞当前线程。当计数量等于0时所有调用await方法且被阻塞的线程都被唤醒,然后进行相应操作。
此处用于模拟10个并发用户进行购买,库存初始化为5,看是否会发生超卖。
库存并发方案为对于某个sku的库存增减要求最终减去购买库存后库存量要大于等于0。这步由数据库语句完成。
例,库存更新语句:update skuStock set 更新后库存=原库存减去购买库存 where skuId=sku ID号 and 原库存减去购买库存后大于0
测试类:
public class StockTest implements ApplicationContextAware {
static {
System.setProperty("spring.profiles.active", "dev");
System.setProperty("configPath", "/home/zhao/work/config");
}
@Autowired
private SkuService skuService;
@Autowired
private SkuStockMapper skuStockMapper;
private static ApplicationContext applicationContext;
private static final CountDownLatch countDownLatch = new CountDownLatch(10);
private static final Logger logger = LoggerFactory.getLogger(StockTest.class);
@Test
public void testStock() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(20);
List<Future<Boolean>> futureList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
MockBuyTask mockBuyTask = new MockBuyTask();
futureList.add(executorService.submit(mockBuyTask));
}
int sucCount=0;
for(Future<Boolean> future:futureList){
if(future.get()){
sucCount++;
}
logger.info(future.get().toString());
}
logger.info("共"+sucCount+"人成功购物一件商品");
Assert.assertTrue(sucCount==5);
SkuStock skuStock = skuStockMapper.selectPoByPrimaryKey(7L);
Assert.assertTrue(skuStock != null && skuStock.getSkuId()==8L && skuStock.getCount() == 0);
}
static class MockBuyTask implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
countDownLatch.countDown();
logger.info("+wait for other man to run,thread:" + Thread.currentThread().getId());
countDownLatch.await();
SkuStock skuStock = new SkuStock();
skuStock.setSkuId(8L);
skuStock.setCount(1);
SkuStockMapper skuStockMapper = applicationContext.getBean(SkuStockMapper.class);
int rowCount = skuStockMapper.updateStockBySkuIdAndCountOfBuy(skuStock);
logger.info("+rowcount:" + rowCount);
return rowCount > 0 ? true : false;
}
}
@SuppressWarnings("static-access")
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
}
很多时候,验证方案非常重要。
java可以利用CountDownLatch测试多并发。CountDownlatch通常用于某个业务线程需要等待其它多个线程完成某个条件后才进行相应操作。
CountDownLatch有countDown及await方法,分别对应减少计数器及当计数器大于0时阻塞当前线程。当计数量等于0时所有调用await方法且被阻塞的线程都被唤醒,然后进行相应操作。
此处用于模拟10个并发用户进行购买,库存初始化为5,看是否会发生超卖。
库存并发方案为对于某个sku的库存增减要求最终减去购买库存后库存量要大于等于0。这步由数据库语句完成。
例,库存更新语句:update skuStock set 更新后库存=原库存减去购买库存 where skuId=sku ID号 and 原库存减去购买库存后大于0
测试类:
public class StockTest implements ApplicationContextAware {
static {
System.setProperty("spring.profiles.active", "dev");
System.setProperty("configPath", "/home/zhao/work/config");
}
@Autowired
private SkuService skuService;
@Autowired
private SkuStockMapper skuStockMapper;
private static ApplicationContext applicationContext;
private static final CountDownLatch countDownLatch = new CountDownLatch(10);
private static final Logger logger = LoggerFactory.getLogger(StockTest.class);
@Test
public void testStock() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(20);
List<Future<Boolean>> futureList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
MockBuyTask mockBuyTask = new MockBuyTask();
futureList.add(executorService.submit(mockBuyTask));
}
int sucCount=0;
for(Future<Boolean> future:futureList){
if(future.get()){
sucCount++;
}
logger.info(future.get().toString());
}
logger.info("共"+sucCount+"人成功购物一件商品");
Assert.assertTrue(sucCount==5);
SkuStock skuStock = skuStockMapper.selectPoByPrimaryKey(7L);
Assert.assertTrue(skuStock != null && skuStock.getSkuId()==8L && skuStock.getCount() == 0);
}
static class MockBuyTask implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
countDownLatch.countDown();
logger.info("+wait for other man to run,thread:" + Thread.currentThread().getId());
countDownLatch.await();
SkuStock skuStock = new SkuStock();
skuStock.setSkuId(8L);
skuStock.setCount(1);
SkuStockMapper skuStockMapper = applicationContext.getBean(SkuStockMapper.class);
int rowCount = skuStockMapper.updateStockBySkuIdAndCountOfBuy(skuStock);
logger.info("+rowcount:" + rowCount);
return rowCount > 0 ? true : false;
}
}
@SuppressWarnings("static-access")
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
this.applicationContext = applicationContext;
}
}
相关文章推荐
- eclipse下出现乱码的问题
- MyBatis根据Map中key作为字段名,value作为字段值修改数据
- iOS语言中的单例模式
- 关于开发者证书那点儿挫折
- OAuth 2.0系列教程(八) 授权码授权
- iOS开发工具-网络封包分析工具Charles
- DBN深信度网络
- 如何实现可动态调整隐藏header的listview
- [日志处理工作之五]整合logstash,kafka
- malloc()之后,内核发生了什么?
- Cordys Workspace 中Solution的使用
- linux 下密码加密程序(可以用于替换shadow文件中的用户密码)
- 虚拟机桥接网络设置(转)
- MySQL事务的艺术和陷阱
- [转] 机器学习那些事儿
- php把字符串指定字符分割成数组
- C#分析URL参数获取参数和值得对应列表
- 一些C++11语言新特性 - Range-Based for Loops
- 创建新文件夹
- DBCP连接池配置参数说明