Atividade de Laboratório - Desenvolvimento de Aplicações com JDBC

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

Java DataBase Connectivity - 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 a partir da página dos drivers JDBC que é 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 do banco. Em uma máquina Windows, isto pode ser feito usando o Administrador de fonte de dados ODBC, que fica no painel de controle.

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 SQL Server e clique o botão Concluir.

Em seguida, 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, o login e a senha que serão usados para acessar o banco, e depois clique em Avançar novamente.

Em seguida, especifique o nome do banco 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 (para isto é necessário que o servidor esteja rodando). Após testá-la, clique em OK para confirmar a criação.

  

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

Consulta a um Banco de Dados usando JDBC

O acesso ao banco através de um programa Java é bastante simples. Basta criar a conexão com o banco usando o driver JDBC e em seguida executar a consulta desejada. No programa abaixo foi feita uma consulta ao banco de dados dos clientes de uma instituição financeira, que foi utilizado nas aulas anteriores.

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

public class SelectConta {
    
    public static void main( String args[] ) {
        String url = "jdbc:odbc:Banco";
        String username = "sa";
        String password = "sa";
        Connection connection = null;
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url, username, password );
        }
        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".

Executando Stored Procedures a partir de Aplicações Java

Um procedimento armazenado pode ser criado no SQL Server manualmente ou utilizando os Wizards do Enterprise Manager. Neste último caso, podemos criar procedimentos simples para criação de tabelas e para inserção e remoção de dados.

Após conectar ao servidor do banco, os wizards podem ser acessados a partir do menu Tools -> Wizards. Selecione na janela abaixo o "Create Stored Procedure Wizard", que cria procedimentos armazenados, e clique o botão OK.

Na janela que surgirá, selecione a base de dados que será utilizada e clique em Avançar.

Na janela seguinte, indique que queremos criar uma stored procedure para inserção de dados na tabela contas, e clique novamente em Avançar.

Edite as propriedades da stored procedure de modo a remover a coluna rowguid, que foi criada automaticamente pelo SQL Server. Clique em OK para finalizar a criação.

Para acessar este procedimento, faremos algumas alterações no programa anterior para que obtenhamos os parâmetros de chamada da stored procedure e por fim a executemos no banco. 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";
        String username = "sa";
        String password = "sa";
        Connection connection = null;
        int agencia = 0;        
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url, username, password );
        }
        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();
        
            // Determina o número da conta
            ResultSet resultSet = statement.executeQuery( 
                "select max(conta) from contas" );
            resultSet.next();
            int conta = resultSet.getInt(1) + 1;
            
            // 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 insert_contas_1 " + conta + "," +
                nome + "," + agencia + ", 0.00" );
            
            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";
        String username = "sa";
        String password = "sa";
        Connection connection = null;
        Statement statement = null;        
        
        // Cria a conexão com o banco
        try {
            Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
            connection = DriverManager.getConnection( url, username, password );  
            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 a partir do Query Analyzer 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.

Projeto

Crie uma aplicação que possa ser usada pelos funcionários de um banco para:

A aplicação poderá ser feita em duplas, devendo ser feita preferencialmente em Java. Se desejar usar outra linguagem, consulte o professor.

A avaliação será efetuada na aula do dia 18/09 no período vespertino.