Você gostaria de escrever menos
código nas suas aplicações java que lidam com chamadas sql a um banco de dados?
você gostaria que suas declarações sql fossem verificadas durante a compilação
e não em tempo de execução? então o sqlj pode ser o que você precisa! o sqlj
possibilita o desenvolvimento rápido, com menos código, facilidade de depuração
e otimização automática de desempenho.
este artigo assume que você possui
conhecimentos básicos de jdbc e de seus métodos, assim como algum conhecimento
de sql.
o
que é sqlj?
O sqlj é essencialmente sql embutido,
inserido em aplicações java. o sqlj foi desenvolvido para facilitar o
desenvolvimento de projetos orientados a banco de dados, reduzindo
significativamente o tempo de desenvolvimento/depuração.
problemas de codificação podem
decorrer de erros de sintaxe e de outras questões semânticas que podem não
estar corretas, ou simplesmente podem decorrer de nomes de coluna errados,
causando a repetição do ciclo teste/depuração/codificação. a depuração é
particularmente fácil com o sqlj porque você vê o fonte gerado e pode localizar
depressa qualquer erro.
usando o sqlj, seu código fica mais
manutenível e flexível. às vezes, as especificações da sua aplicação podem
mudar e isto não nos deveria surpreender. você cria freqüentemente declarações
sql complexas que combinam unions, joins, e múltiplas cláusulas com valores
dinâmicos. porém, se você usar o sqlj, você verá que seu código permanecerá
legível mesmo se contiver código sql extenso. por exemplo, com o sqlj você não
precisa concatenar suas declarações sql; você pode escrever quantas declarações
sql você quiser, contanto que sejam corretamente definidas. se você usar
oracle, você pode usar qualquer package dbms, procedures, custom packages e todas
as funções embutidas existentes na sua aplicação java. se você for um
desenvolvedor pl/sql, você achará o sqlj muito útil para o desenvolvimento de
software avançado com reutilização do seu estilo e do código pl/sql.
tradutor
sqlj
A arquitetura do
sqlj é composta por um conjunto de funcionalidades que atuando em conjunto
permitem a tradução de comandos inseridos no sqlj para um determinado sql.
neste contexto, o tradutor desempenha algumas funcionalidades principais:
·
verificação
sintática dos construtores sql embutidos;
·
verificação
de data type do java e sql;
·
verificação
do schema.
Começando
a trabalhar com o sqlj
1-
Java
SDK instalado
2-
Oracle
instalado
3-
Verificar
se JAVA_HOME e ORACLE_HOME estão corretos.
4-
Jogar
no path o arquivos SQLJ.exe
5-
Jogar
no classpath as bibliotecas:
D:\oracle\ora81\sqlj\lib\translator.zip;
D:\oracle\ora81\sqlj\lib\runtime12ee.zip
D:\oracle\ora81\sqlj\lib\translator.zip;
D:\oracle\ora81\sqlj\lib\runtime12ee.zip
Obs. Runtime.zip para
JDK 1.1, runtime12.zip para JAVA2 e runtime12ee.zip para JAVA2EE. (estas
bibliotecas se localizam no diretório [oracle]\sqlj\lib)
Obs2. Não existe pluggin
para Eclipse ou Netbeans desenvolvimento com sqlj, no momento da geração do
código Java e do class devera ser feita em linha de comando, daí sim compila-se
o código Java na IDE.
Na listagem 1 temos uma
sequence e uma tabela que serão como exemplo.
create
sequence customer_seq minvalue 1 maxvalue 999999999999999
start with 1 increment by 1 cache 20;
create
table customer (id number(12) primary key , fullname varchar2(100) null,
street varchar2(100) null, city varchar2(100) null, province varchar2(100)
null,
country varchar2(100) null );
commit;
listagem 1. sequence e tabela.
Escrevendo
uma aplicação sqlj
Agora
vamos ver um exemplo simples que utiliza o sqlj para recuperar dados das
colunas fullname e street name (ver código da listagem 2).
import java.sql.*; // este import é necessário para o
sqlexception e outras classes jdbc
import oracle.sqlj.RUNTIME.oracle;
public
class singlerowquery extends base {
public
static void main(string[] args) {
try
{
connect();
singlerowquery(1);
}
catch (sqlexception e) {
e.printstacktrace();
}
}
public static void singlerowquery(int id) throws SQLException{
string fullname = null;
string street = null;
#sql { select fullname, street into :
out fullname,
: out street from customer where id = :id};
system.out.println("customer with id = " + id);
system.out.println();
system.out.println(fullname + " " + street);
}
}
listagem 2. aplicação
utilizando o sqlj.
Agora vamos analisar
os trechos importantes da listagem 2.
Inicialmente temos o import oracle.sqlj.RUNTIME.oracle. este é parte do translator.jar e permite o uso de suas
funcionalidades, a classe base lida com a questão da conexão.
vale
ressaltar aqui que qualquer método que possua uma declaração sqlj sempre terá
que possuir throws sqlexception. caso contrário, o tradutor não funcionará.
Agora, passemos para a parte de
manipulação de dados. você talvez esteja um pouco confuso caso conheça o
pl/sql: porque "into" está sendo usado neste contexto?
Neste exemplo, você está usando uma
declaração select para salvar os valores em duas host variables especificando
into : out.
·
:
out denota os valores que são armazenados
em variáveis do host;
·
:
in denota as variáveis lidas. se
você estiver usando um método para obter o valor, você tem que incluí-lo entre
parênteses.
Variáveis Host
Variáveis
host permitem que programas sqlj troquem informações entre o sql embutido e o
restante da aplicação java. apesar deste nome diferenciado, é uma variável
qualquer criada em seu programa java.
para
exemplificar o uso dessas variáveis, vamos analisar o comando select da
listagem 3. nele é ilustrado o uso da cláusula select into para recuperar as
colunas first_name, last_name, dob e phone da tabela customers onde a coluna id
seja igual a 2. os valores retornados são armazenados nas variáveis host. neste
caso, as variáveis host declaradas na aplicação java foram id, first_name, last_name,
dob e phone.
// declarando variáveis
host
int id = 2;
string
first_name = null;
string
last_name = null;
java.sql.date
dob = null;
string
phone = null;
//
executa select
#sql
{
select
first_name, last_name, dob, phone
into
:first_name, :last_name, :dob, :phone
from
customers
where
id = :id
};
listagem 3. entendendo
variáveis host.
Agora que você finalizou o código,
você pode aprofundar-se mais nas particularidades do sqlj. como você pode ver,
a execução da declaração sqlj não é uma string regular e seu arquivo deve ter a
extensão .sqlj. além disto, esta declaração tem a seguinte sintaxe:
#sql
{sql statement};
As características
suportadas pelo sqlj são:
·
sql
dml (data modification language): declarações como select, update, delete e
insert;
·
declarações
de controle de transações sql como commit e rollback;
·
sql ddl (data
definition language) como
create table e drop table;
·
chamadas
a stored procedures, funções e pacotes oracle pl/sql;
·
diretivas
de sessão (session directives).
Eis aqui um exemplo do procedimento
de chamada ao pl/sql:
#sql {
// chamada à
procedure
call
insertcustomerorder(1234,44);
};
e outro exemplo de bloco executável
que designa um valor pl/sql a uma variável host:
#sql {
declare
loc_myid number := 1234;
begin
set :(:my_hostvariable) := loc_myid;
end;
};
código
gerado pelo tradutor
Passemos do código escrito pelo
desenvolvedor para o código gerado pelo tradutor. como você pode ver na listagem
4, o código gerado contém imports fundamentais para chamadas ao jdbc,
conferência de resultados, execução nativa de uma consulta oracle e também gera
todo o tratamento de exceções e algumas outras verificações. o código gerado
também é otimizado quando o compilamos para bytecode através do javac.
// o código reflete o comando sql definido
...
//
************************************************************
//
#sql { select fullname, street
//
from customer
//
where id = :id };
//
************************************************************
{
oracle.jdbc.oraclepreparedstatement __sjt_st = null;
sqlj.RUNTIME.ref.defaultcontext
_sjt_cc
= sqlj.RUNTIME.ref.defaultcontext.getdefaultcontext();
if
(__sjt_cc==null)
sqlj.RUNTIME.error.RUNTIMEreferrors.raise_null_conn_ctx();
sqlj.RUNTIME.executioncontext.oraclecontext
__sjt_ec =
((__sjt_cc.getexecutioncontext()==null) ?
sqlj.RUNTIME.executioncontext.raisenullexecctx()
:
__sjt_cc.getexecutioncontext().getoraclecontext());
oracle.jdbc.oracleresultset
__sjt_rs = null;
try {
__sjt_st =
__sjt_ec.prepareoraclestatement(
__sjt_cc,"0singlerowquery",
"select fullname,ntttt street
from customer where id = :1");
if (__sjt_ec.isnew())
{
__sjt_st.setfetchsize(2);
}
// designar os parâmetros in
__sjt_st.setint(1,id);
// execute query
__sjt_rs = __sjt_ec.oracleexecutequery();
if (__sjt_rs.getmetadata().getcolumncount() != 2)
sqlj.RUNTIME.error.RUNTIMEreferrors.raise_wrong_num_cols(
2,__sjt_rs.getmetadata().getcolumncount());
if (!__sjt_rs.next()) sqlj.RUNTIME.error.RUNTIMEreferrors.
raise_no_row_select_into();
// recuperação dos parâmetros
out
fullname =
__sjt_rs.getstring(1);
street =
__sjt_rs.getstring(2);
if (__sjt_rs.next()) sqlj.RUNTIME.error.RUNTIMEreferrors.
raise_multi_row_select_into();
} finally { if (__sjt_rs!=null) __sjt_rs.close();
__sjt_ec.oracleclose(); }
}
...
// inserir aqui a impressão dos resultados
listagem 4. parte do código
gerado pelo tradutor.
Conecção com Banco de dados
Para
conecção a banco de dados utilizamos o context
, seu formato básico é:
#sql context MyCtx;
E
após isto temos duas opções, criarmos nossa conecção:
String url = "jdbc:vendor:myDB";
String user = "john";
String password = "secret";
MyCtx myCtx = new MyCtx(url, user, password, false);
Ou
trabalharmos com uma conecção JDBC pré-existente:
MyCtx myCtx =
new MyCtx(Connection conn);
Recuperação
de linhas múltiplas
Em qualquer aplicação você pode
precisar recuperar linhas múltiplas do banco de dados ou de algum outro
datasource. se você usar a tecnologia sqlj,
esta será uma tarefa fácil.
Em jdbc, você usaria um resultset para manipular um conjunto de
registros. usando o sqlj, você usaria o que é chamado de iterator para atingir um resultado semelhante (se você conhece o
pl/sql, você pode considerar o iterator como um cursor ref). os seguintes
passos resumem as etapas que devem ser seguidas para se trabalhar com iterator:
·
use
a declaração sqlj para definir a classe iterator;
·
declare
uma instância do iterator;
·
povoe
a instância do iterator com select;
·
use
o método next() da classe iterator para recuperar a próxima linha;
·
extraia
os valores de coluna do iterator atual usando os métodos da classe iterator;
·
desative
ou dispense a instância do iterator invocando o método end().
Criação de um iterator em sqlj:
#sql
iterator << iterator name >>
(<< list of attributes declarations) };
Instanciamento de um iterator:
iterator_class_name
instance_name;
//
populando
#sql
instance_name = { select_statement };
na listagem 5 apresentamos um
exemplo completo para recuperar uma lista de clientes.
//
importações necessárias
#sql
iterator customeritr implements scrollable
( int id, string fullname, string street);
#sql
context Ctx;
// esta é a linha que será traduzida para a
classe java chamada customeritr
// com os métodos id(), fullname(), street() alguns
métodos principais, manipulador de conexão
public
static void printcustomers(Connection conn) throws sqlexception {
//declarando o objeto iterator
que armazenará o resultado
customeritr
itr; //
instanciando o iterator
//populando o iterator utilizando uma
declaração select
Ctx contx= new Ctx(conn);
String nomecompleto= “manoel de sousa”;
// :<variavel> insere variável Java
no SQLJ
#sql [contx]
itr = { select id, fullname,street from
customer where fullname = :nomecompleto};
system.out.println("idtnametstreettn");
itr.afterlast();
//lendo valores das colunas via
iterator
while(itr.previous())
{
system.out.print(itr.id());
system.out.print("t");
system.out.print(itr.fullname());
system.out.print("t");
system.out.print(itr.street());
system.out.println();
}
itr.close(); //fechando o iterator
}
listagem 5. utilizando
iterator.
perceba que os parâmetros do iterator
devem ser iguais aos nomes das colunas referenciadas no banco de dados.
execução e compilação do sqlj
uma vez criado o arquivo sqlj, você
vai querer compilá-lo e executá-lo. a sintaxe abaixo mostra como fazer isto:
> sqlj <<
filename.sqlj>>
compilar o arquivo *.sqlj com as
bibliotecas correspondentes do classpath resulta na geração dos arquivos *.
java e *.class.
Acessando banco de dados sem CONTEXT
package br.com.abril.cev.integration.sqlj;
import java.sql.Connection;
import java.sql.SQLException;
import sqlj.runtime.ref.*;
import br.com.abril.cev.util.Converter;
import sqlj.runtime.ConnectionContext;
public class consultaPreCancelamento {
private
VarejoCtx vCtx;
private
Connection conn;
private
String qtde;
public consultaPreCancelamento(Connection conn,
String nf, String cota) throws SQLException
{
this.conn = conn;
vCtx = new VarejoCtx(conn);
try{
#sql [vCtx] {
select
count(*) valor
into :qtde
from
varejo.item_extrato_devolucao ied,varejo.extrato_devolucao ed
where
ied.num_extrato_devolucao_ited
= ed.num_extrato_devolucao_exdv and
ied.num_nota_fiscal_ftf_ited = :nf
and ed.cod_cota = :cota
};
}
finally{
if(vCtx!=null)
vCtx.close(false);
}
}
public
String registros(){
return this.qtde;
}
}
Obs: Joga-se o valor de INTO diretamente para variáveis
private, o método registros nos fornece o valor armazenado posteriormente.
conclusão
Escrever código enxuto e claro usando
um back-end de banco de dados é parte
essencial do desenvolvimento de software. qualquer tipo de arquitetura de
software estará bastante amarrada a dados, tanto em aplicações web quanto em
aplicações baseadas em formulários. se você está escrevendo um projeto pequeno
e não tem um design de aplicação de três camadas, o sqlj será perfeito para
você. ele lhe permite o desenvolvimento rápido de aplicações e também economiza
tempo com correção de erros simples.

Nenhum comentário:
Postar um comentário