SQLJ: uma alternativa de alto nível a JDBC Universidade Federal de Campina Grande Disciplina: Banco de Dados I Professor: Cláudio de Souza Baptista Estagiário: Elvis Rodrigues da Silva http://www.lsi.dsc.ufcg.edu.br/ Roteiro • Introdução • Sintaxe Inicial • Comandos avançados • Requisitos • Referências Introdução (1 de 5) • SQLJ é uma tecnologia que permite a um programa Java acessar um banco de dados utilizando statements SQL embutidos • Arquivo fonte termina com “.sqlj” • Manipulações SQLJ – Meta informações: Create, Alter, Drop – Dados: Select, Insert, Update, Open, Fetch – Controle de Transações: Commit, Rollback Introdução (2 de 5) • SQLJ não pode ser compilado diretamente pelo compilador Java • Solução: usar um tradutor – SQLJ Translator Introdução (3 de 5) • O tradutor verifica erros de sintaxe e semânticos na instrução SQL em tempo de tradução: – Nomes incorretos – Checagem de tipos – Verifica se o comando SQL está de acordo com o Banco de Dados – Etc. Introdução (4 de 5) • A IDE Oracle JDeveloper reconhece a sintaxe de SQLJ para o banco de dados Oracle, mas é possível utilizar outros compiladores • O IBM Websphere também possui compatibilidade com SQLJ para o banco de dados IBM DB2 Introdução (5 de 5) • Vantagens de SQLJ sobre JDBC (comandos estáticos) – Código-fonte reduzido – Checagem de tipos SQL via conexão – Associação de variáveis em um único comando – Checagem de tipos de parâmetros e retorno antes da execução • Desvantagens – Um passo a mais no processamento: tradução de sqlj para java Sintaxe Inicial: Declarações (1 de 3) • Declarações SQLJ : – #sql{<comando SQL>}; • Regras pra declarações SQLJ SQLJ declaration; // OK (top level scope) class Outer { SQLJ declaration; // OK (class level scope) class Inner { SQLJ declaration; // OK (nested class scope) } void func() { SQLJ declaration; /* OK in JDK 1.2.x; ILLEGAL in JDK 1.1.x (method block)*/ } } • Exemplo: Sintaxe Inicial: Declarações (3 de 3) • Existem 2 tipos de declarações SQLJ: – Iterator – Context • Iterator – Declarações que definem classes iterator – Usado para receber os resultados de consultas • Context – Usado para criar uma conexão ao Banco de Dados Sintaxe Inicial: SQLJ Namespace • Todas as restrições de nome em Java são aplicadas aqui • Evitar usar as palavras reservadas, nome de classes e colunas em iterator: – iterator – context – with Sintaxe Inicial: Iterator (1 de 8) • Declaração: • Modifiers: – publics, static, etc • Existem 2 tipos de iterator: – named iterators – positional iterators Sintaxe Inicial: Iterator (2 de 8) • named iterators • positional iterators Sintaxe Inicial: Iterator (3 de 8) • Exemplo named iterators: #sql iterator MyCheckedIter (String ename, double sal); ... MyCheckedIter iter; #sql iter = { SELECT ename, sal FROM Employee}; while (iter.next()) { System.out.println(iter.ename()); System.out.println(iter.sal()); } Sintaxe Inicial: Iterator (4 de 8) • Obtendo os elementos de um Positional iterators – FETCH INTO seguido por endFetch() – O FETCH INTO chama implicitamente o método next() • Exemplo de “positional iterators” Sintaxe Inicial: Iterator (6 de 8) • Iterator e ResultSet podem existir dentro de outro Iterator em Oracle SQLJ • Exemplos: CREATE TABLE DEPT ( DEPTNO NUMBER(2), DNAME VARCHAR2(14) ); CREATE TABLE EMP ( EMPNO NUMBER(4), ENAME VARCHAR2(10), SAL NUMBER(7,2), DEPTNO NUMBER(2) ); Sintaxe Inicial: Iterator (7 de 8) Sintaxe Inicial: Iterator (8 de 8) • Outro exemplo: • Declaração: • Execução: Sintaxe Inicial: Connection (1 de 7) • Existem várias formas de criar uma conexão com o Banco de Dados: – Criando um contexto Default DefaultContext defctx = new DefaultContext ("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger", false); – Através da declaração SQLJ: Sintaxe Inicial: Connection (2 de 7) • Exemplo: #sql context MyContext; ... MyContext myContext = new MyContext("jdbc:oracle:thin:@localhost:1521:dbhome", “scott", "tiger ", false); Sintaxe Inicial: Connection (3 de 7) • Simples conexão usando connect() da classe oracle.sqlj.runtime.Oracle – Oracle.connect(MyClass.class, "connect.properties"); – Oracle.connect("jdbc:oracle:thin:@localhost:1521: orcl", "scott", "tiger"); • A função connect() simplifica o processo de criação e usa uma instância da classe DefaultContext Sintaxe Inicial: Connection (4 de 7) • Formato do arquivo “properties”: sqlj.url=jdbc:oracle:thin:@localhost:1521:dbhome sqlj.user=scott sqlj.password=tiger Sintaxe Inicial: Connection (5 de 7) • Multiplas conexões DefaultContext ctx1 = Oracle.getConnection ( "jdbc:oracle:thin:@localhost1:1521:orcl1", "scott", "tiger"); DefaultContext ctx2 = Oracle.getConnection ( "jdbc:oracle:thin:@localhost2:1521:orcl2", "bill", "lion"); #sql [ctx1] { SQL operation }; ... #sql [ctx2] { SQL operation }; Sintaxe Inicial: Connection (6 de 7) • Se uma conexão é usada várias vezes podemos fazer: DefaultContext.setDefaultContext(ctx1); #sql { SQL operation }; #sql { SQL operation }; #sql { SQL operation }; ... DefaultContext.setDefaultContext(ctx2); #sql { SQL operation }; #sql { SQL operation }; #sql { SQL operation }; Sintaxe Inicial: Connection (7 de 7) • Fechando a conexão – Há um “commit” implícito quando a conexão é fechada ... finally { try { ctx.close(); //ou Oracle.close(); } catch(SQLException ex) { ... } } ... Sintaxe Inicial: Interfaces (1 de 3) • Iterator e Context são transformados em classes java depois de traduzidos #sql iterator MyCheckedIter (String ITEM_NAME, Double COST); tradutor class MyCheckedIter extends sqlj.runtime.ref.ResultSetIterImpl implements sqlj.runtime.NamedIterator{ … public String ITEM_NAME(){…} public Double COST(){…} … } Sintaxe Inicial: Interfaces (2 de 3) • Quando se declara um “iterator” ou “context”, pode-se especificar uma ou mais interfaces #sql <modifiers> context context_classname implements intfc1,..., intfcN; • Exemplo: #sql iterator EmpIter implements mypackage.EmpIterIntfc (String emame, int empno, float sal); • Exemplo: evitar acesso a uma coluna da tabela Erro de compilação Sintaxe Inicial: SubClasses • Exemplo: // Declarando um iterator #sql public static iterator EmpIter(int empno, String ename); ... //criando a subclasse public static class EmpColl extends EmpIter {...} ... //usando a subclasse EmpColl ec; #sql ec = { select ename, empno from emp }; Sintaxe Inicial: Hosts (1 de 4) • Usados para troca de valores entre variáveis Java e SQLJ • Podem ser referenciados dentro de uma instrução SQLJ • SQLJ fica responsável em devolver os valores • O tipo da variável host é convertida para o tipo compatível com a coluna Sintaxe Inicial: Hosts (2 de 4) • Sintaxe: – : [mode] variavel_host – Onde mode pode ser • IN, OUT e INOUT – O default é OUT se a variável é parte de uma lista INTO ou em um statement SET e é IN caso contrário Sintaxe Inicial: Hosts (3 de 4) • Exemplos String nome; int mat = 5; #sql { SELECT aluno INTO :nome FROM cadastro WHERE matricula = :mat } Sintaxe Inicial: Hosts (4 de 4) • Outro exemplo: float balance = 12500.0; float minPmtRatio = 0.05; ... #sql { UPDATE creditacct SET minPayment = :(balance * minPmtRatio) WHERE acctnum = 537845 }; Comandos Avançados: Scrollable Iterators (1 de 8) • Iterator tem apenas um único método para navegar: – next() • Scrollable Iterators permite o usuário dizer o sentido da iteração Comandos Avançados: Scrollable Iterators (2 de 8) • Para um iterator tornar-se um Scrollable Iterator ele deve implementar a interface “sqlj.runtime.Scrollable” • Declaração: #sql public static MyScrIter implements sqlj.runtime.Scrollable (String ename, int empno); Comandos Avançados: Scrollable Iterators (3 de 8) • Scrollable Interface: – setFetchDirection(int) • FETCH_FORWARD (default) • FETCH_REVERSE – – – – – getFetchDirection() boolean isBeforeFirst() boolean isFirst() boolean isLast() boolean isAfterLast() Comandos Avançados: Scrollable Iterators (4 de 8) • Métodos de navegação: – – – – – boolean boolean boolean boolean boolean previous() first() last() absolute(int) relative(int) – void beforeFirst() – void afterLast() Comandos Avançados: Scrollable Iterators (5 de 8) • Exemplo ... Comandos Avançados: Scrollable Iterators (6 de 8) • Scrollable Positional Iterators • O comando: – #sql { FETCH :iter INTO :x, :y, :z } É uma abreviação para: – #sql { FETCH NEXT FROM :iter INTO :x, :y, :z } Comandos Avançados: Scrollable Iterators (7 de 8) • O comando – #sql { FETCH NEXT FROM :iter INTO :x, :y, :z } sugere um padrão para movimentos alternativos: – – – – #sql #sql #sql #sql :z } – #sql } { { { { FETCH FETCH FETCH FETCH PREVIOUS FROM :iter INTO :x, :y, :z } FIRST FROM :iter INTO :x, :y, :z } LAST FROM :iter INTO :x, :y, :z } ABSOLUTE :n FROM :iter INTO :x, :y, { FETCH RELATIVE :n FROM :iter INTO :x, :y, :z Comandos Avançados: Scrollable Iterators (8 de 8) • Não podemos usar constantes numéricas para especificar movimentos: – #sql { FETCH RELATIVE 0 FROM :iter INTO :x, :y, :z }; (ERRADO) – #sql { FETCH RELATIVE :(0) FROM :iter INTO :x, :y, :z }; (OK) Comandos Avançados: Constantes (1 de 2) • Declaração com constantes • As constantes são sempre produzidas como “public static final” Comandos Avançados: Constantes (2 de 2) • Exemplo: #sql public iterator MyScrollableIterator implements sqlj.runtime.Scrollable with (sensitivity=ASENSITIVE) (String ename, int empno); • Sensitivity é um atributo da interface sqlj.runtime.ResultSetIterator • “with” sempre deve vir após “implements” Comandos Avançados: Transação (1 de 4) • Uma transação é uma seqüência de operações SQL que o BD trata como uma simples unidade • Uma transação começa depois de: – conectar ao Banco de Dados – depois de um COMMIT – depois de um ROLLBACK Comandos Avançados: Transação (2 de 4) • Commit automático • Por default o auto-commit tem o valor “false” • Ativando o auto-commit: Oracle.getConnection ( "jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger", true); Comandos Avançados: Transação (3 de 4) • Mudando o auto-commit – ctx.getConnection().setAutoCommit(false); ou – ctx.getConnection().setAutoCommit(true); Comandos Avançados: Transação (4 de 4) • Commit e Rollback manual – #sql { COMMIT } – #sql { ROLLBACK } • Não usar o COMMIT ou o ROLLBACK quando o auto-commit estiver habilitado Comandos Avançados: SQL Dinâmico (1 de 6) • O Oracle9i possui uma extensão para suportar SQL dinâmico em SQLJ – Operações que podem mudar em tempo de execução • “Meta bind” são usados para SQL dinâmico em SQLJ Comandos Avançados: SQL Dinâmico (2 de 6) • Sintaxe :{ Java_bind_expression } ou :{ Java_bind_expression :: SQL_replacement_code } Identificador ou expressão Java do tipo String Seqüência de SQL tokens Comandos Avançados: SQL Dinâmico (3 de 6) • Exemplo 1: ... int x = 10; int y = x + 10; int z = y + 10; String table = "new_Emp"; #sql { INSERT INTO :{table :: emp} VALUES (:x, :y, :z) }; ... Durante a tradução: INSERT INTO emp VALUES (10, 20, 30); Durante a execução: INSERT INTO new_Emp VALUES (10, 20, 30); Comandos Avançados: SQL Dinâmico (4 de 6) • Exemplo 2: ... String table = "new_Emp"; String query = "ename LIKE ’S%’ AND sal>1000"; #sql myIter = { SELECT * FROM :{table :: emp2} WHERE :{query :: ename=’SCOTT’} }; ... Durante a transação: SELECT * FROM emp2 WHERE ename=’SCOTT’; Durante a execução: SELECT * FROM new_Emp WHERE ename LIKE ’S%’ AND sal>1000; Comandos Avançados: SQL Dinâmico (5 de 6) • Restrições • O “Meta bind” pode ser usado nos seguintes tipos de comandos: – – – – o nome de uma tabela o nome de uma coluna (sem alias) todo ou parte de uma cláusula WHERE um valor literal ou uma expressão SQL Comandos Avançados: SQL Dinâmico (6 de 6) • Um “Meta bind” não pode ser a primeira expressão de uma operação SQL • Não pode conter o token “INTO” • Não pode aparecer em qualquer dos tipos de instruções SQL/SQLJ: – CALL, VALUES, PSM SET, COMMIT, ROLLBACK, FETCH INTO ou CAST Requisitos (1 de 2) • Para rodar um programa SQLJ precisamos de: – Um driver JDBC – Um SQLJ translator: • [Oracle Home]/sqlj/lib/translator.zip (ou .jar) – Um SQLJ runtime: • runtime11.jar, runtime12. jar, runtime. jar, runtime-nonoracle. jar – O programa [Oracle Home]/bin/sqlj Requisitos (2 de 2) • Procedimentos para rodar um programa SQLJ: – – – – Colocar todos os .jar necessários no “classpath” Editar o “path” para a pasta [Oracle Home]/bin/ Criar o arquivo “.sqlj” Executar o comando: • sqlj nome_arq.sqlj – Executar o programa • Java nome_arq Referências • Manuais da Oracle – http://www.oracle.com/technology/documentation/in dex.html • Tutoriais na Web: – http://www.onjava.com/pub/ct/46 – http://www.javaworld.com/javaworld/jw-051999/jw-05-sqlj_p.html – http://www.javaolympus.com/J2SE/Database/SQLJ/ SQLJ.jsp • Leitura recomendada: Java Programming with Oracle SQLJ, Jason Price, O’Reilly