13 de agosto de 2007

Hibernate


Eae galera.....

Vou começar com um breve tutorial de Hibernate:

Primeiramente estarei explicando alguns conceitos que estão relacionados com frameworks de persistência:

Um framework de persistência deve prover algumas funcionalidades e serviços para ser considerável a utilização do mesmo, citarei alguns seviços e funcionalidades referente a framework de persistência, em nosso exemplo do Hibernate.

· Controle transacional: o framework deve permitir rollback quando ocorrer algum erro e commit quando o objeto for persistido com sucesso.
· Identificadores de objeto: cada objeto de ter um identificador único para ser relacionado com o registro correspondente. Um OID (Object Identifier) garante que o objeto não se duplicará.
· Mapeamento O-R: se não utilizar um banco de dados orientado a objetos deve existir um mapeamento de objeto relacional entre a classe e a tabela do banco de dados isso é um dos requisitos principais de um framework de persistência de objetos é responsável por transformar uma representação de dados não orientada a objetos em um objeto e por armazenar um objeto persistente no seu mecanismo de persistência como um banco de dados, por exemplo.
· Cache: com o uso do cache o objeto é colocado em uma memória local para obter um maior desempenho, quando for necessário o uso desse objeto basta apenas buscá-lo na memória local que ele foi colocado agilizando todo o processo.
· Consultas sob demanda: os objetos são carregados apenas quando necessário evitando que registros sejam recuperados, todos de uma vez só. Com isso reduz a carga de informações na rede, se sua aplicação for utilizada através de internet este recurso garante um melhor desempenho.
· Proxy: é um objeto proxy de forma que o usuário e o serviço de persistência conseguem identificar. Assim quando um objeto for carregado apenas as informações definidas pelo objeto proxy serão recuperadas.
· Queries: utilizado para consultas mais complexas, isto pode ser feito através de OQL (Object Query Language) que é uma linguagem de consulta a banco de dados orientados a objetos ou também embutindo código SQL (Structure Query Language) na aplicação, pois isto não é muito recomendado porque acopla a estrutura do banco de dados com a sua aplicação.
. Portabilidade: um framework de persistência deve ser compatível com vários tipos de mecanismos de persistência de dados e também disponibilizar diversas maneiras de conexão, sendo isso muito importante porque quando for necessário trocar de mecanismo de persistência de dados não é necessário mudar toda sua aplicação.


Então o que é Hibernate ? Quais as vantagens de utilizar ? Quais desvantagens ?

Hibernate é um framework de persistência que permite a utilização de banco de dados relacional, porém, trabalhando com objetos, falar isso apenas é muito pouco
para o que o Hibernate pode fazer...
Uma das vantagens de utilizá-lo é que o desenvolvimento de aplicação se torna mais rápido, por não ter que escrever códigos e mais códigos SQL da vida... A idéia do
hibernate é encapsular todo o código SQL Jdbc por tráz de sua implementação, ficando transparente para o desenvolvedor.
Uma das desvantagens do hibernate é que para criar algumas queries bem complexas deve-se perder um tempo maior estudando as Criterias da vida!!!! São um pouco
complexas...
Outra desvantagen que eu considero é colocar milhões de jar's em sua aplicação, porém uma vez configurado não é preciso mexer novamente.


Exemplo:

Tudo isso:
INSERT INTO agendaadmissao (codigoagenda, nomecandidato, matriculacoordenador, codigocurso, data, status)
VALUES("1", "João da Silva Dias", "p100", "2", "2007-06-28 19:40:00", "P");

por isso:
session.save(objeto); // uau em uma linha!!!!

O hibernate permite ainda ir mais além, com apenas essa linha citada acima ele salva também todos os relacionamentos, para isso basta apenas configurar
uma propriedade chamada de Cascade, temos alguns tipos de cascade como:
ALL = persiste o objeto pai mais todos os filhos, cuidado ao utilizar pois se você deletar um objeto pai e tiver com essa propriedade tudo vai pro espaço...
None = este é o default, as operações relacionadas ao objeto pai apenas sofrerão alguma mudança nele mesmo em mais ninguém.
Save Update = onde o objeto pai pode salvar ou atualizar os filhos.
Persist = Apenas para operações de save.
All delete orphan = a partir do objeto pai ele deleta os filhos.


O Hibernate possui algumas interfaces importantes que vale a pena ser descrito, então vamos lá:


1º Interface de sessão (Session): Sessão (Session) é a interface primária do Hibernate, é de peso leve e mais fácil de criar e destruir. O objeto Session, por ser leve, ajudará na sua aplicação porque há uma grande necessidade de criar e destruir objetos Session há quase todo instante. As sessões não são Threadsafe, ou seja, uma Sessão do Hibernate é algo entre conexão e transação. Pode ser um armazenamento ou coleção de objetos numa única unidade de trabalho, podendo ser chamada de gerente de persistência, que faz a interface com operações relacionadas com a persistência, armazenando e recuperando objetos.

2º Interface SessionFactory: a interface SessionFactory não é considerada peso leve, sendo compartilhada entre muitas threads. Para a SessionFactory há um único aplicativo, criado na inicialização. Se seu aplicativo for acessar bancos de dados múltiplos usando Hibernate, é necessário uma SessionFactory para cada banco de dados. Esta interface controla dados armazenados e que foram lidos em uma unidade de trabalho, podendo ser reutilizados em uma unidade futura. Isso se o mapeamento de classe especificar o armazenamento do segundo nível. Geralmente a SessionFactory armazena instruções SQL (Structured Query Language), e outros metadados que são executados em tempo de execução.

3º Interface de Configuração: Segundo Bauer, King (2005, p. 39), a interface de configuração vai ser a primeira a ser encontrada quando você usar o Hibernate. Essa interface é muito importante porque depois de configurada, o Hibernate vai criar o SessionFactory.

4º Interface de Transação: é uma API (Application Programming Interface) opcional do Hibernate uma transação permite controlar os limites das transações usando uma API consistente com isso tornam-se portáveis os aplicativos do Hibernate com ambientes diferentes de execução.

5º Consulta e critérios de interfaces: a interface de consulta e critério serve para executar consultas no banco de dados. As consultas são feitas “escritas” em SQL(Structured Query Language) de seu banco de dados, para ligar parâmetros de consultas e limitar o número de resultados devolvidos pela consulta.

Vamos para o que interessa, criar um exemplo simples:

Vamos supor que estamos desenvolvendo um cadastro de cliente, (por enquanto, sem relacionamento):

Temos então:

Tabelas:

DROP TABLE IF EXISTS `cliente`;
CREATE TABLE `cliente` (
`nome` varchar(30) default NULL,
`id_cliente` int(9) NOT NULL auto_increment,
PRIMARY KEY (`id_cliente`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Para cada tabela dessa temos um Objeto chamado de Objeto ORM (Mapeamento de Objeto Relacional), ou seja o mapeamento das suas classes.

Essa é uma classe simples JavaBean com método get e set, a partir desta classe que faremos o mapeamento:



/**
* @author alberto ribeiro
*/
public class Cliente {
private int id;
private String nome;
get's e set's
}

Para a criação da aplicação alguns jar's terão que ser incluidos no classpath do projeto:

Hibernate3.jar: core do Hibernate.
c3p0-0.8.4.5.jar: Pool de conexão básico para executar testes unitários.
cglib-full-2.0.2.jar: biblioteca geradora de código para criação de proxies para classes persitentes.
dom4j-1.4.jar: biblioteca XML para parse de arquivos de configuração e mapeamento.
ecache-0.9.jar: cachê puro em Java, cachê padrão do Hibernate.
jta.jar: Java Transaction API.
commons-loging-1.0.4.jar: base para o mapeamento de produtos objeto relacional
commons-collections-2.1.1: contém as listas como bag, array list entre outros tipos de listas.
ojdbc.jar: jar do fabricante do bando de dados

Abaixo o mapeamento ORM, da classe Cliente, chamaremos de ClienteORM.hbm.xml:




Neste mapeamento vale ressaltar algumas propridades:

class name = é o relacionamento da tabela com a classe, sendo que o atributo name deve conter o nome completo do objeto incluindo o pacote e o atributo table deve conter o nome da tabela.

table = nome da tabela referente a classe.

id = nome do campo id dentro da classe cliente

column = "id_cliente" = referente ao nome da coluna no banco de dados.

type = o tipo da propriedade no caso id_cliente é um int.

generator = referente ao esquema de geração de ID no banco de dados, o native indica que o banco se encarregará de gerar este número sequencial.

property = a propriedade da classe, exemplo: nome e seu tipo string.


Depois de ter as classes mapeadas em um arquivo xml, temos então que configurar o hibernate.cfg.xml que será responsável
por algumas propiedades importantes de configuração:



Vale ressaltar as seguintes propridades:

dialect = responsável pela geração das intruções SQL de acordo com cada Bando de Dados, ele representa a linguagem que será gerada as queries da aplicação para o banco.

connection.url = a url é específica ao banco de dados utilizado, na url passamos como parâmetros o IP da máquina ou o nome do servidor, porta e o nome da base de dados. Usuário e senha são do banco de dados

connection.driver_class = O nome do driver que estamos utilizando no caso MySQL.

connection.username = username no banco de dados.

connection.password = senha no banco de dados.

show_sql = se estiver marcado como true, todas as queries geradas serão impressas no console.

mapping resource = local onde estão os mapeamentos XML referente as classes.


Criaremos agora uma classe utilitária responsável por criar as famosas Session's do hibernate:


public class HibernateUtil {

private static SessionFactory sessionFactory;

private static Session session;

private static Logger logger = Logger.getLogger(HibernateUtil.class);

static {
sessionFactory = new Configuration().configure().buildSessionFactory();
// obs o arquivo hibernate.cfg.xml deve estar na pasta src, o hibernate procura ela la dentro
// caso queira ficar em outro lugar deve mudar aqui: new Configuration().configure("nome do pacote onde está o //arquivo").buildSessionFactory();


if (logger.isDebugEnabled()) {
logger.info("Criando a session factory");
}
}

public static Session getCurrentSession() {
if (session == null || !session.isOpen() || !session.isConnected()) {
session = ((SessionFactory) sessionFactory).openSession();
}
return session;
}

public static void closeSession() {
session.close();
}

}


Criando nosso DAO, mas antes uma breve explicação: DAO é um padrão de projetos que veio para separar a camada de modelos de dados referente a banco de dados dos modelos de objetos, caso o mecanismo de persistencia troque, modifica-se a camada DAO.
Dentro desse DAO ficará os métodos CRUD, ou seja, create, retrieve, update e delete.

ClienteDAO:

public class ClienteDAO{

public void save(Object object) throws AcessoBaseDeDadosException {
if (object == null) {
throw new AcessoBaseDeDadosException(
"O objeto à ser salvo está nulo.");
}

try {
HibernateUtil.getCurrentSession().save(object);
} catch (HibernateException e) {
throw new AcessoBaseDeDadosException("Erro persistindo o objeto: "
+ object.getClass().toString(), e);
} catch (Exception e) {
throw new AcessoBaseDeDadosException("Erro persistindo o objeto: "
+ object.getClass().toString(), e);
}
}
}

A estrutura do projeto ficou assim:

Persistencia
src
br/edu/persistencia/common/
Cliente.java
ClienteORM.hbm.xml
br/edu/persistencia/dao/
ClienteDAO.java
br/edu/persistencia/util/
HibernateUtil.java
hibernate.cfg.xml
lib
Todos os jar's citados acima.

Podemos agora fazer o teste:

public class Teste {

public static void main(String[] args) throws Exception {
ClienteDAO dao = new ClienteDAO();

Cliente cliente = new Cliente();
cliente.setNome("Alberto");

Session session = HibernateUtil.getCurrentSession(); // Pegando uma sessão, caso esteja em aberto ele apenas //retorna uma sessão corrente
Transaction tx = session.begintransaction(); // iniciando uma transação para poder inserir no banco de dados
dao.save(cliente); // chamando o método save da classe DAO
tx.commit(); // finalizando a transação.
session.close(); // fechando a sessão com o banco.
}
}

É isso ai então, depois testar, mas, acredito que esteja correto, qualquer dúvida mande!!!! Este foi o primeiro, não sei se está bom mas com o tempo isso melhora...


[]'s

7 comentários:

Bruno disse...

Quando citado como desvantagem o aprendizado de Criteria, creio que fosse pertinente lembrar a existência de HQL como alternativa.

Eduardo Bregaida disse...

Sim realmente HQL é uma alternativa, o primeiro impacto com Criteria tende a ser algo inovador, mas a curva de aprendizado é muito rápida.
No artigo de JavaServer Faces eu mostro as vantagens do HQL e do Critéria pois faço as consultas tbm usando JPA e para fãs de Criteria uma ótima noticia, JPA 2.0 virá com Critéria =)

Anônimo disse...

Um bom artigo, mas incompleto.

Eduardo Bregaida disse...

Pq incompleto? coloca aí a dúvida que respondemos... =)

Anônimo disse...

Tentei testar, mas não consegui encontrar referencia a "AcessoBaseDeDadosException"
o netbeans ficou apontando erro para esta classe

Anônimo disse...

Tentei testar, mas não consegui encontrar referencia a "AcessoBaseDeDadosException"
o netbeans ficou apontando erro para esta classe

Alberto Ribeiro disse...

Bom dia, então referente a esse erro que está dando é porque eu criei uma classe de Exception, então você pode criar uma sua ou usar uma existente, segue exemplo da minha:

public class AcessoBaseDeDadosException extends Exception {

public AcessoBaseDeDadosException() {
super();
}

public AcessoBaseDeDadosException(String msg) {
super(msg);
}

public AcessoBaseDeDadosException(Throwable e) {
super(e);
}

public AcessoBaseDeDadosException(String msg, Throwable e) {
super(msg, e);
}

}

[]'s e feliz ano novo