Systêxtil Connection (AppConnection)

Biblioteca para fazer acesso à base de dados do Systêxtil ERP.

A classe principal é AppConnection. Por ela são feitas todas as operações envolvendo Connection, Statement, ResultSet etc.

A maior parte das operações requer que o objeto seja fechado ao fim, para liberar Statements e ResulSets (cursores). Por isso, ele implementa AutoCloseable, e é importante usá-lo dentro de um bloco try-with-resources - especialmente se com ele forem executadas operações que podem fazer retornos prematuros, como return, throw, break.

Se ocorrer erro de execução de SQL dentro do objeto AppConnection, esse objeto é fechado automaticamente, e é lançada uma DebugException contendo os detalhes do erro.

Existem métodos que estão documentados como não requerendo fechamento do objeto (não precisam estar num bloco try-with-resources). São métodos que fazem uma operação atômica em um comando SQL (só retornam após terem processado o comando até o fim e fecham o objeto). São principalmente métodos que retornam o resultado de um único registro, ou o método que insere um único registro sem se importar com violação de chave única. Recomenda-se dar preferência a esses métodos quando possível.

Histórico

Esta biblioteca foi criada há muito tempo atrás para facilitar a execução de comandos SQL usando JDBC. Por isso, ela torna possível fazer praticamente qualquer coisa com JDBC - mas também requer cuidado para fazer da forma correta e para não esquecer de fechar os cursores.

Com o tempo foram adicionadas melhorias para tornar mais fáceis algumas tarefas muito frequentes.

Agora é possível usar programação funcional (lambdas) para algumas tarefas.

Recursos usando programação funcional (lambdas)

Algumas operações usam lambdas e não requerem que o objeto AppConnection seja fechado explicitamente (isto é garantido internamente). Recomendamos usar essas operações quando possível, especialmente nas tarefas muito frequentes exemplificadas a seguir:

String SQL = "select descricao from depositos where id = ?";
String nome;


// Obter a descrição, ou um texto padrão se não existir:
nome = new AppConnection(conn, SQL, id)
        .map(c -> c.getString(1))
        .orElse("Não encontrado.");


// Obter a descrição, ou lançar uma mensagem se não existir:
nome = new AppConnection(conn, SQL, id)
        .map(c -> c.getString(1))
        .orElseThrow(() -> new Exception("Depósito não encontrado"));


// Obter a descrição e usá-la imediatamente:
new AppConnection(conn, SQL, id)
        .map(c -> c.getString(1))
        .ifPresent(nome -> campo.setDescricao(nome));


// Lançar uma mensagem se encontrar um problema:
new AppConnection(conn, "select problema from problemas")
        .ifPresentThrow(c -> new Exception("Foi encontrado um problema: "+c.getString(1)));


// Ler um objeto a partir de um registro:
Num numero = new AppConnection(conn, "select id, name from numbers where id = ?", id)
        .map(c -> new Num(c.getInt(1), c.getString(2)))
        .orElseThrow(() -> new Exception("Número não existe."));


// Processar vários registros, um a um:
int quantos = new AppConnection(conn, "select * from depositos where situacao <> 0")
        .forEach(c -> {
            int cod = c.getInt("codigo");
            String desc = c.getString("descricao");
            int situacao = c.getInt("situacao");

            // Faça alguma coisa com tudo isso.
        });


// Ler e processar registros usando stream:
// (As possibilidades são infinitas - isto é só um exemplo!)
String maiorQueUm = new AppConnection(conn, "SELECT * FROM NUMBERS")
        .stream(stream -> {
            return stream
                    .filter(cn -> cn.getInt(1) > 1)
                    .map(cn -> cn.getString(2))
                    .collect(Collectors.joining(", "));
        });
assertEquals(maiorQueUm, "TWO, THREE");