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

Qual o problema de definir a transaction no DAO?

Qual o problema de definir a transaction no DAO?

2 respostas
solução!

Oi Giulia, tudo bem ?

O problema é que você fica com um escopo de transação muito fechado/curto. Vejamos um exemplo:

Dao

@Repository
public class ProdutoDao {

    @PersistenceContext
    private EntityManager manager;

    @Transaction // abrindo no início da chamada e fechando no fim da chamada deste método
    public void salva(Produto produto) {
        manager.persist(produto);
    }

    public void qualquerOutraOperacao() {
        // manager.fazQualquerCoisaNoBanco
        // altera o estado da base
    }
}

Veja que o salva() define abertura e fechamento de transação. Caso algo dê errado no contexto dessa transação (qualquer exception lançada) automaticamente vai desencadear um rollBack não afetando o banco com mudanças indesejadas.

Controller (ou qualquer classe de Serviço que vai usar o dao)

@Controller
@RequestMapping("/produto")
public class ProdutoController {

    @Autowired
    private ProdutoDao dao;

    @PostMapping
    public String salva(@Valid Produto produto) {

        // faz qualquer coisa relativa ao atendimento da requisição

        this.dao.salva(produto);

        return "redirect:/produto"; // manda pra lista 
    }
}

Até aqui tudo normal. Agora imagine que você precise pra essa action chamar qq outro método do Dao que altere a base, ou mesmo que nem seja no Dao, você poderia mandar a capa do livro pra um serviço de storage externo e dada uma resposta positiva você prossegue e salva no banco o produto com a url da capa, por exemplo.

    @PostMapping
    public String salva(@Valid Produto produto) {

        // faz qualquer coisa relativa ao atendimento da requisição

        storageService.salvaCapa(produto);
        this.dao.salva(produto);
        this.dao.qualquerOutraOperacao();

        return "redirect:/produto"; // manda pra lista 
    }

Caso a capa não seja salva no serviço de storage o produto não deveria ser salvo no banco, nem a outra operação chamada. Mas da forma como se encontra, o save tem um contexto de transação que vai iniciar e fechar efetivando alterações de forma independente das outras ações. Escopo muito fechado.

Seria interessante então ao invés de cada ação do dao, ou do storage ter sua própria Tx, a própria ação do controller (ou qq outra lógica que os usa) ter sua transação. Com @Transaction no método do controller, ao invés dos métodos do Dao, conseguimos isso. Qualquer problema com a ação em geral, vai gerar um rollBack de todas as possíveis alterações :) Exemplo, qualquer problema com o serviço de storage o livro não será commitado no banco. Qualquer problema com a chamada a seguir do dao, vai dar rollback não efetivando o save do produto, mesmo ele tendo sido chamado antes, etc, etc.

Espero ter ajudado. Abraço!

Sim muito clara a explicação obrigado