única função em um projeto altamente concorrente: a entrevista de avaliação real

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

única função em um projeto altamente concorrente: a entrevista de avaliação real

registros da tabela de Commodity

única função em um projeto altamente concorrente: a entrevista de avaliação real

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

única função em um projeto altamente concorrente: a entrevista de avaliação real

Ordens de tabela:

única função em um projeto altamente concorrente: a entrevista de avaliação real

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

única função em um projeto altamente concorrente: a entrevista de avaliação real

Acho que você gosta

Origin blog.51cto.com/14570694/2483731
Recomendado
Clasificación