passagem de objetos entre java e oracle
DESCRIPTION
Transformando e enviando Pojos Java como parametros para Procedures em PL/SQL no OracleTRANSCRIPT
Passagem de Objetos entre Java e Oracle
Transformando e enviando Pojos Java como parâmetros para Procedures em PL/SQL no Oracle.
?
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)
Fatores:
Como “era” feito:
String sql = "insert into contatos (nome,email) values (?,?)";PreparedStatement stmt = con.prepareStatement(sql);stmt.setString(1, contato.getNome());stmt.setString(2, contato.getEmail());stmt.execute();
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); }
Depois:
session.save(contato);
Como “era” feito:String proc = "{call procInsereContato(?,?,?)}";CallableStatement cs = con.prepareCall(proc);cs.registerOutParameter(1, java.sql.Types.NUMERIC);cs.setString(2, contato.getNome());cs.setString(3, contato.getEmail());cs.execute();contato.setId(cs.getInt(1));
Como “era” feito:CREATE OR REPLACE PROCEDURE procInsereContato(
contatoId OUT Contatos.id%TYPE, contatoNome IN Contatos.nome%TYPE, contatoEmail IN Contatos.email%TYPE)
ISBEGIN INSERT INTO Contatos (id, nome, email) VALUES (SQ_CON.NEXTVAL, contatoNome, contatoEmail) RETURNING id INTO contatoId; END;
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;private DadoCivilBean dadoCivilBean;private EnderecoBean enderecoBean;
Como “era” feito:String proc = "{call procCadastraPessoa(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}";CallableStatement cs = con.prepareCall(proc);cs.setLong(1, pessoa.getIdPessoa());cs.setDate(2, pessoa.getDtNascimento());cs.setString(3, Character.toString(pessoa.getSexo()));cs.setInt(4, pessoa.getIdNacionalidade());cs.setInt(5, pessoa.getIdUF());cs.setInt(6, pessoa.getIdNaturalidade());cs.setString(7, pessoa.getNaturalidadeExt());cs.setInt(8, pessoa.getIdCor());cs.setInt(9, pessoa.getIdEstadoCivil());cs.setString(10, pessoa.getTelResidencial());cs.setString(11, pessoa.getTelCelular());
String proc = "{call procCadastraPessoa(?)}"; CallableStatement cs = con.prepareCall(proc); cs.setObject(1, pessoa); Pessoa p = cs.getObject(2);
PROCEDURE procCadastraPessoa(Pessoa IN p);
Bizzaro!?
ojdbc14.jarojdbc14.jar
Primeira versãopublic 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;}
}
Primeira versãopublic class Bairro {
private int id;private String nome;// getters e setters suprimidospublic STRUCT toSTRUCT(OracleConnection oconn)
throws SQLException {...
}public void toBEAN(STRUCT struct) throws
SQLException {...
}}
Primeira versão
public STRUCT toSTRUCT(OracleConnection oconn) throws SQLException {
StructDescriptor sd = StructDescriptor.createDescriptor("TP_BAIRRO", oconn);
Object[] attributes = { ( 0 >= this.id ? null : this.id ),( "".equals(this.nome) ? null : this.nome )
};return new STRUCT(sd, oconn, attributes);
}
Primeira versãopublic 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()); } } }
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));
Primeira versãoDAO
Primeira versão
CREATE OR REPLACE TYPE TP_BAIRRO AS OBJECT ( id NUMBER(3), nome VARCHAR2(50));
GRANT EXECUTE ON TP_BAIRRO TO USUARIO;
ORACLE
CREATE OR REPLACE PROCEDURE procCadastraBairro( bairro IN OUT TP_BAIRRO)
ISBEGIN INSERT INTO Bairros (id, nome) VALUES (SQ_BAI.NEXTVAL, bairro.nome) RETURNING id INTO bairro.id; END;
Primeira versãoORACLE
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;
Primeira versãoORACLE
Primeira versãoLISTA 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...
Primeira versãoLISTA 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;
Primeira versão
CREATE OR REPLACE TYPE TPLISTA_BAIRRO AS TABLE OF TP_BAIRRO;
GRANT EXECUTE ON TPLISTA_BAIRRO TO USUARIO;
ORACLE
Primeira versão
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;
ORACLE
CREATE OR REPLACE PROCEDURE procPesquisarBairro( bairro IN TP_BAIRRO, listaBairros OUT TPLISTA_BAIRRO)
ISBEGIN
SELECT TP_BAIRRO(id, nome) BULK COLLECT INTO listaBairros FROM Bairros WHERE nome = bairro.nome;
END;
Primeira versãoORACLE
SELECT VALUE(e) BULK COLLECT INTO listaBairros FROM TABLE( CAST( MULTISET(
SELECT id, nome
FROM Bairros WHERE nome = bairro.nome
) AS TPLISTA_BAIRRO)) e;
Primeira versãoORACLE
Primeira versão
Object[] attributes = { int/long, // NUMBERString, // VARCHAR2boolean ? 1 : 0, // NUMBER(1)3 estados ? 1 : 0 : null, // NUMBER(1)util.Date ? new Timestamp(date.getTime()), // DATEOutroTipo.toSTRUCT(oconn), // TP_OUTROTIPOString ? CLOB.getEmptyCLOB(), // CLOBlistaOutroTipoArray // TPLISTA_OUTROTIPO
};
toSTRUCT()
Primeira versãotoSTRUCT()
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());}
Primeira versãotoBEAN()
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]);
Primeira versãotoBEAN()
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());
Primeira versãotoBEAN()
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);
}
Primeira versãoimport java.io.IOException;import java.io.Reader;import java.sql.SQLException;import java.util.ArrayList;import java.util.Date;import java.util.List;import oracle.jdbc.OracleConnection;import oracle.sql.ARRAY;import oracle.sql.ArrayDescriptor;import oracle.sql.CHAR;import oracle.sql.CLOB;import oracle.sql.DATE;import oracle.sql.Datum;import oracle.sql.NUMBER;import oracle.sql.STRUCT;import oracle.sql.StructDescriptor;
Bizzaro!?
OracleTypeConverter
@ DBType(value)
@ NotInType
@ SendNull
OracleTypeConverter
STRUCTPrinter
@DBType("TP_BAIRRO")public class Bairro {
private int id;private String nome;// getters e setters suprimidos
}
OracleTypeConverter
String proc = "{call procCadastraBairro(?)}";OracleCallableStatement cs = oconn.prepareCall(proc);cs.setSTRUCT(1, OracleTypeConverter.toSTRUCT(oconn, bairro));cs.registerOutParameter(1, OracleTypes.STRUCT, OracleTypeConverter.getDBTypeAnnotation(Bairro.class));cs.execute();bairro = OracleTypeConverter.toBEAN(Bairro.class, cs.getSTRUCT(1));
DAO
OracleTypeConverter
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));
LISTA no DAO
OracleTypeConverter
@DBType("TP_PAGINACAO")public class Paginacao {
private int pagina = 1;private int quantRegistros = 10;@SendNullprivate int total;@NotInTypeprivate String action;@DBType("TRISTATES")private String ativo;// getters e setters suprimidos
}
OracleTypeConverter
CREATE OR REPLACE TYPE TP_PAGINACAO AS OBJECT ( pagina NUMBER, quantRegistros NUMBER, total NUMBER, ativo NUMBER(1));
ORACLE
OracleTypeConverter
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;
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 );
ORACLE
OracleTypeConverter
cs.setSTRUCT(1, OracleTypeConverter.toSTRUCT(oconn, ocorrencia));cs.registerOutParameter(2, OracleTypes.CLOB);cs.execute();CLOB clob = cs.getCLOB(2);Writer sw = clob.setCharacterStream(1L); sw.write(ob.getDescricao().trim().toCharArray());sw.flush();sw.close();
DAO – Enviar CLOB
OracleTypeConverter
OracleTypeConverter
OracleTypeConverterNã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!!!
ReferênciasOracle Database JDBC Developer's Guide and Reference:
Working with Oracle Object Typeshttp://download.oracle.com/docs/cd/B19306_01/java.102/b14355/oraoot.htm
Using PL/SQL Collections and Recordshttp://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/collections.htm
Oracle Database JPublisher User's Guide:
Introduction to JPublisherhttp://download.oracle.com/docs/cd/B19306_01/java.102/b14188/intro.htm
Introduction to JPublisher # JDBC Mappinghttp://download.oracle.com/docs/cd/B19306_01/java.102/b14188/intro.htm#sthref50
Obrigado!
André Luis F. Reis
twitter.com/andrelfreis
facebook.com/andrelfreis
linkedin.com/in/andrelfreis