3
respostas

Dúvida - Sobre jpa( atualizacao do metodo pagamento)

Olá pessoal, dúvida simples na service ao recuperar o id do pagamento foi alterado o Status do pagamento e logo após foi feito um save.

Minha dúvida é o seguinte, na chamada do findById se ele encontrar, esse objeto estaria como managed pela JPA.
ao alterar nao deveria salvar automaticamente? Sem precisar chamar o .save novamente?

Qual seria as vantagens em mandar salvar novamente e quais seriam as desvantagens em nao chamá-lo?

Garanta sua matrícula hoje e ganhe + 2 meses grátis

Continue sua jornada tech com ainda mais tempo para aprender e evoluir

Quero aproveitar agora
3 respostas

Olá Igor! Tudo ben?

Quando você utiliza o JPA e faz uma busca por um objeto com findById, ele é de fato carregado no contexto de persistência e se torna um objeto "managed". Isso significa que qualquer alteração feita nesse objeto será detectada pelo JPA e, ao final da transação, essas alterações serão automaticamente sincronizadas com o banco de dados, sem a necessidade de chamar save explicitamente.

No entanto, existem algumas situações em que chamar save explicitamente pode ser vantajoso:

  1. Controle de Transações: Se você estiver trabalhando em um contexto onde a transação é gerenciada manualmente ou precisa de um controle mais fino sobre quando as alterações devem ser aplicadas, chamar save pode ser útil.

  2. Atualizações Parciais: Em alguns casos, você pode querer garantir que apenas certas alterações sejam persistidas. Chamando save, você tem a certeza de que o estado atual do objeto é o que será salvo, o que pode ser útil em cenários complexos.

  3. Claridade de Código: Em algumas equipes, pode ser uma questão de clareza ou estilo de código, deixando explícito que o objeto foi atualizado e salvo.

Por outro lado, não chamar save pode simplificar o código e reduzir a quantidade de operações explícitas, confiando no JPA para gerenciar o ciclo de vida do objeto.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Uma duvida. Para que o registro fosse atualizado sem a necessidade de chamar o método save, o método na classe Service não deveria estar anotado com @Transactional?

Bom dia, Bruno! Perdão pela demora em responder!

No Spring Data JPA, o findById do repositório roda com @Transactional(readOnly = true) e só vale durante a execução do método do repositório. Se o seu método de serviço não estiver anotado com @Transactional, a transação do findById termina logo após a consulta e a entidade volta detached; ao alterar o estado desse objeto fora da transação, o JPA não fará dirty checking, então você teria que chamar .save (que faz merge) para persistir.

O que fazer (solução direta):

  1. Garanta uma transação no método de serviço onde você lê e altera a entidade, para manter o objeto managed do começo ao fim.
    Veja este exemplo:

    @Service
    public class PagamentoService {
    
       private final PagamentoRepository repo;
    
       public PagamentoService(PagamentoRepository repo) {
           this.repo = repo;
       }
    
       @Transactional // sem readOnly
       public void confirmarPagamento(Long id) {
           Pagamento p = repo.findById(id)
               .orElseThrow(() -> new EntityNotFoundException("Pagamento não encontrado"));
    
           p.setStatus(Status.CONFIRMADO); // dirty checking vai detectar
           // NÃO precisa repo.save(p) aqui
           // o flush ocorre no commit da transação
       }
    }
    
  2. Se o método estiver com @Transactional(readOnly = true), não altere a entidade ali; mova a alteração para um método com transação de escrita ou remova o readOnly=true. Em Hibernate, readOnly=true ajusta o flush/dirty checking, e as mudanças não serão sincronizadas no commit.

  3. Se você está fora de transação ou com entidade detached, então use .save (que faz merge) para reanexar e persistir as alterações:

    public void confirmarPagamentoSemTransacao(Long id) {
        Pagamento p = repo.findById(id).orElseThrow();
        p.setStatus(Status.CONFIRMADO);
        repo.save(p); // necessário: faz merge e agenda o update
    }
    

Quando chamar .save mesmo com transação:

  • Entidade possivelmente detached (veio de outra camada, foi desserializada, mapeada de DTO, etc.).
  • Você quer persistir imediatamente antes do commit (usar saveAndFlush ou flush) — útil quando precisa que o UPDATE ocorra agora (por exemplo, para validar uma constraint no meio do fluxo).
  • Upsert de nova entidade (id null): save faz persist.

Abraços e bons estudos!