Utilizacao de Rollback - Com Urgencia

Sei que para desfazer transacoes em meu banco (access) posso utilizar o um rollback, , gostaria que caso alguem respondesse podesse colocar parte da sintaxe utilizada, espero resposta …

Na interface Connection tem o método rollback

public void rollback(Savepoint savepoint)
throws SQLExceptionUndoes all changes made after the given Savepoint object was set.
This method should be used only when auto-commit has been disabled.

Parameters:
savepoint - the Savepoint object to roll back to

Só que antes, você deve executar o setAutoCommit(false) (o default é true), senão toda declaração insert, update, etc vai ser comitada no banco de dados

Também tem o método rollback() (sem parâmetros)

Nem todo driver JDBC suporta SavePoints.

Mas vc só pode dar rollback quando vc tá sem AutoCommit. Um processo simples é o mostrado abaixo: primeiro, fazemos um update normal, usando uma query pré-definida, pra mostrar onde o driver faz o commit. Depois, tiramos o auto commit e fazemos isso “na mão”:

// código que insere no banco.
Connection conn = createConnection();
conn.setAutoCommit(true); // esse é o default pra quase 100% dos casos.
PreparedStatement stmt = conn.prepareStatement(queries.getProperty("usuarios.count.update"));
stmt.setInt(1, count);
stmt.executeUpdate(); // auto-committed
stmt.close();

conn.setAutoCommit(false); // queremos uma transação
try {
  ... // faz o que tem que fazer
  conn.commit();
}
catch (SQLException e) {
  conn.rollback();
}
finally {
  conn.setAutoCommit(true); // voltamos ao estado original
}

Acho que deu pra sacar, né??

[]s

Valeu Galera, vc´s me ajudaram bastante, eu nao sabia que deveria colocar em meu catch, para desfazer …

Valeu, …

Ah, foi um exemplo!! Vc tem que dar rollback se deu algo errado na transação, neh?? :slight_smile:

Num contexto mais complexo, as condições para um rollback poderiam ser outras…

[]s

Realmente a J2SE obriga que a aplicação controle as transações.

Por isso sugiro que você tbm observe outros aspectos.

1- Chamar as transações de bancos de dados somente quando necessário, pois o uso indequado delas vai comprometer a performance.

2- Acessar o Banco de Dados usando um ConnectionPool, você pode fazer Download de um muito bom aqui:
http://cvs.apache.org/viewcvs/jakarta-commons/dbcp/

Ex:

import java.sql.*;

public class Database {

      private String driver, url, user, password;

      public Database(String driver, String url, String user, String pass) {
             this.driver = driver;
             this.url = url;
             this.user = user;
             this.pass = pass;
      }

      public void loadDriver() {
             try {
                 Class.forName( driver );
             } catch (Exception e) {
               e.printStackTrace();
             }
      }

      public Connection createConnection() throws SQLException {
            // o ideal é que este metodo obtenha a conexão de um POOL.
             Connection connection = null;
              if ( user == null || pass == null ) {
                   connection = DriverManager.getConnection( url );
              } else {
                   connection = DriverManager.getConnection( url, user, pass );
              }
              return connection;
      }

      
      public ArrayList select() throws SQLException {
             
             Connection connection = createConnection();
             connection.setAutoCommit(true);
             connection.close();
             
      }
      
      public void insert() throws Exception {
             Connection connection = null;
             try {      
             connection = createConnection();
             connection.setAutoCommit(false);
             
             // insert data
             
             connection.commit();
             connection.close();
             } catch (Exception e) {
               connection.rollback();
               connection.setAutoCommit(true);
               throw new Exception( e.toString() );
             }           
      
      }
      
      public void update() throws Exception {
             Connection connection = null;
             try {      
             connection = createConnection();
             connection.setAutoCommit(false);
             
             // update data
             
             connection.commit();
             connection.close();
             } catch (Exception e) {
               connection.rollback();
               connection.setAutoCommit(true);
               throw new Exception( e.toString() );
             }           
      
      }
      
      public void delete() throws SQLException {
 
             Connection connection = createConnection();
             connection.setAutoCommit(true);
             
             // delete data
             connection.close();     
      }      
}

Bom estudos.

Minha experiência também recomenda esconder o banco da aplicação, inclusive a parte de JDBC.

Eu sempre uso adapters para controlar o acesso ao banco, e muitas vezes tenho uma classe responsável por cuidar de uma parte do banco (um módulo, ou um tipo de acesso, ou mesmo um grupo de tabelas).

Mas quanto a connection pools, eu acho o dbcp do Jakarta impossível de usar. Primeiro pq não tem documentação suficiente, e depois porque vc acaba tendo que criar adapters muito complexos. Realmente, é uma API poderosíssima, mas eu não funciono muito bem sem Javadoc.

Eu até hoje prefiro fazer meu próprio pool com um LinkedList sincronizado. O problema é que vc tem que lembrar sempre de devolver a conexão pro banco, coisa que o dbcp faz sozinho. Mas como vc mesmo tá fazendo o adapter, não corre tanto risco.

E mesmo assim, eu sugiro que um método createConnection() sempre crie uma nova conexão. Ele não precisa ser público, é claro!! Mas use-o internamente para preencher seu pool e só. Pra pegar e devolver conexões, eu uso normalmente a dupla borrow/release:

/**
* cria uma nova conexão
**/
protected Connection createConnection(String connectUrl, String username, String password);

/**
* pega uma conexão do pool, bloqueando até haver alguma disponível. Equivale a borrowConnection(true);
**/
public Connection borrowConnection();

/**
* pega uma conexão do pool. Se block for true, bloqueia até ter uma conexão disponível, senão retorna null.
**/
public Connection borrowConnection(boolean block);

/**
* Devolve a conexão para o pool.
**/
public void releaseConnection(Connection c);

é bom pq vc pode criar conexões diferentes, ou pools de comportamento diferente, através de subclasses.

A utilização fica assim:

Connection c = adapter.borrowConnection();
c.setAutoCommit(false); // ah, vai ter transações!!
try {
  ... // faz o que tem que fazer
  c.commit();
}
catch(PauFeioException e) {
  c.rollback();
  throw e;
}
finally {
  adapter.releaseConnection(c);
}

[]s do duke!!