Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Performace do metodo cadastrar

Estou desenvolvendo um projeto baseado no curso para minha faculdade, contudo um dos requisitos é que a API aceite uma grande volume de inclusões no método cadastrar (Exc: 100.000 por segundo), que seria criar um novo item no banco. Gostaria de saber como poderia realizar esta tarefa. Na aula sobre cache é citado usar Redis para melhorar a performance, mas não sei se seria esse o caso. Preciso muito de um direcionamento no que diz respeito a isso. Agradeço a atenção. Espero ter cido claro.

segue o codigo do controller:

package com.bytebank.gestaodegastos.controller;

@RestController
@RequestMapping("/transacoes")
public class TransacoesController {

    @Autowired
    private TransacaoRepository transacaoRepository;

    @GetMapping
    @Cacheable(value="listaDeTopicos")
    public Page<TransacaoDto> lista(@PageableDefault(sort = "id", 
        direction = Direction.DESC, page = 0, size = 10) Pageable paginacao) {

        Page<Transacao> transacao = transacaoRepository.findAll(paginacao);
        return TransacaoDto.converter(transacao);

//        if(dataDaTransacao == null) {
//            List<Transacao> transacao = transacaoRepository.findAll();
//            return TransacaoDto.converter(transacao);
//        }else {
//            List<Transacao> transacao = transacaoRepository.findAll();
//            return TransacaoDto.converter(transacao);
//        }

    }

    @PostMapping
    @Transactional
    @CacheEvict(value="listaDeTopicos", allEntries=true)
    public ResponseEntity<TransacaoDto> cadastrar(@RequestBody @Valid TransacaoForm form,
            UriComponentsBuilder uriBuilder) {
        Transacao transacao = form.converter();
        transacaoRepository.save(transacao);

        URI uri = uriBuilder.path("/transacoes/{id}").buildAndExpand(transacao.getId()).toUri(); 
        return ResponseEntity.created(uri).body(new TransacaoDto(transacao));
    }

    @GetMapping("/{id}")
    public ResponseEntity<DetalhesDaTransacaoDto> detalhar(@PathVariable Long id) {
        Optional<Transacao> transacao = transacaoRepository.findById(id);
        if(transacao.isPresent()) {
            return ResponseEntity.ok(new DetalhesDaTransacaoDto(transacao.get()));
        }
        return ResponseEntity.notFound().build();
    }

    @PutMapping("/{id}")
    @Transactional
    @CacheEvict(value="listaDeTopicos", allEntries=true)
    public ResponseEntity<TransacaoDto> atualizar(@PathVariable Long id, @RequestBody @Valid AtualizacaoTransacaoForm form){
        Optional<Transacao> optional = transacaoRepository.findById(id);
        if(optional.isPresent()) {
            Transacao transacao = form.atualizar(id, transacaoRepository);
            return ResponseEntity.ok(new TransacaoDto(transacao));
        }
        return ResponseEntity.notFound().build();
    }


    @DeleteMapping("/{id}")
    @Transactional
    @CacheEvict(value="listaDeTopicos", allEntries=true)
    public ResponseEntity<?> remover(@PathVariable Long id){
        Optional<Transacao> optional = transacaoRepository.findById(id);
        if(optional.isPresent()) {
            transacaoRepository.deleteById(id);
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }
}

codigo do modelo a ser cadastrado:

package com.bytebank.gestaodegastos.modelo;

@Entity
public class Transacao {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String descricao;
    private double valor;
    private LocalDate dataDaTransacao = LocalDate.now();
    @ManyToOne
    priva
2 respostas
solução!

Oi Bruno,

O esquema de cache utilizado no curso serve para melhorar a performance em relação às consultas.

No seu caso então não vai ajudar.

O ideal nesse caso seria ter um método que insere múltiplos registros de uma vez, ao invés de inserir de um em um. Esse processo é conhecido como Batch insert.

No application.properties precisa passar uns parâmetros para ativar o batch na JPA:

spring.jpa.properties.hibernate.jdbc.batch_size=1000
spring.jpa.properties.hibernate.order_inserts=true

O valor 1000 seria de quantos em quantos registros serão enviados ao banco de dados de uma vez.

Dá uma pesquisada à respeito disso.

Mas talvez isso não seja a solução para o seu caso. Por exemplo, imagine que esses 100 mil inserts por segundo sejam de usuários distintos.

Ou seja, não é um usuário inserindo milhares de registros, mas sim milhares de usuários cada um inserindo apenas um registro.

Aí então o jeito para aguentar esse número alto de registros deixa de ser uma preocupação a nível de código e passa a ser a nível de arquitetura.

Provavelmente vai precisar ter uma boa infra estrutura com diversos servidores em cluster e um balanceador de cargas.

Isso porque as seguintes caracteristicas de arquitetura serão criticas para esse projeto: Escalabilidade e Disponibilidade, além é claro de Performance.

Pesquise a respeito disso também.

Bons estudos!

Oi Rodrigo, obrigado irei pesquisar sobre Batch insert. E referente ao balanceador de cargas, eu achei um interessante da Netflix OSS, ja estou estudando sobre. Desculpe mas estou muito interessado nessa sequencia de cursos sobre API então acabarei fazendo muitas perguntas. Obrigado :)