Você está na página 1de 26

Artigo Java Magazine 40 - Hibernate e Stored Procedures

1 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

www.devmedia.com.br
[verso para impresso]
Link original: http://www.devmedia.com.br/articles
/viewcomp.asp?comp=10222

Artigo da Revista Java Magazine Edio 40.


Esse artigo faz parte da revista Java Magazine edio 40.
Clique aqui para ler todos os artigos desta edio

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

2 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

Ateno: por essa edio ser muito antiga no h arquivo PDF para
download.Os artigos dessa edio esto disponveis somente atravs do
formato HTML.

Hibernate e Stored Procedures


Obtendo o Melhor dos Mundos O/R e Procedural

Aprenda a integrar eficientemente o famoso framework de persistncia


s stored procedures de seu banco de dados

Desde a sua verso 3.0, o framework de persistncia Hibernate suporta a


integrao com stored procedures para alguns dos principais bancos de dados
(Oracle, DB2, Sybase e SQL Server) e atualmente a verso 3.1.3 tambm
oferece suporte a stored procedures desenvolvidas para MySQL e Apache Derby.
Neste artigo vamos discutir como tirar o melhor proveito deste recurso de
integrao.

Remdio ou veneno?
Os principais gerenciadores de bancos de dados oferecem linguagens procedurais
para o desenvolvimento de stored procedures (SPs). As SPs so tradicionalmente
empregadas em sistemas corporativos por trs motivos bsicos, detalhados a
seguir.

Aumento de desempenho
Por se tratarem de rotinas armazenadas no prprio banco de dados as SPs tm
acesso imediato aos registros das tabelas e so capazes de manipular um grande
volume de informaes sem gerar trfego de rede. Variando entre fabricantes de
banco de dados, as linguagens procedurais geralmente oferecem estruturas de
controle e poderosos mecanismos de manipulao de cursores que permitem uma
programao de baixo nvel. Nas mos de programadores experientes, essas
linguagens podem resolver muitos problemas e gargalos de desempenho, que a

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

3 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

arquitetura cliente/servidor, baseada em instrues SQL, no capaz de


resolver. verdade que muitos "gargalos" de desempenho so causados por
problemas de modelagem do banco de dados.
Porm, o esforo de construo de uma stored procedure de alto desempenho
pode ser menor do que e o necessrio para remodelagem e migrao de dados de
produo.

Centralizao de regras
Uma segunda motivao para o uso de stored procedures a possibilidade de
centralizar regras de negcio no repositrio de dados. Freqentemente
encontramos vrias aplicaes desenvolvidas em plataformas diferentes
acessando o mesmo banco de dados. Nesta situao
pode ser desastroso pressupor que todas as aplicaes reproduzem fielmente as
mesmas regras de negcio para manipular os dados. Aqui as stored procedures
so valiosas para criar uma camada de regras unificada e obrigatria para todos
que pretendem operar com os dados. (Triggers de banco de dados podem ser uma
opo s SPs neste caso - confira o quadro
"Regras de negcio com Triggers".)

Mais segurana
As polticas de segurana de uma empresa podem apontar tabelas que contm
informaes sensveis e que no devem ficar disposio dos programadores e
da maioria das aplicaes. As views de bancos de dados constituem uma primeira
soluo, expondo informaes de maneira controlada e reduzindo assim os riscos
de segurana.
Porm, em algumas situaes o uso de views pode reduzir o desempenho em
operaes de consultas mais elaboradas especialmente quando precisam ser
combinadas com outras tabelas atravs de joins. Quando encontramos tal
impasse podemos abandonar as views e resolver as operaes de consulta
atravs de stores procedures desenvolvidas por administradores

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

4 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

de banco de dados (DBAs) ou por outros tcnicos com permisso de acesso as


tabelas mais sensveis.

Desvantagens
Ao considerar as SPs, no podemos ignorar seus pontos negativos. O primeiro
deles a portabilidade. A criao de muitas stored procedures pode manter as
solues tecnolgicas de uma empresa vinculadas a um fabricante de banco de
dados, pois as linguagens procedurais
normalmente so proprietrias. Diante da necessidade de adotar um novo
gerenciador de banco de dados (SGBD), a tarefa de re-escrita das SPs representa
um investimento alto. Num momento como esse, as empresas podem preferir
adotar outras arquiteturas para no cair em um novo cenrio de dependncia de
um SGBD especfico.
Um outro ponto negativo tem a ver com o desempenho. Uma stored procedure
mal programada ou mal testada pode comprometer o desempenho de todo o
banco de dados, e conseqentemente, de todas as aplicaes dependentes deste
banco.
Discutimos algumas alternativas as SPs no quadro "Alternativas Java".

Vantagens do Hibernate no contexto


antes de mostrar como acessar SPs atravs do Hibernate, vamos comentar
quatro capacidades muito importantes do Hibernate, que no podemos perder de
vista ao adotar esse framework como soluo de persistncia.
A primeira dessas capacidades o que todos esperam em um framework de
persistncia: o mapeamento objeto-relacional. Uma vez que as colunas das
tabelas estejam mapeadas para os atributos das classes, no precisamos escrever
instrues em SQL, ou manipular a API JDBC. Mais ainda, no precisamos
instanciar e preencher os objetos com valores recuperados
de consultas ao banco de dados.
A segunda capacidade a portabilidade, que derivada da primeira. Estando

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

5 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

tudo mapeado, podemos migrar nossa aplicao para qualquer outro banco de
dados suportado pelo Hibernate. O esforo de migrao muitas vezes limita-se a
ajustar o dialeto do Hibernate utilizado e, se necessrio, modificar nomes de
colunas e tabelas nos arquivos (ou anotaes) de mapeamento.
A terceira capacidade menos evidente, mas extremamente importante para
nossa discusso: caches. Atravs do mapeamento objeto-relacional, o Hibernate
compreende como so nossos objetos e como eles se relacionam e levando em
conta esse conhecimento, cria caches de objetos em memoria para reaproveitar
informaes acessadas recentemente,
minimizando consultas ao banco de dados. Veja mais no quadro "Caches do
Hibernate".
A quarta capacidade o mecanismo conhecido como "automatic dirty checking",
que percebe as alteraes nos objetos vinculados a um cache de sesso e agenda
operaes de insert, update e delete. Quando executamos o mtodo flush() em
um objeto Session do Hibernate, ou quando encerramos uma transao, as
operaes de modificao "agendadas" so executadas para atualizar o banco de
dados com a situao dos objetos em memria.
Mantendo em mente a terceira e a quarta capacidades, conseguiremos integrar
corretamente
as SPs ao Hibernate.

Hibernate e procedures de persistncia


As operaes de persistncia de objetos via Hibernate acabam gerando operaes
tradicionais com SQL no banco de dados: select, insert, update e delete. Vamos
nos basear em um cenrio onde as stored procedures so desenvolvidas para
substituir as operaes tradicionais, a fim de realizar operaes de persistncia
diferenciadas, em um sistema de cadastro de correntistas
de uma instituio bancria. Os exemplos utilizam a linguagem procedural
PL/SQL para bancos de dados Oracle.
A Figura 1 mostra as tabelas de correntistas e funcionrios da instituio. Vamos

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

6 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

suportar uma regra de negcio que afeta as operaes de persistncia: "Todo


funcionrio considerado um correntista que possui uma conta para recebimento
de salrio".
No modelo apresentado, a tabela de funcionrios pertence ao sistema de recursos
humanos, e o acesso direto as colunas ID_FUNCIONARIO, RAMAL e SALARIO
no est liberado para o sistema de cadastro de correntistas. Uma tabela auxiliar
(tb_funcionarios_aux) armazena informaes adicionais do funcionrio, que
so relevantes para o cadastro de correntistas, inclusive um identificador. Toda
vez que dados de correntistas estiverem sob recuperao ou alterao, devemos
considerar a tabela tb_correntistas e tambm as tabelas tb_funcionarios e
tb_funcionarios_aux.
Por questes de segurana de dados, uma insero ou deleo feita atravs do
cadastro de correntistas nunca afeta as tabelas de funcionrios (um funcionrio
inserido e deletado pelo sistema de RH).
Apresentamos na Listagem 1 as procedures de consulta (get_correntista_id e
get_correntistas) capazes de unificar os funcionrios aos correntistas. Nessa
listagem temos tambm uma procedure (altera_correntista) para modificar os
dados de um correntista, em tb_correntistas ou nas tabelas tb_funcionarios e
tb_funcionarios_aux.
Outras abordagens (como herana) poderiam resolver este problema, evitando o
uso de stored procedures, mas estamos imaginando uma base de dados legada
que possui estas procedures e este modelo de dados homologados.

A Listagem 2 mostra a classe dos correntistas e a Listagem 3 apresenta o


arquivo de mapeamento objeto-relacional, incluindo o mapeamento das stored
procedures.

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

7 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

Figura 1. Tabelas do banco de dados

Listagem 1. Stored Procedures para Orade (em


PL/SQL)

create or replace package pkg_correntista as


type cursor_type is ref cursor;
function get_correntista_id (
id IN numeric) return cursor_type;
function get_correntistas (
pAgencia IN numeric. pNome IN varchar2)
return cursor_type;
function altera_correntista (
pAgencia IN integer, pNome IN varchar2,
pRg IN varchar2, pCpf IN varchar2,
pTelefone IN varchar2,pRef_com IN varchar2,
pTel_ref_com IN varcharZ2 pId IN integer) return integer;
end pkg_correntista;

create or replace package body pkg_correntista as


function get_correntista_id (
id IN numeric) return cursor_type
as

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

8 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

cursor_correntista cursor_type;
qtd integer;
begin
-- verifica presenca de correntista
select count(id_correntista) into qtd
from tb_correntlstas where ld correntlsta = id;
if qtd = 1 then -- eh correntista
open cursor_correntista for
select id_correntista, id_agencia, nome,
rg, cpf, telefone,
referencia_comercial, telefone_ref comercial
from tb_correntistas
where id_correntista = id;
return cursor_correntista;
else -- eh funcionario
open cursor_correntista for
select a.id_correntista, a.id_agencia, f.nome,
f.rg, a.cpf, f.telefone_residencia as telefone,
a.referencia_comercial, a.telefone_ref_comercial
from tb_funcionarios f, tb_funcionarios_aux a
where f.id_funcionario = a.id_funcionario
and a.id_correntista = id;
return cursor_correntista;
end if;
end get_correntista_id;

function get_correntistas (
pAgencia IN numeric, pNome IN varchar2)
return cursor_type as
cursor_correntistas cursor_type;

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

9 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

begin
open cursor_correntistas for
select id_correntista, id_agencia, nome,
rg, cpf, telefone,
referencia_comercial, telefone_ref_comercial
from tb_correntistas
where id_agencia = pAgencia and nome like pNome
union
select a.id_correntista, a.id_agencia, f.nome,
f.rg, a.cpf, f.telefone_residencia as telefone,
a.referencia_comercial, a.telefone ref_comercial
from tb_funcionarias f, tb_funcianarios_aux a
where f.id_funcionario = a.id_funcianario
and a.id_agencia = pAgencia and f.nome like pNome:
return cursor_correntistas;
end get_correntistas;

function altera_correntista (
pAgencia IN integer, pNome IN varchar2,
pRg IN varchar2. pCpf IN varchar2,
pTelefone IN varchar2.pRef_com IN varchar2.
pTel_ref_com IN varchar2. pId IN integer)
return integer as
qtd integer;
idFunc integer;
begin
-- verifica presenca de correntista
select count(id_correntista) into qtd
from tb correntistas where id correntista = pId;
if qtd =1 then --eh correntista

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

10 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

update tb_correntistas
set id_agencia = pAgencia. nome = pNome,
rg = pRg, cpf = pCpf, telefone = pTelefone,
referencia_comercial = pRef_com,
teIefone_ref_comercial = pTel_ref_com
where id_correntista = pId;
else --eh funcionario
--localiza id funcionario
select id_funcionario into idFunc
from tb_funcionarios aux where id correntista = pId;
-- update 1a. parte
update tb_funcionarios
set nome = pNome. rg = pRg,
telefone_residencia = pTelefone
where id funclonario = idFunc;
-- update 2a. parte
update tb_funcionarios_aux
set id_agencia = pAgencia, cpf = pCpf,
referencia_comercial = pRef_com,
telefone ref_comerclal = pTel_ref_com
where id_correntista = pId;
end if;
return SOL%ROWCOUNT;
end altera_correntista;
end pkg_correntista;

Listagem 2.
Correntista.java

package jm.sp.hib.model;

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

11 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

public class Correntista {


private Integer idCorrentista;
private Short idAgencia;
private String nome;
private String rg;
private String cpf;
private String telefone;
private String referenciaComercial;
private String telefoneRefComercial;
// getters e setters omitidos
}

Listagem 3.
Correntista.hbm.xml

<?xml version-"1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD
3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping3.0.dtd">

<hibernate-mapping schema="SCOTT" package="jm.sp.hib.model">

<class name="Correntista" table="TB_CORRENTISTAS" optimisticlock="none">


<id name="idCorrentista" type="integer" unsaved-value="null">
<column name="ID_CORRENTISTA" not-null="true"/>
<generator class="sequence">
<param name="sequence">seq_correntistas</param>

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

12 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

</generator>
</id>
<property name="idAgencia" column="ID_AGENCIA"/>
<property name="nome" column="NOME" not-null="true"/>
<property name="rg" column="RG" I>
<property name="cpf" column="CPF" not-null="true"/>
<property name="telefone" column="TELEFONE" />
<property name="referenciaComercial"
column="REFERENCIA_COMERCIAL" />
<property name="telefoneRefComerclal" column="TELEFONE
REF_COMERCIAL"/>
<loader query-ref="sp.recupera.correntista.id"/>
<sql-update callable="true">
{? = call pkg_correntista.altera_correntista(?,?,?,?,??,?,?)}
</sql-update>
</class>

<sql-query name="sp.recupera.correntista.id" callable="true">


<return alias="correntista" class="Correntista">
<return-property name="idCorrentista" column="ID_CORRENTISTA" I>
<return-property name="idAgencia" column="ID_AGENCIA"/>
<return-property name="nome" column="NOME"/>
<return-property name="rg" column="RG"/>
<return-property name="cpf" column="CPF"/>
<return-property name="telefone" column="TELEFONE"/>
<return-property name="referenciaComercial"
column="REFERENCIA_COMERCIAL"/>
<return-property name="telefoneRefComercial"

column="TELEFONE_REF_COMERCIAL"/>

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

13 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

</return>
<![CDATA[ {? = call pkg_correntista.geCcorrentista_id(?)}]]>
</sql -query>

<sql-query name="sp.recupera.correntistas" callable="true">


<return alias="correntista" class="Correntista">
<return-property name="idCorrentista" column="ID_CORRENTISTA" I>
<return-property name="idAgencia" column="ID_AGENCIA"/>
<return-property name="nome" column="NOME"/>
<return-property name="rg" column="RG"/>
<return-property name="cpf" column="CPF"/>
<return-property name="telefone" column="TELEFONE"/>
<return-property name="referenciaComercial" column="REFERENCIA
COMERCIAL"/>
<return-property name="telefoneRefComercial"

column="TELEFONE_REF_COMERCIAL"/>
</return>

<![CDATA[ {? - call pkg_correntista.get_correntistas(?,?)} ]]>


</sql -query>
</hibernate-mapping>

Mapeando procedures de recuperao de dados

Primeiramente vamos comentar os elementos de mapeamento para as


procedures que retornam resultsets, com dados que podem ser utilizados para
preencher objetos de correntistas.
No caso dos bancos de dados cujas procedures retornam o resultado de uma
consulta atravs de um cursor, como o Oracle, temos que observar a seguinte

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

14 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

regra: o Hibernate sempre considera o primeiro parmetro da procedure como


um parmetro de retorno (OUT), que devolve justamente o cursor que
representa o resultset desejado. Esta regra no se aplica ao Sybase ou ao SQL
Server, pois suas procedures no precisam declarar cursores para retornar o
resultado de uma consulta.
Qualquer que seja a estratgia de retorno de resultados utilizada por uma
linguagem procedural (com ou sem declarao de cursores), o Hibernate
considera apenas o primeiro resultset retornado. SPs que retornam mltiplos
resultsets no sero plenamente aproveitadas pelo Hibernate.

Se o cursor retornado por sua procedure se encontra fora do primeiro parmetro


voc deve criar uma "procedure adaptadora; que invoca a procedure original e
retorna o cursor desejado como primeiro parmetro.

As procedures de consulta devem ser mapeadas e nomeadas no Hibernate


atravs de elementos , como se v na Listagem 3. O sub-elemento utilizado
para definir o tipo dos objetos que
sero retornados. Cada elemento mapeia um atributo de Correntista para uma
coluna encontrada no resultset retornado. E na regio CDATA descrevemos a
procedure, seguindo o estilo dos mtodos prepareCall() de
java.sql.Connection.
Quando invocamos os mtodos get() e load() em um objeto Session, o
Hibernate obrigado a recuperar dados de um objeto atravs do seu atributo
identificador. E se esses dados no se encontram nos caches, a recuperao exige
uma consulta ao banco de dados. Por default, esta consulta e uma instruo
select resolvida dinamicamente pelo Hibernate baseando-se nos dados de
mapeamento. Podemos redefinir este comportamento utilizando o elemento como
mostra a Listagem 3. Este elemento configura o Hibernate para utilizar a
consulta nomeada sp.recupera.correntista.id, que est associada procedure
get_correntista_id, quando for necessrio carregar do banco de dados um

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

15 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

objeto Correntista atravs de seu atributo identificador.


Esse esforo de mapeamento nos traz alguns benefcios: os objetos so
preenchidos automaticamente pelo Hibernate e armazenados nos caches de
Session e de SessionFactory. As consultas feitas atravs do identificador de
correntista (mtodos get() e load()) podem se beneficiar de informaes
parcialmente carregadas nos caches, sem necessidade de acesso ao banco de
dados.

Mapeando stored procedures de modificao


Ao encontrar em seu cache objetos da classe dos correntistas modificados (dirty),
o Hibernate devera realizar operaes de update no banco de dados. Por default,
a seguinte instruo seria gerada dinamicamente, levando em considerao o
mapeamento estabelecido:

update TB_CORRENTISTAS
set ID_AGENCIA=?, NOME=?,
RG=?, CPF=?, TELEFONE=?,
REFERENCIA_COMERCIAL= ?,
TELEFONE_REF _COMERCIAL=?
where ID_CORRENTISTA=?

Na Listagem 3, observamos o elemento , que foi aplicado para forar o


Hibernate a utilizar a procedure altera_correntista, para atualizar no banco de
dados a situao dos objetos modificados.
Uma regra importante: o Hibernate espera encontrar a procedure estabelecida
em com a mesma quantidade e ordem de parmetros da instruo update que
seria gerada dinamicamente. A ordem dos parmetros determinada pela ordem
das declaraes dos elementos do arquivo de mapeamento.
Na dvida, voc pode utilizar a seguinte estratgia: omita o elemento , habilite o
og de SQL o Hibernate, e force as operaes de persistncia para observar como

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

16 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

as colunas so consideradas. Para habilitar o log, utilize o elemento no arquivo


de configurao da SessionFactory, como na Listagem4.

Aqui tambm pode ser necessrio criar uma "procedure adaptadora, que recebe
os parmetros na ordem considerada pelo Hibernate e os repassa para a
procedure original, na ordem adequada.

Analogamente, os elementos e podem ser empregados no arquivo de


mapeamento para designar procedures customizadas de insero e deleo de
registros. ( recomendvel que as stored procedures mapeadas nestes elementos
retornem a quantidade de linhas afetadas no banco de dados.)
O benefcio deste esforo de mapeamento que os caches do Hibernate ficam
naturalmente
sincronizados com a situao do banco de dados, e portanto no necessitam de
limpeza. Acompanhe na Listagem 5 um exemplo completo com procedures de
persistncia.

Listagem 4. hibernate.cfg.xml- Configurao da Session


Factory

<?xml version-"1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate=configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration 3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">
oracle.jdbc.driver.OracleDriver

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

17 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

</property>
<property name="hibernate.connection.url">
jdbc:oracle:thin:@localhost:1521:ORCL</property>
<property name="hibernate.connection.password">tiger</property>
<property name="hibernate.connection.username">scott</property>
<property
name="hibernate.dialect">org.hibernate.dialect.OracleOialect</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="jm/sp/hib/model/Correntista.hbm.xml"/>
</session-factory>
</hibernate-configuration>

Listagem 5. Realizando operaes com Hibernate configurado para utilizar


procedures de persistncia

package jm.sp.hib.teste;
import jm.sp.hib.model.Correntista;
import java.util.List;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;

public class ExemploProceduresPersistencia {


public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
SessionFactory sf = cfg.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

18 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

try {
// consuta por agencia e por nome
// sp.recupera.correntistas = get_correntistas(?,?)
Query q = session.getNamedQuery("sp.recupera.correntistas");
q.setInteger(0, 400); // agencia
q.setString(1, "%Santos%"); // trecho do nome
List listaCorrentistas = q.list(); // coleo de correntistas
for(int i =0; i < listaCorrentistas.size(); i++) {
Correntista c = CCorrentista) listaCorrentistas.get(i);
// manipula coleo de correntistas
}
// consulta por idCorrentista
// <loader> = sp.recupera.correntista.id = get_correntista_id(?)
// dados podem ser aproveitados dos caches
Correntista corr = (Correntista) session.get(Correntista.class. new
Integer(600932));
corr.setTelefone("6655-4433"); // sujando o objeto
// <sql-update> = altera_correntista
session.flush();
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
}

finally {
session.close();
sf.close();

}
}
}

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

19 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

Hibernate e procedures de negcio


Existem determinadas procedures de banco de dados que suportam todo um
processo de negcio. Procedures desse tipo no se destinam a realizar simples
operaes de persistncia; elas tm a responsabilidade de garantir o
cumprimento de regras importantes, muitas vezes criando e modificando diversas
tabelas no banco de dados.
Por ser um framework de persistncia e no de regras de negcio, o Hibernate
no suporta correspondncias diretas com este tipo de procedure. Nestes casos,
devemos utilizar o bom e velho java.sql.CallableStatement da API JDBC (veja
uma introduo rpida no quadro CallableStatements bsico").
No exemplo da Listagem 6, acionamos uma procedure hipottica que processa
todos os pedidos de transferncia de correntistas para uma determinada agncia
de destino. Aps a execuo, muitos registros de correntistas tero seus nmeros
de agncia modificados no banco de dados.
importante entender que no estamos modificando dados atravs do Hibernate,
mas sim diretamente nas tabelas do banco de dados. Ento fundamental
realizar um flush() na sesso antes de executar o CallableStatement. Isso
garante que a procedure de negcio atue com a verso mais recente dos dados
de correntistas.
Estamos considerando que a procedure de negcio deve ser executada dentro da
mesma transao de banco de dados utilizada pela sesso do Hibernate. Por isso
tomamos emprestada a java.sql.Connection que acompanha nosso objeto
Session para poder criar o CallableStatement.
Por ltimo, devemos estar cientes que as modificaes realizadas diretamente no
banco de dados no so percebidas pelos caches de Session e de
SessionFactory do Hibernate, que passam a manter uma verso ultrapassada
dos dados dos correntistas.
Estes caches devem ser limpos atravs dos mtodos clear() e evictClass(). (
necessrio saber quais so as tabelas afetadas pela procedure de negcio, e
remover do cache de

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

20 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

SessionFactory todos os dados mapeados para estas tabelas.)


Quando estas precaues no so adotadas, a utilizao direta de
CallableStatements (ou de qualquer outra instruo SQL) em combinao com
o Hibernate pode levar a problemas de inconsistncia de dados. uma "bombarelgio" que pode passar despercebida e causar estragos no ambiente de
produo.

Listagem 6. Acionamento de Stored Procedure de Negcio integrado ao


funcionamento Hibernate

package jm.sp.hib.teste;
import java.sql.*;
import java.util.List;
import jm.sp.hib.model.Correntista;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;

public class ExemploProcedureNegocio {


public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
SessionFactory sf = cfg.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
try {
query q = session.getNamedQuery("sp.recupera.correntistas");
q.setlnteger(0. 400); // agencia
q.setString(1. "%Santos%"); // trecho do nome
List listaCorrentistas = q.list(); // Coleo de Correntistas

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

21 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

for(int i = 0; i < listaCorrentistas.size(); i++) {


Correntista c = (Correntista) listaCorrentistas.get(i);
// manipula coleo de correntistas {
}
session.flush();

Connection conn = session.connection();


CallableStatement call = conn.prepareCall("{ call
transferencia_agencia(?) }");
call.setShort(1, (short) 405);
call.execute();
session.clear(); // limpa cache local
sf.evict(Correntista.class); // limpa cache global, se habilitado
// mais operacoes de persistencia ...
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
} finally {
session.close();
sf.close();
}
}

Concluses
Para o programador Java que encontrou no Hibernate um aliado poderoso para o
desenvolvimento da camada de persistncia, vale a pena saber conviver bem com
as stored procedures, pois estas fazem parte de muitas solues corporativas.
Abordamos neste artigo as frmulas de mapeamento do Hibernate para as stored
procedures, e discutimos os diferentes papis das stored procedures e os

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

22 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

mecanismos de cache e de automatic dirty-checking do Hibernate. O


entendimento desses conceitos permite realizar de maneira correta e otimizada a
integrao de stored procedures com as camadas de persistncia desenvolvidas
com o Hibernate.

Para saber mais


Persistncia Turbinada. Edio 25
Conceitos e exemplos sobre cachs de primeiro e segundo nveis

Persistncia com Hibernate. Edio 28


Primeiros passos com o Hibernate,e criao de uma aplicao completa.

Hibernate na Web. Edio 33


Utilizao do framework Hibernate em aplicaes web e melhores prticas.

Links
hibernate.org ,
Comunidade Hibernate

hibernate.org/hib _docs/v3/reference/en/html
/querysql.html#sq_query
Documentao de referncia sobre stored procedures com Hibernate 3

java.sun.com/j2sell.3/docs/guide/jdbd/getstart/callablestatement.html
Guia sobre CallableStatements do JDBC

oreillynet.com/lpt/a/3136
Manipulao avanada de cursores com Oracle em PL/SQL

Regras de negcio em Triggers

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

23 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

Os triggers so rotinas desenvolvidas e, linguagem procedural de banco de dados


e so disparados quando acontecem operaes de modificao (insert, update,
delete). So como listeners, ou interceptadores, que capturam comandos SQL
executados em determinadas tabelas e realizam operaes adicionais antes ou
depois das instrues SQL originais.
Triggers constituem uma alternativa interessante s stored procedures, pois
garantem as mesmas regras de negcio para qualquer aplicativo cliente. Os
aplicativos clientes podem modificar as tabelas atravs de instrues SQL
comuns, de forma transparente, se a necessidade de conhecer stored prodecures
disponveis, com seus parametros de entrada e de sada.
No entanto, a natureza dos triggers pode torn-los traioeiros quando seu
banco de dados evolui em complexidade. Como o triggers interferem nas
operaes de modificao, muito fcil perder de vista as conseqncias de uma
instruo SQL. Por exemplo, um simples update em uma tabela pode disparar
uma triggers que produz um insert em uma segunda tabela, que por sua vez
dispara triggers que modificam outras tabelas e assim por diante. E ainda que
todos os triggers estejam bem documentados e rastreados, uma mudana nas
regras de negcio acarreta um esforo grande de manuteno e de testes.

Alternativas Java
Para resolver problemas de desempenho sem recorrer as stored procedures,
podemos utilizar os bancos de dados Java que oferecem um modo de
funcionamento "embutido", ou "in-process", como o HSQLDB e o Apache Derby.
Neste modo de operao, o gerenciador de banco de dados funciona na mesma
JVM que a aplicao (em um servidor de aplicaes, por exemplo); portanto o
driver JDBC no acessa a camada de rede. E ainda nos beneficiamos das
otimizaes em runtime de bytecode de uma nica JVM.
A desvantagem que o modo "embutido" impede que outras aplicaes que no
esto na mesma JVM tenham acesso aos dados. Alm disso, os bancos de dados
Java no tem tradio de manipular grandes volumes de dados (o que no

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

24 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

significa que no tenham capacidade para isso). Isso s vezes gera desconfiana
na hora de adot-los para solues crticas. O Java tambm oferece alternativas
poderosas para substituir as stored procedures quando h a necessidade de criar
uma camada de regras de negcio. Os EJBs (Enterprise JavaBeans) so ideais
para criar uma camada de regras de negcio distribuda, robusta, segura e
portvel. Clientes no-Java podem acessar dois tipos de EJBs:os Session Beans
podem ser acessados atravs de CORBA ou de Web Services. Os Message-Driven
Beans podem se comunicar com aplicaes no-Java atravs de filas e tpicos de
mensagens assncronas.
Desde a verso 2.x, o Hibernate suporta integrao com solues baseadas em
EJBs. E a partir da verso 3.1 o Hibernate oferece compatibilidade total com a
especificao EJB 3.0 (atravs de pacotes adicionais), sendo capaz de atuar como
um Entity Manager em containers Java
EE. Inclusive, o Hibernate o Entity Manager default do JBoss 4.0.4.

Caches do Hibernate
O Hibernate suporta o modelo de dois nveis de cache de persistncia, com um
cache local e um cache global. Este modelo foi amplamente discutido (sem
dependncia do Hoibernate) no artigo Persistncia Turbinada da Edio 25 da
Java Magazine. Vamos rever esse modelo aqui, contextualizando com o
Hibernate.
O cache local, ou de primeiro nvel, gerenciado pela Session do Hibernate
por isso comumente chamado de cache de Session. Ele mantm os objetos
persistentes manipulados, atravs das interfaces Session, Query e Criteria.
um cache individual de um cliente da camada de persistncia, que mantm a
verso dos objetos modificados por este cliente. Dentro de uma sesso do
Hibernate, qualquer operao realizada pelas APIs de consulta retorna os objetos
armazenados neste cache local. Quando um objeto no existe no cache de
sesso, o Hibernate utiliza informaes do banco de dados para criar uma nova
instncia que primeiramente vinculada ao cache local e finalmente includa nos

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

25 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

resultados da operao de consulta.


Quando executamos flush() ou commit(), entra em ao o automatic dirty
checking que copia os dados modificados (dirty) do cache de sesso para o banco
de dados. Este cache pode ser limpo atravs das operaes clear() e evict() de
Session.
O cache global ou de segundo nvel opcional, podendo ser habilitado atravs da
coinfigurao. Esse cache uma rea de compartilhamento de dados para as
sesses individuais obtidas a partir de uma mesma SessionFactory por isso
tambm chamado de cache de SessionFactory. Quando um cache local no
dispe de um objeto requisitado, o cache global consultado (se estiver
habilitado). Quando encontramos os dados no cache global, estes so copiados
para uma verso no cache local, evitando o acesso ao banco de dados, quando os
dados no so encontrados neste segundo cache, o banco de dados consultado
e os dois cachs so atualizados. Quando uma Session efetua uma operao
commit(), os dados de seu cache local so copiados para o cache global. A
Figura Q1 ilustra os dois nveis de cache.

Figura Q1. Nveis de cache do Hibernate.

CallabeStattement bsico

A interface java.sql.CallableStatement da API JDBC permite que aplicaes

25/08/2016 16:14

Artigo Java Magazine 40 - Hibernate e Stored Procedures

26 de 26

http://www.devmedia.com.br/articles/viewcomp_forprint.asp?comp=10222

Java interajam com stored procedures de bancos de dados. uma sub-interface


de java.sql.PreparedStatement e por isso tambm orientada a parmetros,
representados como sinais de interrogao nas instrues SQL. Alm de
parmetros de entrada, um CallableStatement permite o registro de
parmetros de sada (ou de retorno) da stored procedure.
Acompanhe no exemplo a seguir a invocao em JDBC puro de uma stored
procedure chamada somar que aceita dois parmetros de entrada e retorna um
resultado no terceiro parmetro:

Connection conn= DriverManager.getConnection{url, user, password);// conexo


JDBC
CallableStatement callable= conn.prepareCall("{call somar(?,?,?)}");
//inicializao
callable.setDouble(1,45.16d); //1. parmetro de entrada
callable.setDouble(2,77.18d); // 2. parmetro de entrada
callable.registerOutParameter(3, java.sql.Types.DOUBLE); //registro do
parmetro de sada
callable.execute(); // execuo no banco de dados
double resultado= callable.getDouble(3); //recuperao do retorno
callable.close();conn.close(); //concluso

por Renato Bellia


Expert em Java e programao Web

25/08/2016 16:14