Problemas nos cadastros com os objetos DAO

Toda vez que uso o cadastro de endereço de entrega de clientes são criados dois objetos DAO, nas linhas abaixo:

private EndEntCliDAO endEntClientes;
private CliDAO clientes;

Mas dentro de cada classe DAO tem uma chamada a uma classe BD que faz a conexão. E o chamado a conexão pela classe GuiCadastroEndEnt.java está da seguinte forma:

if(!endEntClientes.bd.getConnection()) {
    JOptionPane.showMessageDialog(null, "Falha na conexão, o sistema será fechado!");
    System.exit(0);
}

Veja que o programa antigo tinha a necessidade de fazer uma referência ao objeto endEntClientes que é da classe DAO e ao objeto bd que é da classe BD para usar o método getConnection() que faz conexão com o banco de dados e retorna verdadeiro ou falso se não consegue conectar. Mas preciso mudar isto. só vai existir uma conexão que vai ser feita uma vez apenas. Pelo meu entendimento não posso mais ter um objeto bd ligado ao endEntClientes e outro ligado ao clientes (ambos de classes DAO diferentes. Fiz uma modificação no BD (que nosso colega Staroski recomendou) e preciso adequar os programas DAO e Cadastros. Pessoal do GUJ de uma olhada nos quatro programas (classes GuiCadastroEndEntCli, EndEntCliDAO, CliDAO, BD) que vão trabalhar juntos e me digam como posso usar o if(!endEntClientes.bd.getConnection()). Com a modificação achei que não era mais necessário fazer referência ao objeto DAO endEntClientes e poderia sempre usar a referência partindo do objeto criado bd. Lembre-se antes cada objeto DAO tinha um BD diferente mas não pode ser assim senão a conexão é feito toda vez que uso uma tabela diferente e estes quatro programas que trabalham juntos usam duas tabelas. As tabelas usadas são cli_entrega e clientes.

Abaixo vou colocar os quatro programas com extensão java, e espero uma postagem de vocês me indicando o que devo fazer em cada programa.

Muito obrigado,
Ronaldo

Este abaixo é o programa da classe GuiCadastroEndEntCli.java

package br.com.gui;

import bdclientes.CliDAO;
import bdclientes.enderecoEntregaCliente.EndEntCliDAO;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 *
 * @author Ronaldo Rodrigues Godoi
 */
public class GuiCadastroEndEntCli extends JPanel {
    
    JLabel lbCad_end_ent_cli, lbLargura, lbAltura, lbNome_razao;
    
    JLabel lbId, lbId_cliente, lbTelefone, lbCep, lbEndereco, lbNumero,
           lbComplemento, lbBairro, lbCidade, lbEstado;
    
    JButton btGravar, btAlterar, btExcluir, btNovo, btLocalizar, btCancelar, btSair;
    
    JTextField tfId, tfId_cliente, tfTelefone, tfCep, tfEndereco, tfNumero,
            tfComplemento, tfBairro, tfCidade, tfEstado;

    private EndEntCliDAO endEntClientes;
    private CliDAO clientes;
        
    public GuiCadastroEndEntCli() {
        
        inicializarComponentes();
        definirEventos();
        
    }
    
    public void inicializarComponentes() {
        setLayout(null);
        
        Dimension tela = Toolkit.getDefaultToolkit().getScreenSize();
        lbLargura = new JLabel(""+tela.width);
        lbAltura = new JLabel(""+tela.height);
        int altura = 1000;
        int largura = 1800;
        setBounds(0, 0, largura, altura);
        
        lbCad_end_ent_cli = new JLabel("Cadastro de Endereço de Entrega de Clientes");
        
        lbId = new JLabel("Id do endereço de Entrega");
        lbId_cliente = new JLabel("CPF ou CGC: ");
        lbTelefone = new JLabel("Telefone: ");
        lbCep = new JLabel("CEP: ");
        lbEndereco = new JLabel("Endereço: ");
        lbNumero = new JLabel("Número:");
        lbComplemento = new JLabel("Complemento: ");
        lbBairro = new JLabel("Bairro: ");
        lbCidade = new JLabel("Cidade: ");
        lbEstado = new JLabel("Estado: ");
        lbNome_razao = new JLabel("Nome ou Razão: ");
                
        tfId = new JTextField(10);
        tfId_cliente = new JTextField(20);
        tfTelefone = new JTextField(17); 
        tfCep = new JTextField(9);
        tfEndereco = new JTextField(60);
        tfNumero = new JTextField(10);
        tfComplemento = new JTextField(40);
        tfBairro = new JTextField(60);
        tfCidade = new JTextField(40);
        tfEstado = new JTextField(2);
        
        btGravar = new JButton(null, new ImageIcon("c:/icones/icon12/gravar.gif"));
        btGravar.setToolTipText("Gravar");
        btAlterar = new JButton(null, new ImageIcon("c:/icones/icon12/alterar.gif"));
        btAlterar.setToolTipText("Alterar");
        btExcluir = new JButton(null, new ImageIcon("c:/icones/icon12/excluir.gif"));
        btExcluir.setToolTipText("Excluir");
        btLocalizar = new JButton(null, new ImageIcon("c:/icones/icon12/localizar.png"));
        btLocalizar.setToolTipText("Localizar");
        btNovo = new JButton(null, new ImageIcon("c:/icones/icon12/novo.gif"));
        btNovo.setToolTipText("Novo");
        btCancelar = new JButton(null, new ImageIcon("c:/icones/icon12/cancelar.gif"));
        btCancelar.setToolTipText("Cancelar");
        btSair = new JButton(null, new ImageIcon("c:/icones/icon12/sair.png"));
        btSair.setToolTipText("Sair");
        
        lbCad_end_ent_cli.setBounds(35, 75, 250, 25);
        
        lbId.setBounds(35, 175, 200, 25);
        tfId.setBounds(250, 175, 75, 25);
        lbId_cliente.setBounds(35, 250, 100, 25);
        tfId_cliente.setBounds(115, 250, 150, 25);
        lbNome_razao.setBounds(35, 280, 400, 25);
        lbTelefone.setBounds(450, 250, 100, 25);
        tfTelefone.setBounds(520, 250, 100, 25);
        lbCep.setBounds(35, 325, 100, 25);
        tfCep.setBounds(75, 325, 100, 25);
        lbEndereco.setBounds(200, 325, 100, 25);
        tfEndereco.setBounds(270, 325, 300, 25);
        lbNumero.setBounds(665, 325, 100, 25);
        tfNumero.setBounds(735, 325, 100, 25);
        lbComplemento.setBounds(35, 400, 150, 25);
        tfComplemento.setBounds(130, 400, 225, 25);
        lbBairro.setBounds(400, 400, 50, 25);
        tfBairro.setBounds(495, 400, 250, 25);
        lbCidade.setBounds(35, 475, 200, 25);
        tfCidade.setBounds(90, 475, 280, 25);
        lbEstado.setBounds(450, 475, 100, 25);
        tfEstado.setBounds(500, 475, 30, 25);
        
        btNovo.setBounds     (45, 550, 75, 75);
        btLocalizar.setBounds(145, 550, 75, 75);
        btGravar.setBounds   (245, 550, 75, 75);
        btAlterar.setBounds  (345, 550, 75, 75);
        btExcluir.setBounds  (445, 550, 75, 75);
        btCancelar.setBounds (545, 550, 75, 75);
        btSair.setBounds     (645, 550, 75, 75);
        lbLargura.setBounds  (745, 550, 75, 75);
        lbAltura.setBounds   (845, 550, 75, 75);
        
        add(lbCad_end_ent_cli);
        add(lbLargura);
        add(lbAltura);
        add(lbId);
        add(tfId);
        add(lbId_cliente);
        add(tfId_cliente);
        add(lbNome_razao);
        add(lbTelefone);
        add(tfTelefone);
        add(lbCep);
        add(tfCep);
        add(lbEndereco);
        add(tfEndereco);
        add(lbNumero);
        add(tfNumero);
        add(lbComplemento);
        add(tfComplemento);
        add(lbBairro);
        add(tfBairro);
        add(lbCidade);
        add(tfCidade);
        add(lbEstado);
        add(tfEstado);
        
        add(btNovo);
        add(btLocalizar);
        add(btGravar);
        add(btAlterar);
        add(btExcluir);
        add(btCancelar);
        add(btSair);
        
        //setResizable(false);
        setBotoes(true, true, false, false, false, false);
        endEntClientes = new EndEntCliDAO();
        clientes = new CliDAO();
        
        if(!endEntClientes.bd.getConnection()) {
            JOptionPane.showMessageDialog(null, "Falha na conexão, o sistema será fechado!");
            System.exit(0);
        }
    }
    
    public void definirEventos() {
        
        tfId_cliente.addFocusListener(new FocusAdapter() {
            public void focusLost(FocusEvent e) {
                clientes.cliente.setId_cgc_cpf(tfId_cliente.getText());
                if(!clientes.localizar()) {
                    JOptionPane.showMessageDialog(null, "Cliente não cadastrado!");
                    tfId.requestFocus();
                } else {
                    tfTelefone.requestFocus();
                    lbNome_razao.setText("Nome ou Razão: " + 
                            clientes.cliente.getNome_razao());
                }
                return;
            }
        });
        
        btSair.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                endEntClientes.bd.close();
                setVisible(false);
            }
        });
        
        btNovo.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                limparCampos();
                setBotoes(false, false, true, false, false, true);
            }
        });
        
        btCancelar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                limparCampos();
            }
        });
        
        btGravar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                
                if(tfId.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O código do endereço de entrega não pode estar vazio!");
                    tfId.requestFocus();
                    return; 
                }
                
                if(tfId_cliente.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O CPF ou CGC não podem ser vazios!");
                    tfId_cliente.requestFocus();
                    return;
                }
                
                if(tfCep.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O CEP não pode ser vazio!");
                    tfCep.requestFocus();
                    return;
                }
                
                if(tfEndereco.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O Endereço não pode ser vazio!");
                    tfEndereco.requestFocus();
                    return;
                }
                
                if(tfNumero.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O número não pode ser vazio!");
                    tfNumero.requestFocus();
                    return;
                } else {
                    try {
                        int numero = Integer.parseInt(tfNumero.getText());
                    } catch (Exception erro) {
                        JOptionPane.showMessageDialog(null, "O número não pode contém caracteres invalidos!");
                        tfNumero.requestFocus();
                        return;
                    }
                }
                
                if(tfCidade.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "A cidade não pode ser vazia!");
                    tfCidade.requestFocus();
                    return;
                }
                
                if(tfBairro.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O bairro não pode ser vazio");
                    tfBairro.requestFocus();
                    return;
                }
                
                if(tfEstado.getText().equals("")) {
                    JOptionPane.showMessageDialog(null, "O estado não pode estar vazio!");
                    tfEstado.requestFocus();
                    return;
                }
                
                endEntClientes.cli_entrega.setId(tfId.getText());
                endEntClientes.cli_entrega.setId_cliente(tfId_cliente.getText());
                endEntClientes.cli_entrega.setTelefone(tfTelefone.getText());
                endEntClientes.cli_entrega.setCep(tfCep.getText());
                endEntClientes.cli_entrega.setEndereco(tfEndereco.getText());
                endEntClientes.cli_entrega.setNumero(tfNumero.getText());
                endEntClientes.cli_entrega.setComplemento(tfComplemento.getText());
                endEntClientes.cli_entrega.setBairro(tfBairro.getText());
                endEntClientes.cli_entrega.setCidade(tfCidade.getText());
                endEntClientes.cli_entrega.setEstado(tfEstado.getText());
                                
                JOptionPane.showMessageDialog(null, endEntClientes.atualizar(EndEntCliDAO.INCLUSAO));
                limparCampos();
            }
        });
        
        btAlterar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                endEntClientes.cli_entrega.setId(tfId.getText());
                endEntClientes.cli_entrega.setTelefone(tfTelefone.getText());
                endEntClientes.cli_entrega.setCep(tfCep.getText());
                endEntClientes.cli_entrega.setEndereco(tfEndereco.getText());
                endEntClientes.cli_entrega.setNumero(tfNumero.getText());
                endEntClientes.cli_entrega.setComplemento(tfComplemento.getText());
                endEntClientes.cli_entrega.setBairro(tfBairro.getText());
                endEntClientes.cli_entrega.setCidade(tfCidade.getText());
                endEntClientes.cli_entrega.setEstado(tfEstado.getText());
                JOptionPane.showMessageDialog(null, endEntClientes.atualizar(EndEntCliDAO.ALTERACAO));
                limparCampos();
            }
        });
        
        btExcluir.addActionListener(new ActionListener(){ 
            public void actionPerformed(ActionEvent e) {
                endEntClientes.cli_entrega.setId(tfId.getText());
                endEntClientes.localizar();
                int n = JOptionPane.showConfirmDialog(null, endEntClientes.cli_entrega.getId_cliente(),
                        "Excluir o endereço de entrega de cliente? ", JOptionPane.YES_NO_OPTION);
                if(n == JOptionPane.YES_OPTION) {
                    JOptionPane.showMessageDialog(null, endEntClientes.atualizar(EndEntCliDAO.EXCLUSAO));
                    limparCampos();
                }
            }
        });
        
        btLocalizar.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                atualizarCampos();
            }
        });
        
    }
    
    public void limparCampos() {
        tfId.setText("");
        tfId_cliente.setText("");
        tfTelefone.setText("");
        tfCep.setText("");
        tfEndereco.setText("");
        tfNumero.setText("");
        tfComplemento.setText("");
        tfBairro.setText("");
        tfCidade.setText("");
        tfEstado.setText("");
        setBotoes(true, true, false, false, false, false);
    }
    
    public void atualizarCampos() {
        endEntClientes.cli_entrega.setId(tfId.getText());
        if(endEntClientes.localizar()) {
            tfId_cliente.setText(endEntClientes.cli_entrega.getId_cliente());
            tfTelefone.setText(endEntClientes.cli_entrega.getTelefone());
            tfCep.setText(endEntClientes.cli_entrega.getCep());
            tfEndereco.setText(endEntClientes.cli_entrega.getEndereco());
            tfNumero.setText(endEntClientes.cli_entrega.getNumero());
            tfComplemento.setText(endEntClientes.cli_entrega.getComplemento());
            tfBairro.setText(endEntClientes.cli_entrega.getBairro());
            tfCidade.setText(endEntClientes.cli_entrega.getCidade());
            tfEstado.setText(endEntClientes.cli_entrega.getEstado());
            setBotoes(true, true, false, true, true, true);
        } else {
            JOptionPane.showMessageDialog(null, "Endereço de Cliente não encontrado! " + endEntClientes.cli_entrega.getId());
            limparCampos();
        }
    }
    
    public void setBotoes(boolean bNovo, boolean bLocalizar, boolean bGravar,
            boolean bAlterar, boolean bExcluir, boolean bCancelar) {
        btNovo.setEnabled(bNovo);
        btLocalizar.setEnabled(bLocalizar);
        btGravar.setEnabled(bGravar);
        btAlterar.setEnabled(bAlterar);
        btExcluir.setEnabled(bExcluir);
        btCancelar.setEnabled(bCancelar);
    }
    
}

/*
Table: cli_entrega
Columns:
id varchar(10) PK 
id_cliente varchar(10) 
telefone varchar(20) 
cep varchar(9) 
endereco varchar(60) 
numero int 
complemento varchar(40) 
bairro varchar(60) 
cidade varchar(40) 
estado varchar(2)
*/

Este abaixo é o programa da classe EndEntCliDAO.java

package bdclientes.enderecoEntregaCliente;

import empresaiv.BD;
import java.sql.*;

/**
 *
 * @author Ronaldo Rodrigues Godoi
 */
public class EndEntCliDAO {
    
    public Cli_entregas cli_entrega;
    public BD bd;
    private PreparedStatement statement;
    private ResultSet resultSet;
    private String men, sql;
    public static final byte INCLUSAO = 1;
    public static final byte ALTERACAO = 2;
    public static final byte EXCLUSAO = 3;
    
    public EndEntCliDAO() {
        bd = BD.getInstance();
        cli_entrega = new Cli_entregas();
    }
    
    public boolean localizar() {
        sql = "select * from cli_entrega where id = ?";
        try {
            statement = bd.connection.prepareStatement(sql);
            statement.setString(1, cli_entrega.getId());
            resultSet = statement.executeQuery();
            resultSet.next();
            cli_entrega.setId_cliente(resultSet.getString(2));
            cli_entrega.setTelefone(resultSet.getString(3));
            cli_entrega.setCep(resultSet.getString(4));
            cli_entrega.setEndereco(resultSet.getString(5));
            cli_entrega.setNumero(resultSet.getString(6));
            cli_entrega.setComplemento(resultSet.getString(7));
            cli_entrega.setBairro(resultSet.getString(8));
            cli_entrega.setCidade(resultSet.getString(9));
            cli_entrega.setEstado(resultSet.getString(10));
            return true;
        } catch(SQLException erro) {
            System.out.println("erro: " + erro.toString() + sql + cli_entrega.getId());
            return false;
        }
    }
    
    public String atualizar(int operacao) {
        men = "Operação realizada com sucesso!";
        try {
            if(operacao == INCLUSAO) {
                sql = "insert into cli_entrega values (?, ?, ?, ?, ?, ?, ? , ?, ?, ?)";                
                statement = bd.connection.prepareStatement(sql);
                statement.setString(1, cli_entrega.getId());
                statement.setString(2, cli_entrega.getId_cliente());
                statement.setString(3, cli_entrega.getTelefone());
                statement.setString(4, cli_entrega.getCep());
                statement.setString(5, cli_entrega.getEndereco());
                statement.setString(6, cli_entrega.getNumero());
                statement.setString(7, cli_entrega.getComplemento());
                statement.setString(8, cli_entrega.getBairro());
                statement.setString(9, cli_entrega.getCidade());
                statement.setString(10, cli_entrega.getEstado());    
                System.out.println("Id: " + cli_entrega.getId() +
                        " Id cliente: " + cli_entrega.getId_cliente() + 
                        " Telefone: " + cli_entrega.getTelefone());
            } else if(operacao == ALTERACAO) {
                sql = "update cli_entrega set id_cliente = ?,"
                        + " telefone = ?,"
                        + " cep = ?,"
                        + " endereco = ?,"
                        + " numero = ?,"
                        + " complemento = ?,"
                        + " bairro = ?,"
                        + " cidade = ?,"
                        + " estado = ? where id = ?";
                statement = bd.connection.prepareStatement(sql);
                statement.setString(10, cli_entrega.getId());
                statement.setString(1, cli_entrega.getId_cliente());
                statement.setString(2, cli_entrega.getTelefone());
                statement.setString(3, cli_entrega.getCep());
                statement.setString(4, cli_entrega.getEndereco());
                statement.setString(5, cli_entrega.getNumero());
                statement.setString(6, cli_entrega.getComplemento());
                statement.setString(7, cli_entrega.getBairro());
                statement.setString(8, cli_entrega.getCidade());
                statement.setString(9, cli_entrega.getEstado());
            } else if(operacao == EXCLUSAO) {
                sql = "delete from cli_entrega where id = ?";
                statement = bd.connection.prepareStatement(sql);
                statement.setString(1, cli_entrega.getId());
            }
            
            if(statement.executeUpdate() == 0) {
                men = "Falha na operação!";
            }
            
        } catch (SQLException erro) {
            men = "Falha na operação! " + erro.toString()+" "+sql;
        }
        
        return men;
        
    }
    
}

/*
Table: cli_entrega
Columns:
id varchar(10) PK 
id_cliente varchar(16) 
telefone varchar(20) 
cep varchar(9) 
endereco varchar(60) 
numero int 
complemento varchar(40) 
bairro varchar(60) 
cidade varchar(40) 
estado varchar(2)
*/

Este programa abaixo é o CliDAO:

package bdclientes;

/**
 *
 * @author Ronaldo Rodrigues Godoi
 */

import empresaiv.BD;
import java.sql.*;

/**
 *
 * @author Ronaldo R. Godoi
 */
public class CliDAO {
    
    public Clientes cliente;
    public BD bd;
    private PreparedStatement statement;
    private ResultSet resultSet;
    private String men, sql;
    public static final byte INCLUSAO = 1;
    public static final byte ALTERACAO = 2;
    public static final byte EXCLUSAO = 3;
    
    public CliDAO() {
        bd = BD.getInstance();
        cliente = new Clientes();
    }
    
    
    
    public boolean localizar() {
        sql = "select * from clientes where id_cgc_cpf = ?";
        try {
            statement = bd.connection.prepareStatement(sql);
            statement.setString(1, cliente.getId_cgc_cpf());
            resultSet = statement.executeQuery();
            resultSet.next();
            cliente.setId_cgc_cpf(resultSet.getString(1));
            cliente.setCep(resultSet.getString(6));
            cliente.setEndereco(resultSet.getString(7));
            cliente.setNumero(resultSet.getString(8));
            cliente.setComplemento(resultSet.getString(9));
            cliente.setBairro(resultSet.getString(10));
            cliente.setCidade(resultSet.getString(11));
            cliente.setEstado(resultSet.getString(12));
            cliente.setData_cadastro("" + resultSet.getString(13));
            return true;
        } catch(SQLException erro) {
            System.out.println("erro: " + erro.toString() + sql + cliente.getId_cgc_cpf());
            return false;
        }
    }
    
    public String atualizar(int operacao) {
        men = "Operação realizada com sucesso!";
        try {
            if(operacao == INCLUSAO) {
                sql = "insert into clientes values (?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?)";                
                statement = bd.connection.prepareStatement(sql);
                statement.setString(1, cliente.getId_cgc_cpf());
                statement.setString(2, cliente.getFisica_juridica());
                statement.setString(3, cliente.getNome_razao());
                statement.setString(4, cliente.getEmail());
                statement.setString(5, cliente.getTelefone());
                statement.setString(6, cliente.getCep());
                statement.setString(7, cliente.getEndereco());
                statement.setString(8, cliente.getNumero());
                statement.setString(9, cliente.getComplemento());
                statement.setString(10, cliente.getBairro());
                statement.setString(11, cliente.getCidade());
                statement.setString(12, cliente.getEstado());
                statement.setString(13, cliente.getData_cadastro());
                
            } else if(operacao == ALTERACAO) {
                sql = "update clientes set fisica_juridica = ?,"
                        + " nome_razao = ?,"
                        + " email = ?,"
                        + " telefone = ?,"
                        + " cep = ?,"
                        + " endereco = ?,"
                        + " numero = ?,"
                        + " complemento = ?,"
                        + " bairro = ?,"
                        + " cidade = ?,"
                        + " estado = ?,"
                        + " data_cadastro = ? where id_cgc_cpf = ?";
                statement = bd.connection.prepareStatement(sql);
                statement.setString(13, cliente.getId_cgc_cpf());
                statement.setString(1, cliente.getFisica_juridica());
                statement.setString(2, cliente.getNome_razao());
                statement.setString(3, cliente.getEmail());
                statement.setString(4, cliente.getTelefone());
                statement.setString(5, cliente.getCep());
                statement.setString(6, cliente.getEndereco());
                statement.setString(7, cliente.getNumero());
                statement.setString(8, cliente.getComplemento());
                statement.setString(9, cliente.getBairro());
                statement.setString(10, cliente.getCidade());
                statement.setString(11, cliente.getEstado());
                statement.setString(12, cliente.getData_cadastro());
            } else if(operacao == EXCLUSAO) {
                sql = "delete from clientes where id_cgc_cpf = ?";
                statement = bd.connection.prepareStatement(sql);
                statement.setString(1, cliente.getId_cgc_cpf());
            }
            
            if(statement.executeUpdate() == 0) {
                men = "Falha na operação!";
            }
            
        } catch (SQLException erro) {
            men = "Falha na operação! " + erro.toString()+" "+sql;
        }
        
        return men;
        
    }
    
}

/*
Columns:
id_cgc_cpf varchar(16) PK 
fisica_juridica varchar(1) 
nome_razao varchar(60) 
email varchar(80) 
telefone varchar(20) 
cep varchar(9) 
endereco varchar(60) 
numero int 
complemento varchar(40) 
bairro varchar(60) 
cidade varchar(40) 
estado varchar(2) 
data_cadastro datetime
*/

Este programa abaixo é o BD.java:

/**
 * @author Ronaldo R. Godoi, contibuição de Staroski
 */
public final class BD {
    
    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String DBNAME = "empresa";
    private static final String URL = "jdbc:mysql://localhost:3306/" + DBNAME;
    private static final String LOGIN = "root";
    private static final String SENHA = "04latosensu10";
    
    /**
     * Única instância desta classe
     */
    private static BD instance;
    
    /**
     * Obtém a única instância desta classe
     */
    public static synchronized BD getInstance() {
        if (instance == null) {
            instance = new BD();
        }
        return instance;
    }
    
    public final Connection connection;
    
    /**
     * Construtor privado
     */
    private BD() {
        try {
            Class.forName(DRIVER);
            connection = DriverManager.getConnection(URL, LOGIN, SENHA);
            System.out.println("Conectou! ");
        } catch (Throwable t) {
            throw new RuntimeException("Erro ao inicializar BD", t);
        }
    }

    /**
     * Fecha a conexão com o banco
     */
    public void close() {
        try {
            connection.close();
            System.out.println("Desconectou...");
        } catch(Throwable t) {
            throw new RuntimeException("Erro ao fechar BD", t);
        }
    }
}

Você não precisa mais desse if pois a nova classe BD que você tem vai lançar uma exceção se não for possível obter a instância dela.

Você também não precisa mais declarar o BD como variável de instância nos seus DAOs, utilize apenas variáveis locais quando precisar acessar o banco.

Na verdade vejo que para a maioria das coisas você só usa variáveis de instância, isso é desnecessário.
PreparedStatement, ResultSet, mensagens e queries SQL podem ser variáveis locais, pois não faz sentido manter elas como atributos do seu objeto, veja:

public boolean localizar() {
    String sql = "select * from cli_entrega where id = ?"; // variável local
    try {
        BD bd = BD.getInstance(); // variável local
        Prepared statement = bd.connection.prepareStatement(sql); // variável local
        statement.setString(1, cli_entrega.getId());
        Result resultSet = statement.executeQuery(); // variável local
        resultSet.next();
        cli_entrega.setId_cliente(resultSet.getString(2));
        cli_entrega.setTelefone(resultSet.getString(3));
        cli_entrega.setCep(resultSet.getString(4));
        cli_entrega.setEndereco(resultSet.getString(5));
        cli_entrega.setNumero(resultSet.getString(6));
        cli_entrega.setComplemento(resultSet.getString(7));
        cli_entrega.setBairro(resultSet.getString(8));
        cli_entrega.setCidade(resultSet.getString(9));
        cli_entrega.setEstado(resultSet.getString(10));
        return true;
    } catch(SQLException erro) {
        System.out.println("erro: " + erro.toString() + sql + cli_entrega.getId());
        return false;
    }
}

Utilize variáveis de instância somente se você precisa armazenar determinada informação ao longo do ciclo de vida do seu objeto.

Pode sim, por isso que a classe BD agora é um singleton, isso garante que em todo lugar onde você for utilizá-la, estará utilizando a mesma instância.

Antes você fazia um new BD() em cada DAO, o que implicava em um novo objeto e uma nova conexão a ser criada com o método getConnection().

Agora não, quando você chama o método BD.getInstance() a classe BD só vai ser instanciada uma única vez e a cada vez que chamar o método BD.getInstance() estará obtendo a instância que já existe.

1 curtida

Cada vez que eu chamar uma classe DAO desse banco de dados ela verificará se existe conexão e se não houver o BD criará através do instance, correto?

Estou com dificuldade para achar o uso de close() no fim dos trabalhos com o programa de cadastro. Quem chama o close() para fechar o banco de dados? Pelo que entendi ou GuiCadastroEndEntCli ou uma das classes DAO tem que chamar esse método para que a conexão seja fechada e o banco de dados não permaneça aberto. Quem deve chamar close() (que é método criado por BD)?

Outra coisa parece que eu poderia estabelecer a conexão antes de entrar no construtor da Classe que é o programa de cadastro (GuiCadastroEndEntCli.java), isso não é verdade não é? Eu tenho que criar a conexão dentro do contrutor da classe correto? Alias, já não se trata de criar a conexão mas verificar se ela existe através de um método do BD e deixar este método do BD criar a conexão se ela não existir, não é isto?

Vai demorar um pouco até meu sisteminha rodar de novo porque muita coisa mudou quando a classe BD aprendeu a verificar se a conexão já estava estabelecida e o banco de dados aberto. Que pena, ele estava rodando!

Mas prossigamos. Se eu não preciso mais chamar da forma abaixo:

if(!endEntClientes.bd.getConnection()) {
    JOptionPane.showMessageDialog(null, "Falha na conexão, o sistema será fechado!");
    System.exit(0);
}

Porque o BD já verifica se a conexão está criada e não fica abrindo várias conexões, como devo chamar dentro do GuiCadastroEndEntCli.java o getConnection() (já que não será mais com um if e também não poderá fazer referência a endEntClientes, nem a clientes) para acessar o objeto getConnetion() do BD? Se este objeto é privado? Não deveria existir um único objeto da clase BD que de maneira pública pudesse ser chamado diretamente da forma abaixo, para abrir a conexão e o banco de dados dentro do construtor do programa de cadastro?


bd.getConnetion();

Na mesma posição do antigo if que chamava if(!endEntClientes.bd.getConnection()) {…

Pessoal, Staroski, minha cabeça está um pouco bagunçada e parece que não são necessárias grandes alterações nos meus programinhas, mas certeiras correções técnicas. Sei que é pedir muito mas discorra sobre a solução e me de a sintaxe exata de alguns “comandos” (por exemplo, onde e como estabelecer o uso do novo getConnetion()).

Um grande abraço, ao esforçado pessoal do GUJ,
Ronaldo

Não, a conexão é aberta na primeira vez que você chamar o método BD.getInstance().

Você vai chamar o close() imediatamente antes de fazer um System.exit.

Esse objeto você obtém através do método BD.getInstance()
A classe BD continua tendo um atributo público do tipo Connection.

Esse método não existe mais, a conexão é aberta na primeira vez que é chamado o método getInstance()

Cara a única coisa que mudou é que não precisa mais fazer aquele if (bd.getConnection()) e ao invés de fazer new BD(), você vai fazer BD.getInstance().

O que você alterou além disso?

O sisteminha está rodando e não está com erros de execução, não tem nada ilegal nele. Mas tem erro de lógica e vou demorar um pouco para corrigir, ainda não peguei o jeito (o que vai demorar uma eternidade se for nesse ritmo).

Gostaria que vocês comentassem os trechos abaixo, onde eu encontrei o fechamento da conexão:

Programa GuiCadastroEndEntCli.java
    btSair.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            endEntClientes.bd.close();
            setVisible(false);
        }
    });

Queria perguntar se o uso da linha endEntClientes.bd.close() está correto. Como vocês (Staroski e outros) já me disseram, ele só cria o elemento bd uma vez por causa do getInstance() (por favor desconsidere o rigor teórico de minhas afirmações, ainda não aprendi direitinho a terminologia do java). Mas existem duas tentativas de criar bd. Lembra: cada vez que chamo um DAO ele verifica se a conexão existe, então gostaria de perguntar, uma vez que duas classe DAO são chamadas nesse programa. Eu poderia dizer clientes.bd.close() da mesma forma que digo endEntClientes.bd.close()?

Veja a forma como eu crio o elemento bd, neste programa:
private EndEntCliDAO endEntClientes;
private CliDAO clientes;

São feitas duas tentativas de criar bd porque são chamadas duas classe DAO, na minha ignorância eu não sei se o comando clientes.bd.close() funcionaria pois, como vocês podem ver o primeiro chamado cria a conexão e o objeto bd, o segundo chamado não cria conexão pois ele verifica através do método getInstance. Então eu pergunto: para fechar a conexão e o banco de dados eu tenho que chamar por endEntClientes.bd.close() e não posso chamar por clientes.bd.close()? Isto porque acho que bd pertence a endEntClientes, uma vez que foi a primeira tentativa de criar bd. Esta correto o meu raciocínio? O objeto bd pertence a endEntClientes, ou tanto faz porque de uma forma mágica o objeto bd.close() pode ser acessado por qualquer objeto DAO que possuir uma classe close()?

Essa hipótese não me parece lógica porque apesar de bd ser declarado em todas as classes DAO só cria conexão na primeira chamada. Daí eu pergunto a segunda linha que cria um objeto classe DAO não danifica nosso bd? Veja como está nas classe DAO:

Primeiro chamado a DAO do programa de cadastro:

public class CliDAO {
    
    public Clientes cliente;
    public BD bd;

Segundo chamado a DAO do programa de cadastro:

public class EndEntCliDAO {
    
    public Cli_entregas cli_entrega;
    public BD bd;

Minha dúvida é se ao declarar public BD bd duas vezes a segunda não destrói a primeira. Gente, pelo amor de Deus, perdoem tanta ignorância. Mas me digam, qual a conclusão de vocês? Posso chamar qualquer um dos dois endEntClientes.bd.close() ou clientes.bd.close()?

Um grande abraço ao pessoal do GUJ,
Ronaldo

Pelas suas perguntas me parece que ainda não lhe está claro o que é uma classe e o que é um objeto.

Você já reparou que o método getInstance() da classe BD é estático?
E ele inicializa um atributo estático do tipo BD somente se esse atributo ainda não foi inicializado.
Você pode ter trocentas variáveis bd espalhadas pelas suas classes, como eles são inicializadas através do método BD.getInstance(), elas vão referenciar o mesmo objeto, o mesmo endereço de memória, entende?

Tanto o endEntClientes quanto clientes possuem um atributo bd, porque você optou em fazer assim, só você pode responder.
Minha sugestão é usar sempre as variáveis do tipo BD como sendo variáveis locais.

Você não precisa acessar um atributo do endEntClientes é só você fazer isso:

BD.getInstance().close();

O atributo bd tanto do endEntClientes quanto do clientes referência o mesmo objeto retornado pelo BD.getInstance() então é indiferente qual bd você vai usar, eles são o mesmo objeto.

Recomendo você apagar o atributo bd dessas classes e utilizar somente variáveis locais.

Acho que você ainda não entendeu o que o getInstance() faz, sugiro que coloque os seguintes prints:

public static synchronized BD getInstance() {
    if (instance == null) {
        System.out.println("Criando objeto da classe BD");
        instance = new BD();
    }
    System.out.println("Retornando objeto existente da classe BD");
    return instance;
}
1 curtida

Gente, eu gostaria de adicionar uma questão.

Pelo que pesquisei, o que o @anyblueangel3 tá fazendo é uma ideia muito ruim.

Criar uma conexão no inicio do programa e mantê-la aberta até o usuário fechar pode causar varios problemas. Por exemplo: a conexão poderia fechar devido ao tempo ocioso por devido a alguma falha.

Do que eu entendi nas minhas pesquisas, o correto seria vc abrir e fechar a conexão a cada operação. Ou seja, se for inserir algum dado, vc abre a conexão, insere o dado e fecha; se for pegar uma lista de entidades, vc abre a conexão, faz o select e fecha.

O problema óbvio desta abordagem é que criar conexões é custoso pro sistema e é por isso que para minimizar os impactos negativos na performance do programa, nós podemos usar connections pools. Basicamente nós criamos uma certa quantidade de conexões e as deixamos em espera, então, sempre que precisamos nos conectar pegamos uma destas conexões ociosas, então, quando invocamos o método close, na verdade não estamos fechando, mas sim devolvendo ela para a pool, ou seja, para a lista de conexões ociosas.

Há bibliotecas de terceiros que servem para gerenciar este pool, mas alguns drivers JDBC já implementam este conceito sem precisar de terceiros. Parece que o driver do MySQL tem esta funcionalidade, eu só não sei como usar, na documentação até tem um exemplo, mas é usando algum application server, se quiser olhar:

https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-j2ee-concepts-connection-pooling.html

Eu estudei um pouco usando MariaDB e na página do driver mostra um exemplo mais facil de aplicar, se tiver curiosidade de ver como é neste banco de dados:

Mas que que vcs acham, é isso mesmo que eu entendi?

Cordiais saudações, wldomiciano,

Entendi seu ponto de vista, mas a conexão não vai ficar aberta todo tempo. Por enquanto estou mexendo com cadastros então cada vez que entre em uma classe (programa) de um cadastro do banco de dados eu abro a conexão, cada vez que saio deste programa fecho a conexão.

Atenciosamente,
Ronaldo

1 curtida

Fiz a modificação de colocar BD.getInstance().close() e abrir conforme você me orientou Staroski, mas agora tem surgido uns probleminhas, parece que ele fecha a conexão e não abre de novo quando eu preciso dela. Ele tem respondido que clientes que estão cadastrados não estão. Veja algumas mensagens de tempo de execução:

run:
Conectou! 
Desconectou...
Desconectou...
erro: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.select * from clientes where id_cgc_cpf = ?17561408803
erro: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.select * from clientes where id_cgc_cpf = ?17561408803
erro: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.select * from clientes where id_cgc_cpf = ?1
erro: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.select * from clientes where id_cgc_cpf = ?17561408803
Desconectou...
BUILD SUCCESSFUL (total time: 2 minutes 51 seconds)

Repare que ele desconectou duas vezes e conectou uma só. Parece que nossa instancia não esta sendo criada cada vez que uso o comando BD.getInstance().close().

O que faço agora?

Atenciosamente,
Ronaldo

Então você está chamando o close() em mais de um lugar.
Chame o close() somente onde você faz o System.exit(0).

Staroski, o arquivo não pode ser fechado apenas quando ocorre System.exit(0), pelo menos no meu ponto de vista. Se você discorda pode mandar mensagem.

A saída do sistema System.exit(0) só acontece no programa de menu principal, mas o banco de dados é fechado em toda saída de programa. Então (acho que resolvi esta questão) cada vez que chamo o método close() declaro instance = null e da próxima vez que tentar entrar no cadastro ele cria uma nova conexão. Pronto.

Se tiver ideia melhor pode falar. Eu não sei se isto está certo mas agora não tem mais problema de fechar o arquivo mais vezes que abre e o sistema voltou a funcionar (não 100 por cento, mas melhorzinho).

Veja como ficou o close() da classe DB, eu acrescentei instance = null.

public void close() {
    try {
        connection.close();
        instance = null;
        System.out.println("Desconectou...");
    } catch(Throwable t) {
        throw new RuntimeException("Erro ao fechar BD", t);
    }
}

Não entendi, pra você sair de um programa, você tem que fazer System.exit.

Em vez de abrir um JFrame para cada programa, o livro que estava estudando cria programas extends JPanel. Deve ter apenas um ou dois JFrame e vários JPanel. Na verdade acho que só uma tela é JFrame e o resto é JPanel.
Só uso System.exit (0) quando vou fechar tudo e voltar para o Windows, no caso para o Apache NetBeans.
Não fui eu que optei por essa estratégia foi um livro didático. Mas se você tem uma sugestão que considera mais profissional, por favor, me ensine. Diga como você abre várias telas e faz um programa mais profissional.
Atenciosamente,
Ronaldo

Exatamente e é nesse momento que você deveria chamar o close() do seu BD, pelo que entendi agora, acho que você está chamando o close() ao sair de cada tela.

Antes você havia dito que chamava o close() a cada “saída de programa” e saída de programa é quando faz System.exit(0).

Em aplicações desktop eu sempre tenho uma classe que estende JFrame, essa classe será responsável por apresentar as telas do sistema e cada classe de tela eu costumo estender JPanel.

1 curtida

Entendi, Staroski. É exatamente isto que estou fazendo. Criar um JFrame e usar vários JPanel. Porém, eu não concordo que o arquivo deva ficar direto aberto. Assim quando eu troco de tela, voltando para o menu principal, eu fecho a conexão. Daí quando eu entro em outra classe se for necessário (como sempre é) eu abro uma nova conexão. Ou seja o banco de dados não vai ficar direto aberto, fica menos tempo aberto.

A grande questão é se meu procedimento pode ser considerado como correto, adequado ou eu posso estar sacrificando o equipamento com essas aberturas e fechamentos. Na verdade não sei se um programador profissional deixa direto o arquivo aberto. Tinha achado que não e aí o que você acha?

Atenciosamente,
Ronaldo

Também gostaria de saber a opinião do Staroski.

Porque, como eu disse, do que entendi das minhas pesquisas, o jeito que vc está fazendo não é o correto.

O correto seria abrir e fechar a cada operação e, para minimizar o consumo de recursos, usaria um pool de conexões.

Veja só, wldomiciano, em mensagem anterior eu expliquei a forma como estou fazendo: cada vez que vou fazer uso do banco de dados crio uma conexão, cada vez que termino os trabalhos com um cadastro fecho a conexão.

A questão de usar um pool de conexões não faço idéia do que seja ou quais comandos utilizar (como implementar). E assim vou caminhando lentamente…

Atenciosamente,
Ronaldo

Em aplicações standalone é perfeitamente normal ter apenas uma conexão sempre aberta com o servidor. Conecta ao abrir a aplicação e desconecta ao fechar. Estar sempre a conectar/desconectar é muito pesado.

Assumindo que não haverão threads de processamento paralelo com acesso a BD, a pool de conexões não seria necessária para nada já que o utilizador estará fazendo uma operação de cada vez. Mesmo que isso acontecesse, então neste caso poderia abrir uma segunda conexão para a thread e fechar no final do processamento.

Pools de conexões são usadas em servidores aplicacionais onde, com poucas conexões, consegues que muitos utilizadores utilizem o sistema simultaneamente.

2 curtidas

@pmlm é mesmo, não tinha pensado que o pool seria desnecessário quando não há multiplas thread operando nele.

Mesmo assim ainda tem uma coisa a se considerar: E se a conexão cai entre uma operação e outra?

Neste caso, mesmo com apenas uma thread acessando o banco por vez, o pool não faria sentido? Porque vc pode configurá-lo para sempre manter um certo número de conexões abertas e se uma cair, ele cria uma nova, se nenhuma cair ele só a reaproveita. E eu pensei que mesmo se uma pool de apenas uma conexão, ainda assim seria útil, por causa desta questão da conexão poder cair no meio do caminho.

O que vc acha?


@anyblueangel3 Me desculpe por te fazer repetir esta informação. Acho que agora sim eu entendi o que vc disse.

Seria assim:

Quando o usuário entra na tela de cadastro, vc já cria uma conexão. Quando o usuário clica no botão de salvar ou de fechar, vc quer fechar a conexão. Correto?

Se for isso mesmo, eu pensei numa coisa: E se vc não abrir a conexão quando a tela abre? Vc poderia abrir a conexão apenas quando o usuário clica no botão de salvar, assim vc não precisaria se preocupar caso o usuário entre na tela de cadastro e feche a tela sem cadastrar nada.

Para uma aplicação desktop standalone, não vejo problema nenhum em abrir a conexão ao logar no sistema e só fechar ao sair dele.

Se fosse uma aplicação com um banco de dados sendo acessado por diferentes clientes, como por exemplo uma aplicação web, aí eu abriria a conexão quando necessário e preferiria utilizar pool de conexões.

Mas pra uma aplicação desktop standalone, que só roda localmente, não vejo problema nenhum.

1 curtida