Quem mantem códigos JDBC puro?

25 respostas
java
K

Tenho curiosidade de saber se ainda existem muitos códigos JDBC puro.

Digo isso, pois mantenho um software JDBC e já cogitei convertê-lo para JPA, mas o trabalho seria enorme.
Principalmente pelo fato das chaves serem compostas.

Então desenvolvi um projeto simples pra auxiliar projetos JDBC e gostaria de saber se ainda existe público pra ele.

25 Respostas

E

Cara, dá uma olhada nesse projeto: http://www.mybatis.org/mybatis-3/

K

Olha ai o que eu fiz. É bem simples mesmo

E

Olha, como exercício eu achei bem legal. Mas, como biblioteca para reuso, ainda teria que desenvolver muita coisa e melhorar outras. Acho, nesse caso, que o esforço não valeria a pena.

K

Desenvolvi baseado na necessidade do projeto. É bem simples. To lendo aqui sobre o MyBatis e é muita coisa.

Vou mostrar aqui como esse meu projeto ajudou no meu sistema:

Classe Original
/**
*
* @author krismorte
*/
public class AutorizaHoraExtraDao {

public boolean insert(AutorizaHoraExtra model) {
        try {
            Connection con = ConnectionFactory.connectBase();
            String insert = "insert into hep_autoriza_hora_extra values(?,?,?,?,?)";
            PreparedStatement cmd = con.prepareStatement(insert);
            cmd.setString(1, model.getHoraExtra().getUsuario().getMatricula());
            cmd.setDate(2, new Date(model.getHoraExtra().getData().getMillis()));
            cmd.setDate(3, new Date(model.getDataAprovacao().getMillis()));
            cmd.setString(4, model.getJustificativa());
            cmd.setString(5, model.getAprovador().getMatricula());
            cmd.executeUpdate();
            cmd.close();
            con.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            Main.addMsgLog(AutorizaHoraExtraDao.class.getName(), e.getMessage());
            return false;
        }
    }

    public boolean delete(String usuario, Date data) {
        try {
            Connection con = ConnectionFactory.connectBase();
            String insert = "delete from hep_autoriza_hora_extra where usuario=? and data=?";
            PreparedStatement cmd = con.prepareStatement(insert);
            cmd.setString(1, usuario);
            cmd.setDate(2, data);
            cmd.executeUpdate();
            cmd.close();
            con.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            Main.addMsgLog(AutorizaHoraExtraDao.class.getName(), e.getMessage());
            return false;
        }
    }

    public AutorizaHoraExtra select(String usuarioMatricula, Date data) {
        try {
            Connection con = ConnectionFactory.connectBase();
            AutorizaHoraExtra lst = null;
            String select = "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                    + " hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                    + " from hep_autoriza_hora_extra hah(nolock)"
                    + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                    + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                    + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                    + " where hah.usuario=? and hah.data=?";
            PreparedStatement cmd = con.prepareStatement(select);
            cmd.setString(1, usuarioMatricula);
            cmd.setDate(2, data);
            ResultSet set = cmd.executeQuery();
            if (set.next()) {
                Date d = set.getDate(2);
                Date d2 = set.getDate(3);
                UsuarioInterno usuario = new UsuarioInterno();
                usuario.setMatricula(set.getString(6));
                usuario.setNome(set.getString(7));
                usuario.setEmail(set.getString(8));
                UsuarioInterno aprovador = new UsuarioInterno();
                aprovador.setMatricula(set.getString(9));
                aprovador.setNome(set.getString(10));
                aprovador.setEmail(set.getString(11));
                lst = new AutorizaHoraExtra(usuario, new DateTime(d.getTime()), set.getString(12), set.getString(13), set.getString(14), set.getString(15), new DateTime(d2.getTime()), set.getString(4), aprovador, set.getString(16));
            }
            con.close();
            cmd.close();
            return lst;
        } catch (Exception e) {
            Main.addMsgLog(AutorizaHoraExtraDao.class.getName(), e.getMessage());
            return null;
        }
    }

    
    
     public List<AutorizaHoraExtra> list(int ano,int mes) {
        try {
            Connection con = ConnectionFactory.connectBase();
            List<AutorizaHoraExtra> lst = new ArrayList<AutorizaHoraExtra>();
            String select = "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                    + "hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                    + " from hep_autoriza_hora_extra hah(nolock)"
                    + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                    + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                    + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                    + " where DATEPART(YEAR,hah.data)=? and DATEPART(MONTH,hah.data)=?";
            PreparedStatement cmd = con.prepareStatement(select);
            cmd.setInt(1, ano);
            cmd.setInt(2, mes);
            ResultSet set = cmd.executeQuery();
            while (set.next()) {
                Date d = set.getDate(2);
                Date d2 = set.getDate(3);
                UsuarioInterno usuario = new UsuarioInterno();
                usuario.setMatricula(set.getString(6));
                usuario.setNome(set.getString(7));
                usuario.setEmail(set.getString(8));
                UsuarioInterno aprovador = new UsuarioInterno();
                aprovador.setMatricula(set.getString(9));
                aprovador.setNome(set.getString(10));
                aprovador.setEmail(set.getString(11));
                lst.add(new AutorizaHoraExtra(usuario, new DateTime(d.getTime()), set.getString(12), set.getString(13), set.getString(14), set.getString(15), new DateTime(d2.getTime()), set.getString(4), aprovador, set.getString(16)));
            }
            con.close();
            cmd.close();
            return lst;
        } catch (Exception e) {
            e.printStackTrace();
            Main.addMsgLog(AutorizaHoraExtraDao.class.getName(), e.getMessage());
            return null;
        }
    }


    
    public List<AutorizaHoraExtra> list(Date ini, Date fim) {
        try {
            Connection con = ConnectionFactory.connectBase();
            List<AutorizaHoraExtra> lst = new ArrayList<AutorizaHoraExtra>();
            String select = "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                    + "hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                    + " from hep_autoriza_hora_extra hah(nolock)"
                    + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                    + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                    + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                    + " where hah.data between ? and ?";
            PreparedStatement cmd = con.prepareStatement(select);
            cmd.setDate(1, ini);
            cmd.setDate(2, fim);
            ResultSet set = cmd.executeQuery();
            while (set.next()) {
                Date d = set.getDate(2);
                Date d2 = set.getDate(3);
                UsuarioInterno usuario = new UsuarioInterno();
                usuario.setMatricula(set.getString(6));
                usuario.setNome(set.getString(7));
                usuario.setEmail(set.getString(8));
                UsuarioInterno aprovador = new UsuarioInterno();
                aprovador.setMatricula(set.getString(9));
                aprovador.setNome(set.getString(10));
                aprovador.setEmail(set.getString(11));
                lst.add(new AutorizaHoraExtra(usuario, new DateTime(d.getTime()), set.getString(12), set.getString(13), set.getString(14), set.getString(15), new DateTime(d2.getTime()), set.getString(4), aprovador, set.getString(16)));
            }
            con.close();
            cmd.close();
            return lst;
        } catch (Exception e) {
            Main.addMsgLog(AutorizaHoraExtraDao.class.getName(), e.getMessage());
            return null;
        }
    }
}

Classe alterada

/**
 *
 * @author krismorte
 */
public class AutorizaHoraExtraDao extends EntidadeJDBC<AutorizaHoraExtra> {

    public static final Integer CONSULTA_POR_MES = 0;
    public static final Integer CONSULTA_POR_PERIODO = 1;
    public static final Integer INCLUIR_REGISTRO = 2;
    public static final Integer REMOVER_REGISTRO = 3;
    public static final Integer CONSULTA_POR_USUARIO_DATA = 4;

    private Connection conexao;

    public AutorizaHoraExtraDao() throws ExcecaoDao {
        super();
        adicionaComandoSQL(CONSULTA_POR_MES, "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                + "hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                + " from hep_autoriza_hora_extra hah(nolock)"
                + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                + " where DATEPART(YEAR,hah.data)=? and DATEPART(MONTH,hah.data)=?");
        adicionaComandoSQL(CONSULTA_POR_PERIODO, "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                + "hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                + " from hep_autoriza_hora_extra hah(nolock)"
                + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                + " where hah.data between ? and ?");
        adicionaComandoSQL(INCLUIR_REGISTRO, "insert into hep_autoriza_hora_extra values(?,?,?,?,?)");
        adicionaComandoSQL(REMOVER_REGISTRO, "delete from hep_autoriza_hora_extra where usuario=? and data=?");
        adicionaComandoSQL(CONSULTA_POR_USUARIO_DATA, "select hah.*,hu.matricula,hu.nome,hu.email,ha.matricula,ha.nome,ha.email,hhe.motivo,hhe.hora_entrada,"
                + " hhe.hora_saida,hhe.hora_total , case when hhe.motivo is null then 'NÃO LANÇADA' else 'LANÇADA' end"
                + " from hep_autoriza_hora_extra hah(nolock)"
                + " left join hep_hora_extra hhe on hah.usuario=hhe.usuario and hah.data=hhe.data"
                + " inner join hep_usuario hu on hah.usuario=hu.matricula"
                + " inner join hep_usuario ha on hah.aprovador=ha.matricula"
                + " where hah.usuario=? and hah.data=?");
        setExcecao(new ExceptionDao(AutorizaHoraExtraDao.class.getName()));
    }

@Override
    public Connection getConexao() {
        return ConnectionFactory.connectBase();
    }
  
    @Override
    public AutorizaHoraExtra consultar() throws ExcecaoDao {
        try {
            conexao = getConexao();
            AutorizaHoraExtra lst = null;

            ResultSet set = executaConsulta();
            if (set.next()) {
                Date d = set.getDate(2);
                Date d2 = set.getDate(3);
                UsuarioInterno usuario = new UsuarioInterno();
                usuario.setMatricula(set.getString(6));
                usuario.setNome(set.getString(7));
                usuario.setEmail(set.getString(8));
                UsuarioInterno aprovador = new UsuarioInterno();
                aprovador.setMatricula(set.getString(9));
                aprovador.setNome(set.getString(10));
                aprovador.setEmail(set.getString(11));
                lst = new AutorizaHoraExtra(usuario, new DateTime(d.getTime()), set.getString(12), set.getString(13), set.getString(14), set.getString(15), new DateTime(d2.getTime()), set.getString(4), aprovador, set.getString(16));
            }
            return lst;
        } catch (Exception e) {
            getExcecao().lancaExcecao(e);
            return null;
        } finally {
            finalizaConexaoComSeguranca(conexao);
        }
    }

    @Override
    public List listar() throws ExcecaoDao {
        try {
            List<AutorizaHoraExtra> lst = new ArrayList();
            conexao = getConexao();
            ResultSet set = executaConsulta();
            while (set.next()) {
                Date d = set.getDate(2);
                Date d2 = set.getDate(3);
                UsuarioInterno usuario = new UsuarioInterno();
                usuario.setMatricula(set.getString(6));
                usuario.setNome(set.getString(7));
                usuario.setEmail(set.getString(8));
                UsuarioInterno aprovador = new UsuarioInterno();
                aprovador.setMatricula(set.getString(9));
                aprovador.setNome(set.getString(10));
                aprovador.setEmail(set.getString(11));
                lst.add(new AutorizaHoraExtra(usuario, new DateTime(d.getTime()), set.getString(12), set.getString(13), set.getString(14), set.getString(15), new DateTime(d2.getTime()), set.getString(4), aprovador, set.getString(16)));
            }
            return lst;
        } catch (Exception e) {
            getExcecao().lancaExcecao(e);
            return null;
        } finally {
            finalizaConexaoComSeguranca(conexao);
        }
    }
}

Exemplo de Chamada

public boolean add() throws ExcecaoDao {
        EntidadeJDBC dao = new AutorizaHoraExtraDao();
        dao.escolherComandoSQL(AutorizaHoraExtraDao.INCLUIR_REGISTRO);
        dao.adicionaCampos(getHoraExtra().getUsuario().getMatricula(), new Date(getHoraExtra().getData().getMillis()),
                new Date(getDataAprovacao().getMillis()), getJustificativa(), getAprovador().getMatricula());
        dao.incluir();
        return true;
    }
K

Você teria sugestões de melhoria?

D

Eu vou mais longe, porque excluir do seu desenvolvimento JDBC, quando o mesmo é utilizado pelos ORM?

Claro, trabalhar com ORM é um ótima solução para não escrever muito código, padrão, etc, mas, nunca podemos esquecer que o JDBC é a base de tudo.

Então, não acho errado ter JDBC e também não acho errado usar ORM, tudo tem seus pros e contras e no mundo de desenvolvimento os dois podem trabalhar juntos.

Sempre digo isso, e se você tiver que dar manutenção em software legado com JDBC, não é melhor então saber do que excluir! é um ponto de vista.

A

SIm, existem milhares de projetos espalhados por ai que ainda são em JDBC puro, normalmente projetos de 7 anos ou mais, estes são um pesadelos para os desenvolvedores, já passei por isso

P

Pelo que percebi, sua classe alterada acabou ficando com mais linhas de código do que usando JDBC puro. Além de que agora eu tenho que aprender a usar seu framework, enquanto qualquer programador ja sabe mexer com JDBC.

Em que exatamente seu framework auxilia?

P

ORM é ótimo se você tem um modelo de objetos simples pra ser mapeado em tabelas. Qualquer coisa mais complicada você vai ter que lutar com o framework.

K

A classe alterada ficou com mais linhas? Na verdade os métodos incluir/remover/atualizar foram removidos pois herdados e já estão implementados.

A minha ideia é diminuir as classes DAO e fazer reuso do que é comum. O que mais difere nas classes DAO são as consultas, pois os objetos devem ser montados. Já nos métodos incluir/remover/atualizar a preocupação é em montar o comando.

P

Tem razão, mas ainda é muito código pra algo que deveria ser trivial, como armazenar/recuperar informação do banco.
E toda essa concatenação de strings? Jesus.

P

Por que você esta dando a opção do desenvolvedor da aplicação apenas escolher a SQL? Por que ele não pode criar o SQL que ele quiser baseado nos requisitos da aplicação que ele esta desenvolvendo?

K

O @esmiralha me sugeriu o MyBites. É realmente bem mais completo e com isso pede bem mais configuração e todos os comandos SQL ficam em um arquivo XML. Eu meio que criei um meio termo entre o JDBC puro e algo mais organizado.

Utilizei a herança pra deixar alguns métodos comuns já implementados e exijo a implementação da conexão e dos métodos de consulta. Fica claro no exemplo que pus aqui que é necessário “registrar” todos os comandos que podem ser executados. Fica a cargo do que eu fiz montar os comandos e fechar as conexões.

Como eu disse criei isso baseado em um sistema que tenho onde seria muito mais trabalhoso convertê-lo totalmente para JPA.

Minha questão aqui é saber se ainda há muita gente na mesma situação que a minha (manter código antigo em JPA) e se o que eu fiz é interessante se pode melhorar e como. Enfim.

Estou aberto a sugestões :smiley:

K

Se eu entendi bem você tá sugerindo que eu criasse toda a instrução SQL?

Nesse caso eu acho que seria um tanto mais trabalhoso e fugiria ao que imaginei, já que teria que mapear Objetos - > Tabela e Atributos - > Campos

Ou isso é fácil de fazer e eu não sei?

P

Entendo. O problema é que na medida que o projeto cresce, você continua tendo que criar DAOs, e repetindo muito código dentro dos DAOs. Ou seja, isso não escala pra projetos complexos.
E para projetos simples eu imagino que as pessoas preferem usar uma ferramenta ORM.

A

O que você criou é o que geralmente é chamado de Query Helper. Nao chega a ser um ORM completo (como JPA), mas facilita lidar com JDBC diretamente.

Tem muita coisa pronta que já faz isso: o MyBatis já citado, JDBI, Spring Data JDBC extensions, jooq, entre outros.

Apesar de ser legal criar esse tipo de projeto, geralmente é mais fácil usar alguma coisa pronta e madura para resolver seu problema, por vários motivos:

  • Vários problemas que você nem encontrou ainda já foram solucionados
  • É muito mais fácil para seus colegas procurarem no google como fazer alguma coisa, do que terem que ler seu código
  • Geralmente possuem testes automatizados que previnem bugs a cada mudança.
  • Você tem mais tempo pra focar no negócio, resolver os problemas realmente importantes.
P

Pra mim a vantagem de usar JDBC puro é justamente ter o controle total da queries, mas pra isso elas devem ficar o mais próximo das regras de negócio, portanto colocar em arquivos XML como o Mybatis, ou ocultas dentro de um DAO com o nome de CONSULTA_POR_MES não faz sentido.

J

Trabalho enorme e o sistema vai ficar mais pesado.

K

Em que sentido você diz que o sistema ficaria mais pesado.

P

Não sei mas se você tem objetos grandes pra montar e usa ORM, não vai ter que rodar N queries separadas, ao invés de 1 query complicada que retorna tudo?

Se as queries rodam no banco, provavelmente em outra máquina, é uma viagem ao banco pra cada query. Isso pode afetar a performance da sua aplicação.

J

Sua aplicação já começa levantando um pesado objeto “SessionFactory” que fica a vida toda na memória de cada aplicação que use Hibernate na empresa. A cada requisição entra em cena o cache do hibernate consumindo mais memória, que apesar de poder ser desligado, maioria usa pra aproveitar os recursos da ferramenta, como por exemplo o perigoso lazy loading. Fazer querys complexas e performáticas na linguagem de objeto do Hibernate é muito mais complicado do que diretamente em SQL nativo. Pra evitar o problema de N querys vai ter que ser expert no confuso Criteria ou HQL. Como fuga dentro do próprio Hibernate acaba sendo melhor mapear SQL nativo, que fica mais prático e natural da fonte de dados relacional, é o que faço quando trabalho com sistema mantido em Hibernate. Hibernate costuma ser mais útil em sistemas que realmente precisam ser multi banco, onde justifica mais o gasto de seus recursos.

P

Cache do hibernate é inútil se os dados são atualizados com freqüência.

J

Problema é que muitos usam session com cache só pra poder usar o lazy loading, que é um perigo pra performance, gerando N querys. Desperdício de recurso.

P

Esse é o problema dos banco de dados “atualizáveis”. Não dá pra fazer uso de cache nas aplicações, por isso N queries é considerado um problema.

P

Pra todo programador que acaba tendo que lidar com otimização de query em vez de ux, e em especial para o cliente que está pagando para alguém que deveria estar agregando valor, lamento pelo desperdício de vocês.

Criado 30 de agosto de 2016
Ultima resposta 1 de set. de 2016
Respostas 25
Participantes 7