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

setAutoCommit(false)

Olá,

caso eu quisesse assumir o controle das transações, onde poderia colocar os comandos: connection.setAutoCommit(false);e connection.commit(); no projeto final?

seria na classe ProdutoDAO? Se sim, onde no código ficaria correto?

fico no aguardo e agradeço a atenção..

Abraço!

7 respostas

Ricardo, boa tarde. Sim, ficaria na DAO. Como recebemos a connection no construtor, podemos nele mesmo já declarar o setAutoCommit(false); e dentro do try onde chama o método que vai realizar a operação com o banco, depois dele você pode colocar o connection.commit( ); e no catch você pode fazer o connection.rollback( );

    public ProdutoDAO(Connection connection) throws SQLException {
        connection.setAutoCommit(false); 
        this.connection = connection;
    }

    public void salvar(Produto produto) {
        try {    
            String sql = "INSERT INTO PRODUTO (NOME, DESCRICAO) VALUES (?, ?)";

            try (PreparedStatement pstm = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { 

                pstm.setString(1, produto.getNome());
                pstm.setString(2, produto.getDescricao());

                pstm.execute();

                connection.commit();

                try (ResultSet rst = pstm.getGeneratedKeys()) { 
                    while (rst.next()) {
                        produto.setId(rst.getInt(1));
                    }
                }
            }
        } 
        catch (SQLException e) {
            throw new RuntimeException(e);
            e.printStackTrace();
            connection.rollback();
        }
    }

o comando e.printStackTrace(); ficou com erro, o java sugere remover o comando... mas aí não vai aparecer o rollback no log, certo? Então, removo ou tem outra forma de escrevê-lo?

obrigado pela ajuda.

Qual erro aparece? Acredito que seja porquê você está lançando a exceção e assim não irá alcançar o e.printStackTrace( ) e o rollback. Tenta inverter a ordem por favor? Deixando o throw por último.

    public ProdutoDAO(Connection connection) throws SQLException {
        connection.setAutoCommit(false); // false significa que o dev assume o controle das transações
        this.connection = connection;
    }

    public void salvar(Produto produto) throws SQLException {
        try {    
            String sql = "INSERT INTO PRODUTO (NOME, DESCRICAO) VALUES (?, ?)";

            try (PreparedStatement pstm = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { // devolve o ID gerado.
                //Para garantir o fechamento dos recursos -> a cláusula try-with-resources
                pstm.setString(1, produto.getNome());
                pstm.setString(2, produto.getDescricao());

                pstm.execute();

                connection.commit(); // controle da transação

                try (ResultSet rst = pstm.getGeneratedKeys()) { //Para garantir o fechamento dos recursos -> a cláusula try-with-resources
                    while (rst.next()) {
                        produto.setId(rst.getInt(1));
                    }
                }
            }
        } 
        catch (SQLException e) {
            e.printStackTrace();
            connection.rollback();
            throw new RuntimeException(e);

        }
    }

deu certo, mas como podes notar, lançou um throws em salvar, aliás, o comando connection.setAutoCommit(false); também lançou um throws no contrutor do ProdutoDAO e, se eu não me engano, já havíamos tirado o throws dali...

obrigado.

Ricardo, desculpe-me. O que vc quer dizer sobre lançou um throws em salvar e um throws no construtor? Dessa forma que vc mandou ai em cima então não deu certo?

sim, compilou ok. Mas no ProdutoDAO na linha do método Salvar tinhamos substituído o throws pelo try...catch(SQLException e) { throw new RuntimeException(e);}

mas agora, inserindo o connection.commit(); fui obrigado a colocar de volta o throws no método Salvar, como pode ser visto no código acima.

a minha dúvida é: está correto ter um throws na linha do método Salvar e dentro do mesmo método ter o try...catch(SQLException e) { throw new RuntimeException(e);} ??????

Além disso, foi lançado throws no ProdutoController que se tentava evitar, conforme código abaixo:

    public void deletar(Integer id) throws SQLException {
        this.produtoDAO.deletar(id);
    }

    public void salvar(Produto produto) throws SQLException {
        this.produtoDAO.salvar(produto);
    }
solução!

Ricardo, boa noite. Sim, está certo. Este é um problema de trabalhar com o JDBC puro. Muitos recursos lançam SQLException, que é um exceção checkada, então se não isolarmos em um try catch para cada um, temos que subir em todos os níveis de métodos o "throws", por causa dos try's que estão sem catch. A gente pode sair espalhando catchs em todos os "try's", o que evitaria o "throws" na assinatura, mas corre o risco de ficar mto "feio" o nosso código. Vc pode ver qual abordagem lhe interessa mais. Geralmente gosto de tratar exceções que estão envolvidas nas regras de negócios e quando estão envolvidas em objetos/recursos que não estão sempre em nosso controle o erro (banco de dados fora por exemplo) eu prefiro apenas deixar o throws e deixar estourar um erro caso aconteça. Mas só pra deixar claro, isso é o que eu gosto de fazer haha.