Este documento descreve como objetos Java podem ser transformados e enviados como parâmetros para procedures no Oracle, permitindo a integração entre as linguagens Java e PL/SQL. Ele também discute como listas de objetos podem ser mapeadas para tipos tabela no Oracle e retornadas como resultados de queries.
3. Fatores:
PL/SQL !!! / Java? Hibernate WTF??
Contrato com a Oracle de longo prazo
Máquina BD mais potente e ociosa
Algumas definições de segurança
Desempenho (“idas” ao banco)
5. Como “era” feito:
Statment stmt = con.createStatement();
ResultSet rs;
rs = stmt.executeQuery("select * from contatos");
List<Contato> contatos = new ArrayList<Contato>();
while (rs.next()) {
int id = rs.getString("id");
String nome = rs.getString("nome");
String email = rs.getString("email");
Contato c = new Contato(id, nome, email);
contatos.add(c);
}
8. Como “era” feito:
CREATE OR REPLACE PROCEDURE procInsereContato(
contatoId OUT Contatos.id%TYPE,
contatoNome IN Contatos.nome%TYPE,
contatoEmail IN Contatos.email%TYPE)
IS
BEGIN
INSERT INTO Contatos (id, nome, email)
VALUES (SQ_CON.NEXTVAL, contatoNome, contatoEmail)
RETURNING id INTO contatoId;
END;
9. Como “era” feito:
public class PessoaBean {
private long idPessoa;
private Date dtNascimento;
private String nome;
private char sexo;
private int idNacionalidade;
private int idUF;
private int idNaturalidade;
private String naturalidadeExt;
private int idCor;
private int idEstadoCivil;
private String telResidencial;
private String telCelular;
private String telComercial;
private String email;
private boolean stAtivo;
private FiliacaoBean filiacaoBean;
17. Primeira versão
public class Bairro {
private int id;
private String nome;
public final String getNome() {
return nome;
}
public final void setNome(String nome) {
this.nome = nome;
}
public final int getId() {
return id;
}
public final void setId(int id) {
this.id = id;
}
}
18. Primeira versão
public class Bairro {
private int id;
private String nome;
// getters e setters suprimidos
public STRUCT toSTRUCT(OracleConnection oconn)
throws SQLException {
...
}
public void toBEAN(STRUCT struct) throws
SQLException {
...
}
}
20. Primeira versão
public void toBEAN(STRUCT struct) throws SQLException {
if (null != struct) {
Object[] attributes = struct.getOracleAttributes();
if (null != attributes[0]) {
this.setId(((NUMBER)attributes[0]).intValue());
}
if (null != attributes[1]) {
this.setNome(((CHAR)attributes[1]).getString());
}
}
}
21. Primeira versão
DAO
String proc = "{call procCadastraBairro(?)}";
OracleCallableStatement cs = oconn.prepareCall(proc);
cs.setSTRUCT(1, bairro.toSTRUCT(oconn));
cs.registerOutParameter(1, OracleTypes.STRUCT,
"TP_BAIRRO");
cs.execute();
bairro.toBEAN(cs.getSTRUCT(1));
22. Primeira versão
ORACLE
CREATE OR REPLACE TYPE TP_BAIRRO AS OBJECT (
id NUMBER(3),
nome VARCHAR2(50)
);
GRANT EXECUTE ON TP_BAIRRO TO USUARIO;
23. Primeira versão
ORACLE
CREATE OR REPLACE PROCEDURE procCadastraBairro(
bairro IN OUT TP_BAIRRO)
IS
BEGIN
INSERT INTO Bairros (id, nome)
VALUES (SQ_BAI.NEXTVAL, bairro.nome)
RETURNING id INTO bairro.id;
END;
24. Primeira versão
ORACLE
CREATE OR REPLACE PROCEDURE procCadastraBairro(
bairro IN OUT TP_BAIRRO)
IS
bairroId Bairros.id%TYPE;
BEGIN
INSERT INTO Bairros (id, nome)
VALUES (SQ_BAI.NEXTVAL, bairro.nome)
RETURNING id INTO bairroId;
SELECT TP_BAIRRO(id, nome)
INTO bairro
FROM Bairros
WHERE id = bairroId;
END;
25. Primeira versão
LISTA no DAO
String proc = "{call procPesquisarBairro(?,?)}";
OracleCallableStatement cs = oconn.prepareCall(proc);
cs.setSTRUCT(1, bairro.toSTRUCT(oconn));
cs.registerOutParameter(2, OracleTypes.ARRAY,
"TPLISTA_BAIRRO");
cs.execute();
CONTINUA...
26. Primeira versão
LISTA no DAO
ARRAY array = cs.getARRAY(2);
Datum[] lista = array.getOracleArray();
List<Bairro> bairros = new ArrayList<Bairro>();
for (int i = 0; i < lista.length; i++) {
Bairro bairro = new Bairro();
bairro.toBEAN((STRUCT)lista[i]);
bairros.add(bairro);
}
return bairros;
27. Primeira versão
ORACLE
CREATE OR REPLACE TYPE TPLISTA_BAIRRO AS TABLE OF
TP_BAIRRO;
GRANT EXECUTE ON TPLISTA_BAIRRO TO USUARIO;
28. Primeira versão
ORACLE
CREATE OR REPLACE TYPE TPLISTA_BAIRRO AS TABLE OF
NUMBER;
CREATE OR REPLACE TYPE TP_BAIRRO AS OBJECT ();
/** Objetos desfeitos / inicio reconstrucao **/
CREATE OR REPLACE TYPE TP_BAIRRO AS OBJECT (
id NUMBER(3),
nome VARCHAR2(50)
);
CREATE OR REPLACE TYPE TPLISTA_BAIRRO AS TABLE OF
TP_BAIRRO;
29. Primeira versão
ORACLE
CREATE OR REPLACE PROCEDURE procPesquisarBairro(
bairro IN TP_BAIRRO,
listaBairros OUT TPLISTA_BAIRRO)
IS
BEGIN
SELECT TP_BAIRRO(id, nome)
BULK COLLECT INTO listaBairros
FROM Bairros
WHERE nome = bairro.nome;
END;
30. Primeira versão
ORACLE
SELECT VALUE(e)
BULK COLLECT INTO listaBairros
FROM TABLE( CAST( MULTISET(
SELECT id, nome
FROM Bairros
WHERE nome = bairro.nome
) AS TPLISTA_BAIRRO)) e;
31. Primeira versão
toSTRUCT()
Object[] attributes = {
int/long, // NUMBER
String, // VARCHAR2
boolean ? 1 : 0, // NUMBER(1)
3 estados ? 1 : 0 : null, // NUMBER(1)
util.Date ? new Timestamp(date.getTime()), // DATE
OutroTipo.toSTRUCT(oconn), // TP_OUTROTIPO
String ? CLOB.getEmptyCLOB(), // CLOB
listaOutroTipoArray // TPLISTA_OUTROTIPO
};
32. Primeira versão
toSTRUCT()
ARRAY listaOutroTipoArray = null;
ArrayDescriptor ad =
ArrayDescriptor.createDescriptor("TPLISTA_OUTROTIPO",
oconn);
List<Object> listaItems = new ArrayList<Object>();
for (OutroTipo outro : this.listaOutroTipo) {
listaItems.add(outro.toSTRUCT(oconn));
}
listaOutroTipoArray =
new ARRAY(ad, oconn, listaItems.toArray());
}
33. Primeira versão
toBEAN()
Object[] valores = struct.getOracleAttributes();
((NUMBER)valores[0]).intValue();
((NUMBER)valores[1]).longValue();
((CHAR)valores[2]).getString();
((NUMBER)valores[3]).booleanValue();
((DATE)valores[4]).timestampValue();
this.outroTipo = new OutroTipo();
this.outroTipo.toBEAN((STRUCT)valores[5]);
34. Primeira versão
toBEAN()
CLOB cl = ((CLOB)valores[6]);
Reader reader = cl.characterStreamValue();
StringBuffer sb = new StringBuffer();
int nchars = 0;
char[] buffer = new char[10];
while((nchars = reader.read(buffer)) != -1) {
sb.append(buffer, 0, nchars);
}
reader.close();
this.setDescricao(sb.toString());
35. Primeira versão
toBEAN()
this.listaOutroTipo = new ArrayList<OutroTipo>();
Datum[] lista = ((ARRAY)valores[7]).getOracleArray();
for (int i = 0; i < lista.length; i++) {
OutroTipo outro = new OutroTipo();
outro.toBEAN((STRUCT)lista[i]);
this.listaOutroTipo.add(outro);
}
43. OracleTypeConverter
LISTA no DAO
cs.setARRAY(1, OracleTypeConverter.toARRAY(oconn,
listaBairros, "TPLISTA_BAIRRO"));
cs.registerOutParameter(2, OracleTypes.ARRAY,
"TPLISTA_BAIRRO");
cs.execute();
listaBairros =
OracleTypeConverter.toList(Bairro.class,cs.getARRAY(2))
;
44. OracleTypeConverter
@DBType("TP_PAGINACAO")
public class Paginacao {
private int pagina = 1;
private int quantRegistros = 10;
@SendNull
private int total;
@NotInType
private String action;
@DBType("TRISTATES")
private String ativo;
// getters e setters suprimidos
}
45. OracleTypeConverter
ORACLE
CREATE OR REPLACE TYPE TP_PAGINACAO AS OBJECT (
pagina NUMBER,
quantRegistros NUMBER,
total NUMBER,
ativo NUMBER(1)
);
46. OracleTypeConverter
@DBType("TP_OCORRENCIA")
public class Ocorrencia {
private Long id;
private Assunto assunto;
private Date dataCadastro;
private boolean stImprimirCarta;
@DBType("CLOB")
private String descricao;
@DBType("TPLISTA_ENCAMINHAMENTO")
private List<Encaminhamento> listaEncaminhamento;
@SendNull
@DBType("TPLISTA_LOTEIMPRESSAO")
private List<LoteImpressao> listaLoteImpressao;
47. OracleTypeConverter
ORACLE
CREATE OR REPLACE TYPE TP_OCORRENCIA AS OBJECT (
id NUMBER,
assunto TP_ASSUNTO,
dataCadastro DATE,
stImprimirCarta NUMBER(1),
descricao CLOB,
listaEncaminhamento TPLISTA_ENCAMINHAMENTO,
listaLoteImpressao TPLISTA_LOTEIMPRESSAO
);
50. OracleTypeConverter
Não converte FLOAT, DOUBLE, BigDecimal, BigInteger
(ainda não precisei destes);
A converão é baseada na ordem dos atributos;
Cuidado com o tamanho da String para VARCHAR(?) e
do Integer para NUMBER(?);
Até o java 1.6 não existe suporte para o tipo Boolean do
PL/SQL;
Necessita de refatoração urgente!!!
51. Referências
Oracle Database JDBC Developer's Guide and Reference:
Working with Oracle Object Types
http://download.oracle.com/docs/cd/B19306_01/java.102/b14355/oraoot.htm
Using PL/SQL Collections and Records
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/collections.htm
Oracle Database JPublisher User's Guide:
Introduction to JPublisher
http://download.oracle.com/docs/cd/B19306_01/java.102/b14188/intro.htm
Introduction to JPublisher # JDBC Mapping
http://download.oracle.com/docs/cd/B19306_01/java.102/b14188/intro.htm#sthref50
52.
53. Obrigado!
André Luis F. Reis
arghos@gmail.com
twitter.com/andrelfreis
facebook.com/andrelfreis
linkedin.com/in/andrelfreis