Requisitos funcionais: Design um sistema de pico
O programa inicial
Produto Design Tabela: venda de bens disponíveis para o pico de usuário, um inventário inicial.
@Entity
public class SecKillGoods implements Serializable{
@Id
private String id;
/**
* 剩余库存
*/
private Integer remainNum;
/**
* 秒杀商品名称
*/
private String goodsName;
}
projeto de Spike ordens tabela: ordens de sucesso recorde de pico
@Entity
public class SecKillOrder implements Serializable {
@Id
@GenericGenerator(name = "PKUUID", strategy = "uuid2")
@GeneratedValue(generator = "PKUUID")
@Column(length = 36)
private String id;
//用户名称
private String consumer;
//秒杀产品编号
private String goodsId;
//购买数量
private Integer num;
}
Dao projeto: O principal é um método para reduzir o estoque, outro método CRUD que vem com JPA
public interface SecKillGoodsDao extends JpaRepository<SecKillGoods,String>{
@Query("update SecKillGoods g set g.remainNum = g.remainNum - ?2 where g.id=?1")
@Modifying(clearAutomatically = true)
@Transactional
int reduceStock(String id,Integer remainNum);
}
Fornecer inicialização de dados operacional e economia de ordens:
@Service
public class SecKillService {
@Autowired
SecKillGoodsDao secKillGoodsDao;
@Autowired
SecKillOrderDao secKillOrderDao;
/**
* 程序启动时:
* 初始化秒杀商品,清空订单数据
*/
@PostConstruct
public void initSecKillEntity(){
secKillGoodsDao.deleteAll();
secKillOrderDao.deleteAll();
SecKillGoods secKillGoods = new SecKillGoods();
secKillGoods.setId("123456");
secKillGoods.setGoodsName("秒杀产品");
secKillGoods.setRemainNum(10);
secKillGoodsDao.save(secKillGoods);
}
/**
* 购买成功,保存订单
* @param consumer
* @param goodsId
* @param num
*/
public void generateOrder(String consumer, String goodsId, Integer num) {
secKillOrderDao.save(new SecKillOrder(consumer,goodsId,num));
}
}
Aqui é o projeto da camada de controlador
@Controller
public class SecKillController {
@Autowired
SecKillGoodsDao secKillGoodsDao;
@Autowired
SecKillService secKillService;
/**
* 普通写法
* @param consumer
* @param goodsId
* @return
*/
@RequestMapping("/seckill.html")
@ResponseBody
public String SecKill(String consumer,String goodsId,Integer num) throws InterruptedException {
//查找出用户要买的商品
SecKillGoods goods = secKillGoodsDao.findOne(goodsId);
//如果有这么多库存
if(goods.getRemainNum()>=num){
//模拟网络延时
Thread.sleep(1000);
//先减去库存
secKillGoodsDao.reduceStock(num);
//保存订单
secKillService.generateOrder(consumer,goodsId,num);
return "购买成功";
}
return "购买失败,库存不足";
}
}
Acima de tudo, a base de preparação, um teste de unidade usando o seguinte método para simular alta concorrência, um monte de gente para comprar a mesma situação uma commodity quente.
@Controller
public class SecKillSimulationOpController {
final String takeOrderUrl = "http://127.0.0.1:8080/seckill.html";
/**
* 模拟并发下单
*/
@RequestMapping("/simulationCocurrentTakeOrder")
@ResponseBody
public String simulationCocurrentTakeOrder() {
//httpClient工厂
final SimpleClientHttpRequestFactory httpRequestFactory = new SimpleClientHttpRequestFactory();
//开50个线程模拟并发秒杀下单
for (int i = 0; i < 50; i++) {
//购买人姓名
final String consumerName = "consumer" + i;
new Thread(new Runnable() {
@Override
public void run() {
ClientHttpRequest request = null;
try {
URI uri = new URI(takeOrderUrl + "?consumer=consumer" + consumerName + "&goodsId=123456&num=1");
request = httpRequestFactory.createRequest(uri, HttpMethod.POST);
InputStream body = request.execute().getBody();
BufferedReader br = new BufferedReader(new InputStreamReader(body));
String line = "";
String result = "";
while ((line = br.readLine()) != null) {
result += line;//获得页面内容或返回内容
}
System.out.println(consumerName+":"+result);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
return "simulationCocurrentTakeOrder";
}
}
localhost acesso: 8080 / simulationCocurrentTakeOrder, você pode testar o
caso esperado: Porque nós mercadorias só pico (123456) inicializado 10, de preferência, é claro, é reduzir ao inventário zero, formulário de pedido e apenas 10 registros.
Realidade: As ordens registros da tabela
registros da tabela de Commodity
Após a análise do porquê de super stocks vai acontecer:
porque várias solicitações para acesso, basta usar dao consulta um banco de dados não tem estoque, mas mais uma má situação é que muitas pessoas têm encontrado o estoque, desta vez por causa do programa de tratamento atraso, não há tempo para reduzir o estoque, ele apareceu leitura suja. Como evitá-lo no design? A maioria maneira estúpida de se fazer a sincronização seckill método SecKillController, o único que pode colocar ordens. Mas a afetar o desempenho, o single tornou-se uma operação síncrona.
@RequestMapping("/seckill.html")
@ResponseBody
public synchronized String SecKill
melhorias
A especificação de programação multi-thread, promovendo o bloqueio recurso compartilhado, o pensamento mais provável do caso de concorrência acrescido de sincronização blocos simultâneos aparecer. Deve ser apenas um segmento de cada vez para reduzir o estoque. Mas aqui é a melhor opção, é usar o Oracle, MySQL bloqueios no nível de linha - ao mesmo tempo, apenas um thread pode operar sobre os mesmos registros de linha, transformação SecKillGoodsDao:
public interface SecKillGoodsDao extends JpaRepository<SecKillGoods,String>{
@Query("update SecKillGoods g set g.remainNum = g.remainNum - ?2 where g.id=?1 and g.remainNum>0")
@Modifying(clearAutomatically = true)
@Transactional
int reduceStock(String id,Integer remainNum);
}
E apenas adicionando um, grandes mudanças tem causado, int valor de retorno representa um número de linhas afetadas, o controlador correspondente para fazer a determinação apropriada.
@RequestMapping("/seckill.html")
@ResponseBody
public String SecKill(String consumer,String goodsId,Integer num) throws InterruptedException {
//查找出用户要买的商品
SecKillGoods goods = secKillGoodsDao.findOne(goodsId);
//如果有这么多库存
if(goods.getRemainNum()>=num){
//模拟网络延时
Thread.sleep(1000);
if(goods.getRemainNum()>0) {
//先减去库存
int i = secKillGoodsDao.reduceStock(goodsId, num);
if(i!=0) {
//保存订单
secKillService.generateOrder(consumer, goodsId, num);
return "购买成功";
}else{
return "购买失败,库存不足";
}
}else {
return "购买失败,库存不足";
}
}
return "购买失败,库存不足";
}
Em uma olhada na operação
Ordens de tabela:
No caso dos problemas de alta concorrência de pico, mesmo que o atraso de rede existe, também é garantida.
progresso comum, aprender a compartilhar
Congratulo-me com a atenção de todos [número de público calmo como código ], massa relacionadas com Java artigos, materiais de aprendizagem será atualizado no interior, materiais de acabamento será no interior.
Eu me sinto bem para escrever sobre um ponto de louvor, mais seguidores cantar! Ponto de atenção, não se perder, continuamente atualizado! ! !
entrevista maciça, arquitetura de compartilhamento de informações