Atividade de Laboratório - JDBC

Nesta atividade de laboratório você irá criar aplicações Java que acessam bancos de dados.

A Base de Dados de Exemplo

Nos exemplos que serão apresentados será usado um esquema simplificado de base de dados de uma instituição financeira. Você deve criar o seguinte esquema no gerenciador de bancos de dados de sua preferência:

No esquema acima, os clientes da instituição possuem contas bancárias (tabela contas) que podem estar associadas a cartões de crédito (tabela cartoes) e a aplicações financeiras (tabela aplicacoes). Todas as transações efetuadas pelos clientes são registradas na tabela operacoes. Após criar as tabelas você as deve popular, para que tenhamos dados que possam ser utilizados nos exemplos.

Criando uma Conexão JDBC

O JDBC permite que aplicações escritas em Java acessem bancos de dados de forma bastante simples. Para acessar o banco de dados é preciso usar um driver JDBC que faça a conexão com o SGBD.

O driver JDBC para o SQL Server pode ser obtido aqui. Outros drivers podem ser encontrados na página de drivers JDBC mantida pela Sun. No caso de bancos de dados compatíveis com ODBC (Open DataBase Connectivity), podemos também usar um driver genérico JDBC para bancos ODBC que é distribuído pela Sun junto com o Java.

Para tornar a nossa aplicação portável entre bancos de dados, usaremos o driver ODBC. Para isto, você deve criar a conexão ODBC com o servidor de banco de dados. Em uma máquina Windows, isto pode ser feito usando o Administrador de fonte de dados ODBC, que fica no painel de controle, na pasta 'Ferramentas administrativas'.

Ao abrir o administrador você verá algo semelhante à janela abaixo. Clique em Adicionar para iniciar a criação da nova fonte de dados.

Na janela seguinte, selecione o SGBD que você utilizou para criar a base de dados e clique o botão Concluir.

Para criar a conexão com o SQL Server, proceda conforme descrito a seguir. Outros bancos de dados adotam um procedimento semelhante.

Inicialmente, dê um nome e uma descrição à fonte de dados, selecione o servidor e clique em Avançar.

Na próxima janela, especifique o modo de autenticação do Windows e clique em Avançar.

Em seguida, especifique o nome do banco de dados que será usado e clique mais uma vez em Avançar.

Na janela seguinte, altere as configurações padrão se julgar necessário e clique em Concluir.

Na janela seguinte você pode testar a fonte de dados. Após testá-la, clique em OK para confirmar a criação.

  

A partir de agora é possível acessar a base de dados de exemplo usando o driver JDBC para servidores ODBC.

Consulta a um Banco de Dados usando JDBC

O acesso ao banco de dados através de um programa Java é bastante simples. Basta criar a conexão com o banco de dados usando o driver JDBC e em seguida executar a consulta desejada. O programa Java abaixo consulta o saldo de uma conta da base de dados de exemplo.

import java.sql.*;
import java.util.*;

public class SelectConta {
    
    public static void main( String args[] ) {
        String url = "jdbc:odbc:Banco";
        Connection connection = null;
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url );
        }
        catch ( ClassNotFoundException cnfex ) {
            System.err.println( "Driver JDBC/ODBC nao encontrado." );
            cnfex.printStackTrace();
            System.exit( 1 );  
        }
        catch ( SQLException sqlex ) {
            System.err.println( "Falha na conexao." );
            sqlex.printStackTrace();
            System.exit( 1 );              
        }
        
        try {
            // Executa a query
            String query = "select conta, nome, agencia, saldo from contas";
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery( query );
            
            // Imprime o resultado
            System.out.println( "Contas do Banco" );
            System.out.println( "Conta\tNome\tAgencia\tSaldo" );
            while ( resultSet.next() ) {
                System.out.println( resultSet.getInt( 1 ) + "\t" + 
                resultSet.getString( 2 ) + "\t" +
                resultSet.getInt( 3 ) + "\t" + 
                resultSet.getFloat( 4 ) );
            }
            
            // Fecha a conexão com o banco
            statement.close();
            connection.close();
        }
        catch ( SQLException sqlex ) {
            sqlex.printStackTrace();
        }
    }
}

Exercício 1

Crie a fonte de dados ODBC e teste o código acima na sua máquina.

Caso deseje exibir os resultados em uma janela, é necessário adicionar o código para criação da interface gráfica e para mostrar os dados obtidos em uma tabela, como neste exemplo adaptado do livro Java: Como Programar.

Altere o código de modo a mostrar as outras tabelas do banco de dados.

Executando Stored Procedures a partir de Aplicações Java

Crie um procedimento armazenado (uma stored procedure) que faça a criação de novas contas na base de dados de exemplo, executando o seguinte código SQL:

CREATE PROCEDURE CriaConta
    @conta int,
    @nome varchar(50),
    @agencia int,
    @saldo int = 0
AS
BEGIN 
    INSERT INTO contas VALUES ( @conta, @nome, @agencia, @saldo )
END
GO

Para executar o procedimento criado, faremos algumas alterações no programa anterior para obter os parâmetros de chamada da stored procedure e em seguida executá-la no SGBD. O código a seguir mostra estas alterações:

import java.sql.*;
import java.util.*;
import javax.swing.JOptionPane;

public class CriaConta {
    
    public static void main( String args[] ) {
        String url = "jdbc:odbc:Banco";
        Connection connection = null;
        int agencia = 0;
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url );
        } catch ( ClassNotFoundException cnfex ) {
            System.err.println( "Driver JDBC/ODBC nao encontrado." );
            cnfex.printStackTrace();
            System.exit( 1 );
        } catch ( SQLException sqlex ) {
            System.err.println( "Falha na conexao." );
            sqlex.printStackTrace();
            System.exit( 1 );
        }
        
        // Cria a conta
        try {
            Statement statement = connection.createStatement();
            
            // Obtém o número da conta
            int conta = 0;
            while (conta == 0) {
                String cta = JOptionPane.showInputDialog(null,
                        "Entre com o número da conta:", "Cria Conta",
                        JOptionPane.QUESTION_MESSAGE);
                
                if (cta == null) { // botão cancel
                    statement.close();
                    connection.close();
                    System.exit(1);
                } else {
                    ResultSet resultSet = statement.executeQuery( 
                            "select conta from contas where conta = " + cta );
                    if (resultSet.next() == false) { // conta não encontrada
                        try {
                            conta = Integer.parseInt(cta.trim());
                        } catch (NumberFormatException nfe) {
                            System.err.println("Número de conta inválido.");
                        }
                    } else
                        JOptionPane.showMessageDialog(null,
                                "Conta "+ cta + " já existe.", "Cria Conta",
                                JOptionPane.ERROR_MESSAGE);
                }
            }
            
            // Obtém o nome do cliente
            String nome = JOptionPane.showInputDialog(null,
                    "Entre com o nome do cliente:", "Cria Conta",
                    JOptionPane.QUESTION_MESSAGE);
            
            if (nome == null) { // botão cancel
                statement.close();
                connection.close();
                System.exit(1);
            }
            
            // Obtém o número da agência
            String ag = JOptionPane.showInputDialog(null,
                    "Entre com o número da agencia:", "Cria Conta",
                    JOptionPane.QUESTION_MESSAGE);
            
            if (ag == null) { // botão cancel
                statement.close();
                connection.close();
                System.exit(1);
            }
            
            try {
                agencia = Integer.parseInt(ag.trim());
            } catch (NumberFormatException nfe) {
                System.err.println("Código da agência inválido.");
                statement.close();
                connection.close();
                System.exit(1);
            }
            
            // Executa a stored procedure
            statement.execute( "execute CriaConta " + conta + ", " + nome + ", " + agencia );
            
            JOptionPane.showMessageDialog(null, "Conta criada com sucesso.",
                    "Cria Conta", JOptionPane.INFORMATION_MESSAGE);
            
            // Fecha a conexão com o banco
            statement.close();
            connection.close();
            System.exit(0);
        } catch ( SQLException sqlex ) {
            sqlex.printStackTrace();
            System.exit(1);
        }
        
    }
}

Exercício 2

Crie a stored procedure no seu servidor e teste o código acima.

Em seguida, crie stored procedures para encerrar contas e para criar e cancelar cartões de crédito.

Executando Transações em Aplicações Java

A execução de transações a partir de aplicações exige alguns cuidados adicionais. Primeiramente precisamos desabilitar a efetivação automática com o método setAutoCommit(false) da conexão com o banco. Os comandos executados a partir de então são interpretados como parte de uma transação, que deve ser efetivada chamando o método commit() ou abortada através do método rollback().

O código abaixo executa uma transação de saque em uma conta corrente do banco.

import java.sql.*;
import java.util.*;
import javax.swing.JOptionPane;

public class SaqueConta {
    
    public static void main( String args[] ) {
        String url = "jdbc:odbc:Banco";
        Connection connection = null;
        Statement statement = null;        
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url );  
            connection.setAutoCommit(false);            
        }
        catch ( ClassNotFoundException cnfex ) {
            System.err.println( "Driver JDBC/ODBC nao encontrado." );
            cnfex.printStackTrace();
            System.exit( 1 );  
        }
        catch ( SQLException sqlex ) {
            System.err.println( "Falha na conexao." );
            sqlex.printStackTrace();
            System.exit( 1 );              
        }
        
        // Executa o saque
        try {
            statement = connection.createStatement();
        
            // Obtém o número da conta
            String conta = JOptionPane.showInputDialog(null, 
                "Entre com o número da conta", "Saque", 
                JOptionPane.QUESTION_MESSAGE);
            
            if (conta == null) { // botão cancel
                statement.close();
                connection.close();
                System.exit(1); 
            }
            
            // Obtém o saldo atual
            ResultSet resultSet = statement.executeQuery( 
                "select saldo from contas where conta = " + conta );
            resultSet.next();
            
            JOptionPane.showMessageDialog(null, "Saldo na conta: R$" + 
                resultSet.getFloat( 1 ) , "Saque", 
                JOptionPane.INFORMATION_MESSAGE);

            // Obtém o valor do saque
            String valor = JOptionPane.showInputDialog(null, "Entre com o valor do saque", 
                "Saque", JOptionPane.QUESTION_MESSAGE);   

            if (valor == null) { // botão cancel
                statement.close();
                connection.rollback();                   
                connection.close();
                System.exit(1); 
            }

            // Inicia a transaçao de saque
            statement.execute("insert into operacoes " +
                "values(" + conta + ",'Saque',"+ valor + ")");
            statement.execute( "update contas set saldo = saldo - " + valor + 
                "where conta = " + conta +"\n" );

            // Verifica o saldo restante na conta
            resultSet = statement.executeQuery( 
                "select saldo from contas where conta = " + conta );
            resultSet.next();
            
            JOptionPane.showMessageDialog(null, "Saldo após o saque: R$" + 
                resultSet.getFloat( 1 ) , "Saque", 
                JOptionPane.INFORMATION_MESSAGE);    
            
            // Obtém a confirmação do cliente
            int confirm = JOptionPane.showConfirmDialog(null, 
                "Confirmar o Saque?", "Saque", JOptionPane.YES_NO_OPTION);
            
            if (confirm == JOptionPane.YES_OPTION) { 
                // Saque confirmado
                connection.commit();        
                JOptionPane.showMessageDialog(null, "Retire o seu dinheiro.", 
                    "Saque", JOptionPane.INFORMATION_MESSAGE);  
            } else { 
                // Saque cancelado
                connection.rollback();   
                JOptionPane.showMessageDialog(null, "Saque cancelado.", 
                    "Saque", JOptionPane.ERROR_MESSAGE);  
            }
            
            // Fecha a conexão com o banco
            statement.close();
            connection.close();
            System.exit(0); 
        }
        catch ( SQLException sqlex ) {            
            sqlex.printStackTrace();
            System.exit(1);
        }
    }
}

Exercício 3

Teste o código acima. Com a transação em execução, tente acessar os dados usando diversos modos de bloqueio (mais detalhes aqui). Confirme o saque, e em seguida verifique que os dados foram alterados no banco. Em um segundo momento, cancele a transação e verifique que os dados não foram alterados no banco.

Sugestão de Atividade Prática Extra-Classe

Utilizando a base de dados de exemplo, crie uma aplicação que possa ser usada pelos funcionários de uma instituição financeira para:

Utilize transações sempre que julgar adequado.