Hibernate - Guia Rápido
O que é JDBC?
JDBC significa Java Database Connectivity. Ele fornece um conjunto de API Java para acessar os bancos de dados relacionais do programa Java. Essas APIs Java permitem que programas Java executem instruções SQL e interajam com qualquer banco de dados compatível com SQL.
JDBC fornece uma arquitetura flexível para escrever um aplicativo independente de banco de dados que pode ser executado em diferentes plataformas e interagir com diferentes DBMS sem qualquer modificação.
Prós e Contras do JDBC
Profissionais de JDBC | Contras do JDBC |
---|---|
Processamento SQL limpo e simples Bom desempenho com grande volume de dados Muito bom para pequenas aplicações Sintaxe simples tão fácil de aprender |
Complexo se for usado em grandes projetos Grande sobrecarga de programação Sem encapsulamento Difícil de implementar o conceito MVC A consulta é específica do DBMS |
Por que Mapeamento Relacional de Objeto (ORM)?
Quando trabalhamos com um sistema orientado a objetos, há uma incompatibilidade entre o modelo de objeto e o banco de dados relacional. Os RDBMSs representam dados em um formato tabular, enquanto as linguagens orientadas a objetos, como Java ou C #, os representam como um gráfico interconectado de objetos.
Considere a seguinte classe Java com construtores adequados e função pública associada -
public class Employee {
private int id;
private String first_name;
private String last_name;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.first_name = fname;
this.last_name = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return last_name;
}
public int getSalary() {
return salary;
}
}
Considere que os objetos acima devem ser armazenados e recuperados na seguinte tabela RDBMS -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Primeiro problema, e se precisarmos modificar o design de nosso banco de dados depois de desenvolver algumas páginas ou nosso aplicativo? Em segundo lugar, carregar e armazenar objetos em um banco de dados relacional nos expõe aos cinco problemas de incompatibilidade a seguir -
Sr. Não. | Incompatibilidade e descrição |
---|---|
1 | Granularity Às vezes, você terá um modelo de objeto, que possui mais classes do que o número de tabelas correspondentes no banco de dados. |
2 | Inheritance RDBMSs não definem nada semelhante a Herança, que é um paradigma natural em linguagens de programação orientadas a objetos. |
3 | Identity Um RDBMS define exatamente uma noção de 'igualdade': a chave primária. Java, entretanto, define a identidade do objeto (a == b) e a igualdade do objeto (a.equals (b)). |
4 | Associations Linguagens orientadas a objetos representam associações usando referências de objetos, enquanto um RDBMS representa uma associação como uma coluna de chave estrangeira. |
5 | Navigation As maneiras de acessar objetos em Java e em RDBMS são fundamentalmente diferentes. |
o Object-Relacional Mapping (ORM) é a solução para lidar com todas as incompatibilidades de impedância acima.
O que é ORM?
ORM significa Object-Relacional Mapping (ORM) é uma técnica de programação para converter dados entre bancos de dados relacionais e linguagens de programação orientadas a objetos, como Java, C #, etc.
Um sistema ORM tem as seguintes vantagens sobre JDBC simples -
Sr. Não. | Vantagens |
---|---|
1 | Vamos acessar objetos de código de negócios em vez de tabelas de banco de dados. |
2 | Oculta detalhes de consultas SQL da lógica OO. |
3 | Baseado em JDBC 'sob o capô'. |
4 | Não há necessidade de lidar com a implementação do banco de dados. |
5 | Entidades baseadas em conceitos de negócios em vez de estrutura de banco de dados. |
6 | Gerenciamento de transações e geração automática de chaves. |
7 | Desenvolvimento rápido de aplicação. |
Uma solução ORM consiste nas seguintes quatro entidades -
Sr. Não. | Soluções |
---|---|
1 | Uma API para realizar operações CRUD básicas em objetos de classes persistentes. |
2 | Uma linguagem ou API para especificar consultas que se referem a classes e propriedades de classes. |
3 | Um recurso configurável para especificar metadados de mapeamento. |
4 | Uma técnica para interagir com objetos transacionais para realizar verificação suja, busca lenta de associação e outras funções de otimização. |
Frameworks Java ORM
Existem várias estruturas persistentes e opções de ORM em Java. Uma estrutura persistente é um serviço ORM que armazena e recupera objetos em um banco de dados relacional.
- Enterprise JavaBeans Entity Beans
- Objetos de Dados Java
- Castor
- TopLink
- Spring DAO
- Hibernate
- E muitos mais
Hibernate é um Object-Relacional Msolução apping (ORM) para JAVA. É uma estrutura persistente de código aberto criada por Gavin King em 2001. É um serviço de Consulta e Persistência Relacional de Objeto poderoso e de alto desempenho para qualquer aplicativo Java.
O Hibernate mapeia classes Java para tabelas de banco de dados e de tipos de dados Java para tipos de dados SQL e libera o desenvolvedor de 95% das tarefas de programação relacionadas à persistência de dados comuns.
O Hibernate fica entre os objetos Java tradicionais e o servidor de banco de dados para lidar com todos os trabalhos de persistência desses objetos com base nos mecanismos e padrões O / R apropriados.
Vantagens do Hibernate
O Hibernate se encarrega de mapear classes Java para tabelas de banco de dados usando arquivos XML e sem escrever nenhuma linha de código.
Fornece APIs simples para armazenar e recuperar objetos Java diretamente de e para o banco de dados.
Se houver mudança no banco de dados ou em qualquer tabela, você precisará alterar apenas as propriedades do arquivo XML.
Abstrai os tipos de SQL desconhecidos e fornece uma maneira de contornar objetos Java familiares.
O Hibernate não requer um servidor de aplicativos para operar.
Manipula associações complexas de objetos de seu banco de dados.
Minimiza o acesso ao banco de dados com estratégias de busca inteligente.
Fornece consulta simples de dados.
Bancos de dados suportados
O Hibernate suporta quase todos os principais RDBMS. A seguir está uma lista de alguns dos motores de banco de dados suportados pelo Hibernate -
- HSQL Database Engine
- DB2/NT
- MySQL
- PostgreSQL
- FrontBase
- Oracle
- Banco de dados Microsoft SQL Server
- Sybase SQL Server
- Servidor Dinâmico Informix
Tecnologias Suportadas
O Hibernate suporta uma variedade de outras tecnologias, incluindo -
- XDoclet Spring
- J2EE
- Plug-ins Eclipse
- Maven
O Hibernate tem uma arquitetura em camadas que ajuda o usuário a operar sem ter que conhecer as APIs subjacentes. O Hibernate faz uso do banco de dados e dados de configuração para fornecer serviços de persistência (e objetos persistentes) para a aplicação.
A seguir está uma visão de alto nível da Arquitetura do Aplicativo Hibernate.
A seguir está uma visão detalhada da Arquitetura de Aplicativos Hibernate com suas classes principais.
O Hibernate usa várias APIs Java existentes, como JDBC, Java Transaction API (JTA) e Java Naming and Directory Interface (JNDI). JDBC fornece um nível rudimentar de abstração de funcionalidade comum a bancos de dados relacionais, permitindo que quase qualquer banco de dados com um driver JDBC seja suportado pelo Hibernate. JNDI e JTA permitem que o Hibernate seja integrado aos servidores de aplicativos J2EE.
A seção a seguir fornece uma breve descrição de cada um dos objetos de classe envolvidos na Arquitetura do Aplicativo Hibernate.
Objeto de Configuração
O objeto Configuration é o primeiro objeto Hibernate que você cria em qualquer aplicativo Hibernate. Geralmente é criado apenas uma vez durante a inicialização do aplicativo. Ele representa uma configuração ou arquivo de propriedades requerido pelo Hibernate.
O objeto de configuração fornece dois componentes principais -
Database Connection- Isso é tratado por um ou mais arquivos de configuração suportados pelo Hibernate. Esses arquivos sãohibernate.properties e hibernate.cfg.xml.
Class Mapping Setup - Este componente cria a conexão entre as classes Java e as tabelas do banco de dados.
Objeto SessionFactory
O objeto de configuração é usado para criar um objeto SessionFactory que por sua vez configura o Hibernate para a aplicação usando o arquivo de configuração fornecido e permite que um objeto de Sessão seja instanciado. A SessionFactory é um objeto thread-safe e usado por todas as threads de um aplicativo.
A SessionFactory é um objeto pesado; geralmente é criado durante a inicialização do aplicativo e mantido para uso posterior. Você precisaria de um objeto SessionFactory por banco de dados usando um arquivo de configuração separado. Portanto, se você estiver usando vários bancos de dados, terá que criar vários objetos SessionFactory.
Objeto de Sessão
Uma sessão é usada para obter uma conexão física com um banco de dados. O objeto Session é leve e projetado para ser instanciado toda vez que uma interação for necessária com o banco de dados. Objetos persistentes são salvos e recuperados por meio de um objeto de Sessão.
Os objetos de sessão não devem ser mantidos abertos por muito tempo porque eles geralmente não são seguros para thread e devem ser criados e destruídos conforme necessário.
Objeto de transação
Uma transação representa uma unidade de trabalho com o banco de dados e a maior parte do RDBMS suporta a funcionalidade de transação. As transações no Hibernate são tratadas por um gerenciador de transações e transações subjacentes (de JDBC ou JTA).
Este é um objeto opcional e os aplicativos do Hibernate podem escolher não usar esta interface, em vez de gerenciar as transações em seu próprio código de aplicativo.
Objeto de Consulta
Os objetos de consulta usam a string SQL ou Hibernate Query Language (HQL) para recuperar dados do banco de dados e criar objetos. Uma instância Query é usada para vincular parâmetros de consulta, limitar o número de resultados retornados pela consulta e, finalmente, executar a consulta.
Objeto de Critérios
Objetos de critérios são usados para criar e executar consultas de critérios orientados a objetos para recuperar objetos.
Este capítulo explica como instalar o Hibernate e outros pacotes associados para preparar um ambiente para os aplicativos Hibernate. Trabalharemos com o banco de dados MySQL para experimentar exemplos do Hibernate, portanto, certifique-se de já ter uma configuração para o banco de dados MySQL. Para obter mais detalhes sobre o MySQL, você pode verificar nosso Tutorial do MySQL .
Baixando Hibernate
Presume-se que você já tenha a versão mais recente do Java instalada em seu sistema. A seguir estão os passos simples para baixar e instalar o Hibernate em seu sistema -
Escolha se deseja instalar o Hibernate no Windows ou Unix e então prossiga para a próxima etapa para baixar o arquivo .zip para Windows e o arquivo .tz para Unix.
Baixe a última versão do Hibernate de http://www.hibernate.org/downloads.
No momento de escrever este tutorial, eu baixei hibernate-distribution3.6.4.Final e quando você descompacta o arquivo baixado, ele lhe dará a estrutura de diretório conforme mostrado na imagem a seguir
Instalando o Hibernate
Depois de baixar e descompactar a versão mais recente do arquivo de instalação do Hibernate, você precisa seguir duas etapas simples. Certifique-se de definir sua variável CLASSPATH corretamente, caso contrário, você terá problemas ao compilar seu aplicativo.
Agora, copie todos os arquivos de biblioteca de /lib em seu CLASSPATH e altere sua variável de caminho de classe para incluir todos os JARs -
Finalmente, copie hibernate3.jararquivo em seu CLASSPATH. Este arquivo está no diretório raiz da instalação e é o JAR principal que o Hibernate precisa para fazer seu trabalho.
Pré-requisitos de Hibernate
A seguir está a lista de pacotes / bibliotecas requeridos pelo Hibernate e você deve instalá-los antes de iniciar o Hibernate. Para instalar esses pacotes, você terá que copiar os arquivos de biblioteca do/lib em seu CLASSPATH e altere sua variável CLASSPATH de acordo.
Sr. Não. | Pacotes / Bibliotecas |
---|---|
1 | dom4j Análise XML www.dom4j.org/ |
2 | Xalan Processador XSLT https://xml.apache.org/xalan-j/ |
3 | Xerces O Xerces Java Parser https://xml.apache.org/xerces-j/ |
4 | cglib Mudanças apropriadas nas classes Java em tempo de execução http://cglib.sourceforge.net/ |
5 | log4j Logging Faremwork https://logging.apache.org/log4j |
6 | Commons Registro, e-mail etc. https://jakarta.apache.org/commons |
7 | SLF4J Logging Facade para Java https://www.slf4j.org |
O Hibernate requer saber com antecedência - onde encontrar as informações de mapeamento que definem como suas classes Java se relacionam com as tabelas do banco de dados. O Hibernate também requer um conjunto de definições de configuração relacionadas ao banco de dados e outros parâmetros relacionados. Todas essas informações são geralmente fornecidas como um arquivo de propriedades Java padrão chamadohibernate.properties, ou como um arquivo XML chamado hibernate.cfg.xml.
Vou considerar o arquivo formatado em XML hibernate.cfg.xmlpara especificar as propriedades necessárias do Hibernate em meus exemplos. A maioria das propriedades assume seus valores padrão e não é necessário especificá-los no arquivo de propriedades, a menos que seja realmente necessário. Este arquivo é mantido no diretório raiz do classpath do seu aplicativo.
Propriedades de hibernação
A seguir está a lista de propriedades importantes, você deverá configurar para bancos de dados em uma situação autônoma -
Sr. Não. | Propriedades e descrição |
---|---|
1 | hibernate.dialect Esta propriedade faz com que o Hibernate gere o SQL apropriado para o banco de dados escolhido. |
2 | hibernate.connection.driver_class A classe do driver JDBC. |
3 | hibernate.connection.url O URL JDBC para a instância do banco de dados. |
4 | hibernate.connection.username O nome de usuário do banco de dados. |
5 | hibernate.connection.password A senha do banco de dados. |
6 | hibernate.connection.pool_size Limita o número de conexões aguardando no pool de conexão do banco de dados Hibernate. |
7 | hibernate.connection.autocommit Permite que o modo autocommit seja usado para a conexão JDBC. |
Se você estiver usando um banco de dados junto com um servidor de aplicativos e JNDI, será necessário configurar as seguintes propriedades -
Sr. Não. | Propriedades e descrição |
---|---|
1 | hibernate.connection.datasource O nome JNDI definido no contexto do servidor de aplicativos, que você está usando para o aplicativo. |
2 | hibernate.jndi.class A classe InitialContext para JNDI. |
3 | hibernate.jndi.<JNDIpropertyname> Transmite qualquer propriedade JNDI de sua preferência para o JNDI InitialContext . |
4 | hibernate.jndi.url Fornece a URL para JNDI. |
5 | hibernate.connection.username O nome de usuário do banco de dados. |
6 | hibernate.connection.password A senha do banco de dados. |
Hibernar com banco de dados MySQL
O MySQL é um dos sistemas de banco de dados de código aberto mais populares disponíveis atualmente. Vamos criarhibernate.cfg.xmlarquivo de configuração e coloque-o na raiz do classpath de seu aplicativo. Você terá que se certificar de que você temtestdb banco de dados disponível em seu banco de dados MySQL e você tem um usuário test disponível para acessar o banco de dados.
O arquivo de configuração XML deve estar em conformidade com o Hibernate 3 Configuration DTD, que está disponível em http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name = "hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume test is the database name -->
<property name = "hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name = "hibernate.connection.username">
root
</property>
<property name = "hibernate.connection.password">
root123
</property>
<!-- List of XML mapping files -->
<mapping resource = "Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
O arquivo de configuração acima inclui <mapping> tags, que estão relacionadas ao arquivo de mapeamento de hibernação e veremos no próximo capítulo o que exatamente é um arquivo de mapeamento de hibernação e como e por que o usamos?
A seguir está a lista de vários tipos de propriedade de dialeto de bancos de dados importantes -
Sr. Não. | Propriedade de banco de dados e dialeto |
---|---|
1 | DB2 org.hibernate.dialect.DB2Dialect |
2 | HSQLDB org.hibernate.dialect.HSQLDialect |
3 | HypersonicSQL org.hibernate.dialect.HSQLDialect |
4 | Informix org.hibernate.dialect.InformixDialect |
5 | Ingres org.hibernate.dialect.IngresDialect |
6 | Interbase org.hibernate.dialect.InterbaseDialect |
7 | Microsoft SQL Server 2000 org.hibernate.dialect.SQLServerDialect |
8 | Microsoft SQL Server 2005 org.hibernate.dialect.SQLServer2005Dialect |
9 | Microsoft SQL Server 2008 org.hibernate.dialect.SQLServer2008Dialect |
10 | MySQL org.hibernate.dialect.MySQLDialect |
11 | Oracle (any version) org.hibernate.dialect.OracleDialect |
12 | Oracle 11g org.hibernate.dialect.Oracle10gDialect |
13 | Oracle 10g org.hibernate.dialect.Oracle10gDialect |
14 | Oracle 9i org.hibernate.dialect.Oracle9iDialect |
15 | PostgreSQL org.hibernate.dialect.PostgreSQLDialect |
16 | Progress org.hibernate.dialect.ProgressDialect |
17 | SAP DB org.hibernate.dialect.SAPDBDialect |
18 | Sybase org.hibernate.dialect.SybaseDialect |
19 | Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect |
Uma sessão é usada para obter uma conexão física com um banco de dados. O objeto Session é leve e projetado para ser instanciado toda vez que uma interação for necessária com o banco de dados. Objetos persistentes são salvos e recuperados por meio de um objeto de Sessão.
Os objetos de sessão não devem ser mantidos abertos por muito tempo porque eles geralmente não são seguros para thread e devem ser criados e destruídos conforme necessário. A principal função da Sessão é oferecer, criar, ler e excluir operações para instâncias de classes de entidade mapeadas.
As instâncias podem existir em um dos três estados a seguir em um determinado momento -
transient - Uma nova instância de uma classe persistente, que não está associada a uma Sessão e não tem representação no banco de dados e nenhum valor de identificador é considerada transitória pelo Hibernate.
persistent- Você pode tornar uma instância transitória persistente, associando-a a uma Sessão. Uma instância persistente possui uma representação no banco de dados, um valor identificador e está associada a uma Sessão.
detached - Assim que fecharmos a Sessão do Hibernate, a instância persistente se tornará uma instância separada.
Uma instância de Session é serializável se suas classes persistentes são serializáveis. Uma transação típica deve usar o seguinte idioma -
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
Se a Sessão lançar uma exceção, a transação deve ser revertida e a sessão deve ser descartada.
Métodos de interface de sessão
Existem vários métodos fornecidos pelo Sessioninterface, mas vou listar alguns métodos importantes, que usaremos neste tutorial. Você pode verificar a documentação do Hibernate para uma lista completa de métodos associados comSession e SessionFactory.
Sr. Não. | Métodos e descrição da sessão |
---|---|
1 | Transaction beginTransaction() Comece uma unidade de trabalho e retorne o objeto de transação associado. |
2 | void cancelQuery() Cancele a execução da consulta atual. |
3 | void clear() Limpe completamente a sessão. |
4 | Connection close() Encerre a sessão liberando a conexão JDBC e limpando. |
5 | Criteria createCriteria(Class persistentClass) Crie uma nova instância de Criteria, para a classe de entidade fornecida, ou uma superclasse de uma classe de entidade. |
6 | Criteria createCriteria(String entityName) Crie uma nova instância de Criteria, para o nome de entidade fornecido. |
7 | Serializable getIdentifier(Object object) Retorne o valor do identificador da entidade fornecida como associado a esta sessão. |
8 | Query createFilter(Object collection, String queryString) Crie uma nova instância de Query para a coleção e string de filtro fornecidas. |
9 | Query createQuery(String queryString) Crie uma nova instância de Query para a string de consulta HQL fornecida. |
10 | SQLQuery createSQLQuery(String queryString) Crie uma nova instância de SQLQuery para a string de consulta SQL fornecida. |
11 | void delete(Object object) Remova uma instância persistente do armazenamento de dados. |
12 | void delete(String entityName, Object object) Remova uma instância persistente do armazenamento de dados. |
13 | Session get(String entityName, Serializable id) Retorna a instância persistente da entidade nomeada fornecida com o identificador fornecido, ou null se não houver tal instância persistente. |
14 | SessionFactory getSessionFactory() Obtenha a fábrica de sessão que criou esta sessão. |
15 | void refresh(Object object) Releia o estado de determinada instância do banco de dados subjacente. |
16 | Transaction getTransaction() Obtenha a instância Transaction associada a esta sessão. |
17 | boolean isConnected() Verifique se a sessão está conectada no momento. |
18 | boolean isDirty() Esta sessão contém alguma alteração que deve ser sincronizada com o banco de dados? |
19 | boolean isOpen() Verifique se a sessão ainda está aberta. |
20 | Serializable save(Object object) Persista a instância transitória fornecida, primeiro atribuindo um identificador gerado. |
21 | void saveOrUpdate(Object object) Salve (Objeto) ou atualize (Objeto) a instância fornecida. |
22 | void update(Object object) Atualize a instância persistente com o identificador da instância separada fornecida. |
23 | void update(String entityName, Object object) Atualize a instância persistente com o identificador da instância separada fornecida. |
Todo o conceito do Hibernate é pegar os valores dos atributos da classe Java e persisti-los em uma tabela de banco de dados. Um documento de mapeamento ajuda o Hibernate a determinar como extrair os valores das classes e mapeá-los com a tabela e campos associados.
As classes Java cujos objetos ou instâncias serão armazenados nas tabelas do banco de dados são chamadas de classes persistentes no Hibernate. O Hibernate funciona melhor se essas classes seguirem algumas regras simples, também conhecidas comoPlain Old Java Object (POJO) modelo de programação.
Existem as seguintes regras principais de classes persistentes, no entanto, nenhuma dessas regras são requisitos rígidos -
Todas as classes Java que serão persistidas precisam de um construtor padrão.
Todas as classes devem conter um ID para permitir fácil identificação de seus objetos dentro do Hibernate e no banco de dados. Esta propriedade mapeia para a coluna de chave primária de uma tabela de banco de dados.
Todos os atributos que serão persistidos devem ser declarados privados e ter getXXX e setXXX métodos definidos no estilo JavaBean.
Um recurso central do Hibernate, proxies, depende da classe persistente ser não final ou da implementação de uma interface que declara todos os métodos públicos.
Todas as classes que não estendem ou implementam algumas classes e interfaces especializadas exigidas pela estrutura EJB.
O nome POJO é usado para enfatizar que um determinado objeto é um objeto Java comum, não um objeto especial e, em particular, não é um Enterprise JavaBean.
Exemplo de POJO simples
Com base nas poucas regras mencionadas acima, podemos definir uma classe POJO da seguinte forma -
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Um mapeamento de objeto / relacional geralmente é definido em um documento XML. Este arquivo de mapeamento instrui o Hibernate - como mapear a classe ou classes definidas para as tabelas do banco de dados?
Embora muitos usuários do Hibernate optem por escrever o XML manualmente, existem várias ferramentas para gerar o documento de mapeamento. Esses incluemXDoclet, Middlegen e AndroMDA para os usuários avançados do Hibernate.
Vamos considerar nossa classe POJO definida anteriormente, cujos objetos persistirão na tabela definida na próxima seção.
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Haveria uma tabela correspondente a cada objeto que você deseja fornecer persistência. Considere que os objetos acima precisam ser armazenados e recuperados na seguinte tabela RDBMS -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Com base nas duas entidades acima, podemos definir o seguinte arquivo de mapeamento, que instrui o Hibernate como mapear a classe ou classes definidas para as tabelas do banco de dados.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Você deve salvar o documento de mapeamento em um arquivo com o formato <classname> .hbm.xml. Salvamos nosso documento de mapeamento no arquivo Employee.hbm.xml.
Vamos entender um pouco mais sobre os elementos de mapeamento usados no arquivo de mapeamento -
O documento de mapeamento é um documento XML com <hibernate-mapping> como o elemento raiz, que contém todos os <class> elementos
o <class>elementos são usados para definir mapeamentos específicos de classes Java para as tabelas do banco de dados. O nome da classe Java é especificado usando oname atributo do elemento de classe e do banco de dados table o nome é especificado usando o atributo da tabela.
o <meta> element é um elemento opcional e pode ser usado para criar a descrição da classe.
o <id>elemento mapeia o atributo de ID exclusivo na classe para a chave primária da tabela do banco de dados. oname atributo do elemento id refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
o <generator>O elemento dentro do elemento id é usado para gerar os valores da chave primária automaticamente. oclass atributo do elemento gerador é definido como native para deixar a hibernação pegar também identity, sequence, ou hilo algoritmo para criar a chave primária, dependendo dos recursos do banco de dados subjacente.
o <property>elemento é usado para mapear uma propriedade de classe Java para uma coluna na tabela de banco de dados. oname atributo do elemento refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
Existem outros atributos e elementos disponíveis, que serão usados em um documento de mapeamento e eu tentaria cobrir o máximo possível enquanto discuto outros tópicos relacionados ao Hibernate.
Quando você prepara um documento de mapeamento do Hibernate, descobre que mapeia os tipos de dados Java em tipos de dados RDBMS. otypesdeclarados e usados nos arquivos de mapeamento não são tipos de dados Java; eles também não são tipos de banco de dados SQL. Esses tipos são chamadosHibernate mapping types, que pode traduzir de Java para tipos de dados SQL e vice-versa.
Este capítulo lista todos os tipos básicos de mapeamento, data e hora, objetos grandes e vários outros.
Tipos primitivos
Tipo de mapeamento | Tipo Java | Tipo ANSI SQL |
---|---|---|
inteiro | int ou java.lang.Integer | INTEIRO |
grandes | long ou java.lang.Long | BIGINT |
baixo | short ou java.lang.Short | SMALLINT |
flutuador | float ou java.lang.Float | FLUTUADOR |
em dobro | double ou java.lang.Double | EM DOBRO |
big_decimal | java.math.BigDecimal | NUMÉRICO |
personagem | java.lang.String | CHAR (1) |
corda | java.lang.String | VARCHAR |
byte | byte ou java.lang.Byte | TINYINT |
boleano | boolean ou java.lang.Boolean | MORDEU |
sim não | boolean ou java.lang.Boolean | CHAR (1) ('S' ou 'N') |
verdadeiro falso | boolean ou java.lang.Boolean | CHAR (1) ('T' ou 'F') |
Tipos de data e hora
Tipo de mapeamento | Tipo Java | Tipo ANSI SQL |
---|---|---|
encontro | java.util.Date ou java.sql.Date | ENCONTRO |
Tempo | java.util.Date ou java.sql.Time | TEMPO |
timestamp | java.util.Date ou java.sql.Timestamp | TIMESTAMP |
calendário | java.util.Calendar | TIMESTAMP |
calendar_date | java.util.Calendar | ENCONTRO |
Tipos de objetos binários e grandes
Tipo de mapeamento | Tipo Java | Tipo ANSI SQL |
---|---|---|
binário | byte[] | VARBINÁRIO (ou BLOB) |
texto | java.lang.String | CLOB |
serializável | qualquer classe Java que implemente java.io.Serializable | VARBINÁRIO (ou BLOB) |
clob | java.sql.Clob | CLOB |
bolha | java.sql.Blob | BLOB |
Tipos relacionados a JDK
Tipo de mapeamento | Tipo Java | Tipo ANSI SQL |
---|---|---|
classe | java.lang.Class | VARCHAR |
localidade | java.util.Locale | VARCHAR |
fuso horário | java.util.TimeZone | VARCHAR |
moeda | java.util.Currency | VARCHAR |
Vamos agora dar um exemplo para entender como podemos usar o Hibernate para fornecer persistência Java em um aplicativo independente. Iremos percorrer as diferentes etapas envolvidas na criação de um aplicativo Java usando a tecnologia Hibernate.
Criar classes POJO
A primeira etapa na criação de um aplicativo é construir a classe ou classes Java POJO, dependendo do aplicativo que será mantido no banco de dados. Vamos considerar nossoEmployee aula com getXXX e setXXX métodos para torná-lo uma classe compatível com JavaBeans.
Um POJO (Plain Old Java Object) é um objeto Java que não estende ou implementa algumas classes e interfaces especializadas exigidas respectivamente pela estrutura EJB. Todos os objetos Java normais são POJO.
Quando você projeta uma classe para ser persistida pelo Hibernate, é importante fornecer código compatível com JavaBeans, bem como um atributo, que funcionaria como índice como id atributo na classe Employee.
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Criar tabelas de banco de dados
O segundo passo seria criar tabelas em seu banco de dados. Haveria uma tabela correspondente a cada objeto, você está disposto a fornecer persistência. Considere que os objetos acima precisam ser armazenados e recuperados na seguinte tabela RDBMS -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Criar arquivo de configuração de mapeamento
Este passo é criar um arquivo de mapeamento que instrui o Hibernate como mapear a classe ou classes definidas para as tabelas do banco de dados.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Você deve salvar o documento de mapeamento em um arquivo com o formato <classname> .hbm.xml. Salvamos nosso documento de mapeamento no arquivo Employee.hbm.xml. Vamos ver alguns detalhes sobre o documento de mapeamento -
O documento de mapeamento é um documento XML tendo <hibernate-mapping> como o elemento raiz que contém todos os elementos <class>.
o <class>elementos são usados para definir mapeamentos específicos de classes Java para as tabelas do banco de dados. O nome da classe Java é especificado usando oname atributo do elemento de classe e o nome da tabela do banco de dados é especificado usando o table atributo.
o <meta> element é um elemento opcional e pode ser usado para criar a descrição da classe.
o <id>elemento mapeia o atributo de ID exclusivo na classe para a chave primária da tabela do banco de dados. oname atributo do elemento id refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
o <generator>O elemento dentro do elemento id é usado para gerar os valores da chave primária automaticamente. oclass atributo do elemento gerador é definido como native para deixar a hibernação pegar também identity, sequence ou hilo algoritmo para criar a chave primária, dependendo dos recursos do banco de dados subjacente.
o <property>elemento é usado para mapear uma propriedade de classe Java para uma coluna na tabela de banco de dados. oname atributo do elemento refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
Existem outros atributos e elementos disponíveis, que serão usados em um documento de mapeamento e eu tentaria cobrir o máximo possível enquanto discuto outros tópicos relacionados ao Hibernate.
Criar classe de aplicativo
Por fim, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo. Usaremos este aplicativo para salvar alguns registros de funcionários e, em seguida, aplicaremos as operações CRUD a esses registros.
import java.util.List;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add few employee records in database */
Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
Integer empID3 = ME.addEmployee("John", "Paul", 10000);
/* List down all the employees */
ME.listEmployees();
/* Update employee's records */
ME.updateEmployee(empID1, 5000);
/* Delete an employee from the database */
ME.deleteEmployee(empID2);
/* List down new list of the employees */
ME.listEmployees();
}
/* Method to CREATE an employee in the database */
public Integer addEmployee(String fname, String lname, int salary){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to READ all the employees */
public void listEmployees( ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM Employee").list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to UPDATE salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to DELETE an employee from the records */
public void deleteEmployee(Integer EmployeeID){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado no capítulo de configuração.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado e os registros seriam criados na tabela EMPLOYEE.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
First Name: Zara Last Name: Ali Salary: 5000
First Name: John Last Name: Paul Salary: 10000
Se você verificar sua tabela EMPLOYEE, ela deve ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>
Até agora, vimos um mapeamento O / R muito básico usando o hibernate, mas existem três tópicos de mapeamento mais importantes, que precisamos aprender em detalhes.
Estes são -
- Mapeamento de coleções,
- Mapeamento de associações entre classes de entidade, e
- Mapeamentos de componentes.
Mapeamentos de coleções
Se uma entidade ou classe tem coleção de valores para uma variável particular, então podemos mapear esses valores usando qualquer uma das interfaces de coleção disponíveis em java. O Hibernate pode persistir instâncias dejava.util.Map, java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, e qualquer array de entidades ou valores persistentes.
Sr. Não. | Tipo de coleção e descrição de mapeamento |
---|---|
1 | java.util.Set Isso é mapeado com um elemento <set> e inicializado com java.util.HashSet |
2 | java.util.SortedSet Isso é mapeado com um elemento <set> e inicializado com java.util.TreeSet. osort atributo pode ser definido como um comparador ou ordenação natural. |
3 | java.util.List Isso é mapeado com um elemento <list> e inicializado com java.util.ArrayList |
4 | java.util.Collection Isso é mapeado com um elemento <bag> ou <ibag> e inicializado com java.util.ArrayList |
5 | java.util.Map Isso é mapeado com um elemento <map> e inicializado com java.util.HashMap |
6 | java.util.SortedMap Isso é mapeado com um elemento <map> e inicializado com java.util.TreeMap. osort atributo pode ser definido como um comparador ou ordenação natural. |
Arrays são suportados pelo Hibernate com <primitive-array> para tipos de valores primitivos Java e <array> para todo o resto. No entanto, eles raramente são usados, então não irei discuti-los neste tutorial.
Se você deseja mapear uma interface de coleção definida pelo usuário, que não é diretamente suportada pelo Hibernate, você precisa informar ao Hibernate sobre a semântica de suas coleções personalizadas, o que não é muito fácil e não recomendado para ser usado.
Mapeamentos de associação
O mapeamento de associações entre classes de entidade e os relacionamentos entre tabelas é a alma do ORM. A seguir estão as quatro maneiras pelas quais a cardinalidade da relação entre os objetos pode ser expressa. Um mapeamento de associação pode ser unidirecional ou bidirecional.
Sr. Não. | Tipo de mapeamento e descrição |
---|---|
1 | Muitos para Um Mapeando relacionamento muitos-para-um usando Hibernate |
2 | Um a um Mapeando relacionamento um-para-um usando Hibernate |
3 | Um para muitos Mapeando relacionamento um-para-muitos usando Hibernate |
4 | Muitos para muitos Mapeando relacionamento muitos-para-muitos usando Hibernate |
Mapeamentos de componentes
É muito possível que uma classe Entity possa ter uma referência a outra classe como uma variável de membro. Se a classe referida não tem seu próprio ciclo de vida e depende completamente do ciclo de vida da classe de entidade proprietária, então a classe referida, portanto, é chamada deComponent class.
O mapeamento de Coleções de Componentes também é possível de maneira semelhante, assim como o mapeamento de Coleções regulares com pequenas diferenças de configuração. Veremos esses dois mapeamentos em detalhes com exemplos.
Sr. Não. | Tipo de mapeamento e descrição |
---|---|
1 | Mapeamentos de componentes Mapeamento para uma classe tendo uma referência a outra classe como uma variável de membro. |
Até agora você viu como o Hibernate usa o arquivo de mapeamento XML para a transformação de dados de POJO em tabelas de banco de dados e vice-versa. As anotações do Hibernate são a forma mais recente de definir mapeamentos sem o uso de arquivo XML. Você pode usar anotações além ou como uma substituição dos metadados de mapeamento XML.
Hibernate Annotations é a maneira poderosa de fornecer os metadados para o mapeamento de Objetos e Tabelas Relacionais. Todos os metadados são agrupados no arquivo POJO java junto com o código, o que ajuda o usuário a entender a estrutura da tabela e o POJO simultaneamente durante o desenvolvimento.
Se você pretende tornar seu aplicativo portátil para outros aplicativos ORM compatíveis com EJB 3, deve usar anotações para representar as informações de mapeamento, mas, ainda assim, se desejar maior flexibilidade, deverá optar por mapeamentos baseados em XML.
Configuração do ambiente para anotação do Hibernate
Em primeiro lugar, você deve ter certeza de que está usando o JDK 5.0, caso contrário, será necessário atualizar seu JDK para o JDK 5.0 para aproveitar o suporte nativo para anotações.
Em segundo lugar, você precisará instalar o pacote de distribuição de anotações do Hibernate 3.x, disponível no sourceforge: ( Baixe o Hibernate Annotation ) e copiehibernate-annotations.jar, lib/hibernate-comons-annotations.jar e lib/ejb3-persistence.jar da distribuição de anotações do Hibernate para seu CLASSPATH.
Exemplo de classe anotada
Como mencionei acima, ao trabalhar com o Hibernate Annotation, todos os metadados são agrupados no arquivo POJO java junto com o código, isso ajuda o usuário a entender a estrutura da tabela e o POJO simultaneamente durante o desenvolvimento.
Considere que vamos usar a seguinte tabela EMPLOYEE para armazenar nossos objetos -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
A seguir está o mapeamento da classe Employee com anotações para mapear objetos com a tabela EMPLOYEE definida -
import javax.persistence.*;
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id @GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "salary")
private int salary;
public Employee() {}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
O Hibernate detecta que a anotação @Id está em um campo e assume que deve acessar as propriedades de um objeto diretamente através dos campos em tempo de execução. Se você colocou a anotação @Id no método getId (), habilitaria o acesso às propriedades por meio dos métodos getter e setter por padrão. Portanto, todas as outras anotações também são colocadas em campos ou métodos getter, seguindo a estratégia selecionada.
A seção a seguir explicará as anotações usadas na aula acima.
@Entity Annotation
As anotações padrão EJB 3 estão contidas no javax.persistencepacote, então nós importamos este pacote como a primeira etapa. Em segundo lugar, usamos o@Entity anotação para a classe Employee, que marca essa classe como um bean de entidade, portanto, deve ter um construtor sem argumento que seja visível com pelo menos um escopo protegido.
@Table Annotation
A anotação @Table permite que você especifique os detalhes da tabela que será usada para persistir a entidade no banco de dados.
A anotação @Table fornece quatro atributos, permitindo que você substitua o nome da tabela, seu catálogo e seu esquema, e impõe restrições exclusivas às colunas da tabela. Por enquanto, estamos usando apenas o nome da tabela, que é EMPLOYEE.
Anotações @Id e @GeneratedValue
Cada bean de entidade terá uma chave primária, que você anota na classe com o @Idanotação. A chave primária pode ser um único campo ou uma combinação de vários campos, dependendo da estrutura da tabela.
Por padrão, a anotação @Id determinará automaticamente a estratégia de geração de chave primária mais apropriada a ser usada, mas você pode substituir isso aplicando o @GeneratedValue anotação, que leva dois parâmetros strategy e generatorque não vou discutir aqui, vamos usar apenas a estratégia de geração de chave padrão. Permitir que o Hibernate determine qual tipo de gerador usar torna seu código portátil entre bancos de dados diferentes.
@Column Annotation
A anotação @Column é usada para especificar os detalhes da coluna para a qual um campo ou propriedade será mapeado. Você pode usar a anotação de coluna com os seguintes atributos mais comumente usados -
name atributo permite que o nome da coluna seja especificado explicitamente.
length atributo permite o tamanho da coluna usada para mapear um valor particularmente para um valor String.
nullable atributo permite que a coluna seja marcada como NOT NULL quando o esquema é gerado.
unique atributo permite que a coluna seja marcada como contendo apenas valores únicos.
Criar classe de aplicativo
Por fim, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo. Usaremos este aplicativo para salvar alguns registros de funcionários e, em seguida, aplicaremos as operações CRUD a esses registros.
import java.util.List;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new AnnotationConfiguration().
configure().
//addPackage("com.xyz") //add package if used.
addAnnotatedClass(Employee.class).
buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add few employee records in database */
Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
Integer empID3 = ME.addEmployee("John", "Paul", 10000);
/* List down all the employees */
ME.listEmployees();
/* Update employee's records */
ME.updateEmployee(empID1, 5000);
/* Delete an employee from the database */
ME.deleteEmployee(empID2);
/* List down new list of the employees */
ME.listEmployees();
}
/* Method to CREATE an employee in the database */
public Integer addEmployee(String fname, String lname, int salary){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee();
employee.setFirstName(fname);
employee.setLastName(lname);
employee.setSalary(salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to READ all the employees */
public void listEmployees( ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM Employee").list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to UPDATE salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to DELETE an employee from the records */
public void deleteEmployee(Integer EmployeeID){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Configuração de banco de dados
Agora vamos criar hibernate.cfg.xml arquivo de configuração para definir os parâmetros relacionados ao banco de dados.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name = "hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume students is the database name -->
<property name = "hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name = "hibernate.connection.username">
root
</property>
<property name = "hibernate.connection.password">
cohondob
</property>
</session-factory>
</hibernate-configuration>
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Exclua o arquivo de mapeamento Employee.hbm.xml do caminho.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado e os registros seriam criados na tabela EMPLOYEE.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
First Name: Zara Last Name: Ali Salary: 5000
First Name: John Last Name: Paul Salary: 10000
Se você verificar sua tabela EMPLOYEE, ela deve ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>
Hibernate Query Language (HQL) é uma linguagem de consulta orientada a objetos, semelhante ao SQL, mas em vez de operar em tabelas e colunas, HQL trabalha com objetos persistentes e suas propriedades. As consultas HQL são traduzidas pelo Hibernate em consultas SQL convencionais, que por sua vez executam ações no banco de dados.
Embora você possa usar instruções SQL diretamente com o Hibernate usando SQL nativo, eu recomendaria usar HQL sempre que possível para evitar aborrecimentos de portabilidade de banco de dados e para tirar proveito da geração de SQL do Hibernate e estratégias de cache.
Palavras-chave como SELECT, FROM e WHERE, etc., não diferenciam maiúsculas de minúsculas, mas propriedades como nomes de tabelas e colunas diferenciam maiúsculas de minúsculas em HQL.
Cláusula FROM
Você vai usar FROMcláusula se você deseja carregar objetos persistentes completos na memória. A seguir está a sintaxe simples de usar a cláusula FROM -
String hql = "FROM Employee";
Query query = session.createQuery(hql);
List results = query.list();
Se você precisar qualificar totalmente um nome de classe em HQL, basta especificar o pacote e o nome da classe da seguinte forma -
String hql = "FROM com.hibernatebook.criteria.Employee";
Query query = session.createQuery(hql);
List results = query.list();
Cláusula AS
o AScláusula pode ser usada para atribuir aliases às classes em suas consultas HQL, especialmente quando você tem as consultas longas. Por exemplo, nosso exemplo simples anterior seria o seguinte -
String hql = "FROM Employee AS E";
Query query = session.createQuery(hql);
List results = query.list();
o AS palavra-chave é opcional e você também pode especificar o alias diretamente após o nome da classe, como segue -
String hql = "FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
Cláusula SELECT
o SELECTA cláusula fornece mais controle sobre o conjunto de resultados do que a cláusula from. Se você deseja obter algumas propriedades de objetos em vez do objeto completo, use a cláusula SELECT. A seguir está a sintaxe simples de usar a cláusula SELECT para obter apenas o campo first_name do objeto Employee -
String hql = "SELECT E.firstName FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
É notável aqui que Employee.firstName é uma propriedade do objeto Employee em vez de um campo da tabela EMPLOYEE.
Cláusula WHERE
Se você deseja restringir os objetos específicos que são retornados do armazenamento, use a cláusula WHERE. A seguir está a sintaxe simples de usar a cláusula WHERE -
String hql = "FROM Employee E WHERE E.id = 10";
Query query = session.createQuery(hql);
List results = query.list();
Cláusula ORDER BY
Para classificar os resultados da sua consulta HQL, você precisará usar o ORDER BYcláusula. Você pode ordenar os resultados por qualquer propriedade nos objetos no conjunto de resultados ascendente (ASC) ou decrescente (DESC). A seguir está a sintaxe simples de usar a cláusula ORDER BY -
String hql = "FROM Employee E WHERE E.id > 10 ORDER BY E.salary DESC";
Query query = session.createQuery(hql);
List results = query.list();
Se você quiser classificar por mais de uma propriedade, basta adicionar as propriedades adicionais ao final da cláusula order by, separadas por vírgulas da seguinte forma -
String hql = "FROM Employee E WHERE E.id > 10 " +
"ORDER BY E.firstName DESC, E.salary DESC ";
Query query = session.createQuery(hql);
List results = query.list();
Cláusula GROUP BY
Esta cláusula permite que o Hibernate extraia informações do banco de dados e agrupe-as com base no valor de um atributo e, normalmente, use o resultado para incluir um valor agregado. A seguir está a sintaxe simples de usar a cláusula GROUP BY -
String hql = "SELECT SUM(E.salary), E.firtName FROM Employee E " +
"GROUP BY E.firstName";
Query query = session.createQuery(hql);
List results = query.list();
Usando parâmetros nomeados
O Hibernate suporta parâmetros nomeados em suas consultas HQL. Isso facilita a escrita de consultas HQL que aceitam entrada do usuário e você não precisa se defender contra ataques de injeção de SQL. A seguir está a sintaxe simples de usar parâmetros nomeados -
String hql = "FROM Employee E WHERE E.id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id",10);
List results = query.list();
Cláusula UPDATE
Atualizações em massa são novas no HQL com Hibernate 3, e o trabalho de exclusão é diferente no Hibernate 3 do que no Hibernate 2. A interface Query agora contém um método chamado executeUpdate () para executar instruções HQL UPDATE ou DELETE.
o UPDATEcláusula pode ser usada para atualizar uma ou mais propriedades de um ou mais objetos. A seguir está a sintaxe simples de usar a cláusula UPDATE -
String hql = "UPDATE Employee set salary = :salary " +
"WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("salary", 1000);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Cláusula DELETE
o DELETEcláusula pode ser usada para excluir um ou mais objetos. A seguir está a sintaxe simples de usar a cláusula DELETE -
String hql = "DELETE FROM Employee " +
"WHERE id = :employee_id";
Query query = session.createQuery(hql);
query.setParameter("employee_id", 10);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Cláusula INSERT
Suporta HQL INSERT INTOcláusula apenas onde os registros podem ser inseridos de um objeto para outro objeto. A seguir está a sintaxe simples de usar a cláusula INSERT INTO -
String hql = "INSERT INTO Employee(firstName, lastName, salary)" +
"SELECT firstName, lastName, salary FROM old_employee";
Query query = session.createQuery(hql);
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
Métodos Agregados
O HQL oferece suporte a uma variedade de métodos agregados, semelhantes ao SQL. Eles funcionam da mesma maneira em HQL e em SQL e a seguir está a lista das funções disponíveis -
Sr. Não. | Funções e descrição |
---|---|
1 | avg(property name) A média do valor de uma propriedade |
2 | count(property name or *) O número de vezes que uma propriedade ocorre nos resultados |
3 | max(property name) O valor máximo dos valores da propriedade |
4 | min(property name) O valor mínimo dos valores da propriedade |
5 | sum(property name) A soma total dos valores da propriedade |
o distinctpalavra-chave conta apenas os valores únicos no conjunto de linhas. A consulta a seguir retornará apenas uma contagem única -
String hql = "SELECT count(distinct E.firstName) FROM Employee E";
Query query = session.createQuery(hql);
List results = query.list();
Paginação usando consulta
Existem dois métodos da interface Query para paginação.
Sr. Não. | Método e Descrição |
---|---|
1 | Query setFirstResult(int startPosition) Este método usa um número inteiro que representa a primeira linha em seu conjunto de resultados, começando com a linha 0. |
2 | Query setMaxResults(int maxResult) Este método diz ao Hibernate para recuperar um número fixo maxResults de objetos. |
Usando os dois métodos acima juntos, podemos construir um componente de paginação em nosso aplicativo da web ou Swing. A seguir está o exemplo, que você pode estender para buscar 10 linhas por vez -
String hql = "FROM Employee";
Query query = session.createQuery(hql);
query.setFirstResult(1);
query.setMaxResults(10);
List results = query.list();
O Hibernate fornece maneiras alternativas de manipular objetos e, por sua vez, os dados disponíveis nas tabelas RDBMS. Um dos métodos é a API de critérios, que permite criar um objeto de consulta de critérios de maneira programática, onde você pode aplicar regras de filtragem e condições lógicas.
The Hibernate Session interface fornece createCriteria() método, que pode ser usado para criar um Criteria objeto que retorna instâncias da classe do objeto de persistência quando seu aplicativo executa uma consulta de critérios.
A seguir está o exemplo mais simples de uma consulta de critérios, que simplesmente retornará todos os objetos que correspondem à classe Employee.
Criteria cr = session.createCriteria(Employee.class);
List results = cr.list();
Restrições com critérios
Você pode usar add() método disponível para Criteriaobjeto para adicionar restrição para uma consulta de critérios. A seguir está o exemplo para adicionar uma restrição para retornar os registros com salário igual a 2.000 -
Criteria cr = session.createCriteria(Employee.class);
cr.add(Restrictions.eq("salary", 2000));
List results = cr.list();
A seguir estão mais alguns exemplos que abrangem diferentes cenários e podem ser usados de acordo com o requisito -
Criteria cr = session.createCriteria(Employee.class);
// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));
// To get records having salary less than 2000
cr.add(Restrictions.lt("salary", 2000));
// To get records having fistName starting with zara
cr.add(Restrictions.like("firstName", "zara%"));
// Case sensitive form of the above restriction.
cr.add(Restrictions.ilike("firstName", "zara%"));
// To get records having salary in between 1000 and 2000
cr.add(Restrictions.between("salary", 1000, 2000));
// To check if the given property is null
cr.add(Restrictions.isNull("salary"));
// To check if the given property is not null
cr.add(Restrictions.isNotNull("salary"));
// To check if the given property is empty
cr.add(Restrictions.isEmpty("salary"));
// To check if the given property is not empty
cr.add(Restrictions.isNotEmpty("salary"));
Você pode criar condições AND ou OR usando as restrições LogicalExpression da seguinte forma -
Criteria cr = session.createCriteria(Employee.class);
Criterion salary = Restrictions.gt("salary", 2000);
Criterion name = Restrictions.ilike("firstNname","zara%");
// To get records matching with OR conditions
LogicalExpression orExp = Restrictions.or(salary, name);
cr.add( orExp );
// To get records matching with AND conditions
LogicalExpression andExp = Restrictions.and(salary, name);
cr.add( andExp );
List results = cr.list();
Embora todas as condições acima possam ser usadas diretamente com HQL, conforme explicado no tutorial anterior.
Paginação usando critérios
Existem dois métodos da interface Criteria para paginação.
Sr. Não. | Método e Descrição |
---|---|
1 | public Criteria setFirstResult(int firstResult) Este método usa um número inteiro que representa a primeira linha em seu conjunto de resultados, começando com a linha 0. |
2 | public Criteria setMaxResults(int maxResults) Este método diz ao Hibernate para recuperar um número fixo maxResults de objetos. |
Usando os dois métodos acima juntos, podemos construir um componente de paginação em nosso aplicativo da web ou Swing. A seguir está o exemplo, que você pode estender para buscar 10 linhas por vez -
Criteria cr = session.createCriteria(Employee.class);
cr.setFirstResult(1);
cr.setMaxResults(10);
List results = cr.list();
Classificando os resultados
A API Criteria fornece o org.hibernate.criterion.Orderclasse para classificar seu conjunto de resultados em ordem crescente ou decrescente, de acordo com uma das propriedades do seu objeto. Este exemplo demonstra como você usaria a classe Order para classificar o conjunto de resultados -
Criteria cr = session.createCriteria(Employee.class);
// To get records having salary more than 2000
cr.add(Restrictions.gt("salary", 2000));
// To sort records in descening order
cr.addOrder(Order.desc("salary"));
// To sort records in ascending order
cr.addOrder(Order.asc("salary"));
List results = cr.list();
Projeções e agregações
A API Criteria fornece o org.hibernate.criterion.Projectionsclasse, que pode ser usada para obter a média, o máximo ou o mínimo dos valores da propriedade. A classe Projections é semelhante à classe Restrictions, pois fornece vários métodos de fábrica estáticos para obterProjection instâncias.
A seguir estão alguns exemplos que abrangem diferentes cenários e podem ser usados conforme a necessidade -
Criteria cr = session.createCriteria(Employee.class);
// To get total row count.
cr.setProjection(Projections.rowCount());
// To get average of a property.
cr.setProjection(Projections.avg("salary"));
// To get distinct count of a property.
cr.setProjection(Projections.countDistinct("firstName"));
// To get maximum of a property.
cr.setProjection(Projections.max("salary"));
// To get minimum of a property.
cr.setProjection(Projections.min("salary"));
// To get sum of a property.
cr.setProjection(Projections.sum("salary"));
Exemplo de consultas de critérios
Considere a seguinte classe POJO -
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Vamos criar a seguinte tabela EMPLOYEE para armazenar objetos Employee -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
A seguir estará o arquivo de mapeamento.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Finalmente, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo onde usaremos Criteria consultas -
import java.util.List;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Projections;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add few employee records in database */
Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
Integer empID3 = ME.addEmployee("John", "Paul", 5000);
Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);
/* List down all the employees */
ME.listEmployees();
/* Print Total employee's count */
ME.countEmployee();
/* Print Total salary */
ME.totalSalary();
}
/* Method to CREATE an employee in the database */
public Integer addEmployee(String fname, String lname, int salary){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to READ all the employees having salary more than 2000 */
public void listEmployees( ) {
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
// Add restriction.
cr.add(Restrictions.gt("salary", 2000));
List employees = cr.list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to print total number of records */
public void countEmployee(){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
// To get total row count.
cr.setProjection(Projections.rowCount());
List rowCount = cr.list();
System.out.println("Total Coint: " + rowCount.get(0) );
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to print sum of salaries */
public void totalSalary(){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Criteria cr = session.createCriteria(Employee.class);
// To get total salary.
cr.setProjection(Projections.sum("salary"));
List totalSalary = cr.list();
System.out.println("Total Salary: " + totalSalary.get(0) );
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado no capítulo de configuração.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado e os registros seriam criados na tabela EMPLOYEE.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 5000
First Name: Mohd Last Name: Yasee Salary: 3000
Total Coint: 4
Total Salary: 15000
Se você verificar sua tabela EMPLOYEE, ela deve ter os seguintes registros-
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 14 | Zara | Ali | 2000 |
| 15 | Daisy | Das | 5000 |
| 16 | John | Paul | 5000 |
| 17 | Mohd | Yasee | 3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>
Você pode usar SQL nativo para expressar consultas de banco de dados se quiser utilizar recursos específicos do banco de dados, como dicas de consulta ou a palavra-chave CONNECT no Oracle. O Hibernate 3.x permite que você especifique SQL escrito à mão, incluindo procedimentos armazenados, para todas as operações de criação, atualização, exclusão e carregamento.
Seu aplicativo criará uma consulta SQL nativa a partir da sessão com o createSQLQuery() método na interface da sessão -
public SQLQuery createSQLQuery(String sqlString) throws HibernateException
Depois de passar uma string contendo a consulta SQL para o método createSQLQuery (), você pode associar o resultado SQL a uma entidade Hibernate existente, uma junção ou um resultado escalar usando os métodos addEntity (), addJoin () e addScalar () respectivamente.
Consultas escalares
A consulta SQL mais básica é obter uma lista de escalares (valores) de uma ou mais tabelas. A seguir está a sintaxe para usar SQL nativo para valores escalares -
String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List results = query.list();
Consultas de Entidade
As consultas acima eram todas sobre o retorno de valores escalares, basicamente retornando os valores "brutos" do conjunto de resultados. A seguir está a sintaxe para obter objetos de entidade como um todo a partir de uma consulta sql nativa por meio de addEntity ().
String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List results = query.list();
Consultas SQL nomeadas
A seguir está a sintaxe para obter objetos de entidade de uma consulta sql nativa por meio de addEntity () e usando a consulta SQL nomeada.
String sql = "SELECT * FROM EMPLOYEE WHERE id = :employee_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
query.setParameter("employee_id", 10);
List results = query.list();
Exemplo de SQL nativo
Considere a seguinte classe POJO -
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Vamos criar a seguinte tabela EMPLOYEE para armazenar objetos Employee -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
A seguir estará o arquivo de mapeamento -
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Finalmente, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo onde usaremos Native SQL consultas -
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.SQLQuery;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add few employee records in database */
Integer empID1 = ME.addEmployee("Zara", "Ali", 2000);
Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
Integer empID3 = ME.addEmployee("John", "Paul", 5000);
Integer empID4 = ME.addEmployee("Mohd", "Yasee", 3000);
/* List down employees and their salary using Scalar Query */
ME.listEmployeesScalar();
/* List down complete employees information using Entity Query */
ME.listEmployeesEntity();
}
/* Method to CREATE an employee in the database */
public Integer addEmployee(String fname, String lname, int salary){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to READ all the employees using Scalar Query */
public void listEmployeesScalar( ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
List data = query.list();
for(Object object : data) {
Map row = (Map)object;
System.out.print("First Name: " + row.get("first_name"));
System.out.println(", Salary: " + row.get("salary"));
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to READ all the employees using Entity Query */
public void listEmployeesEntity( ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
String sql = "SELECT * FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Employee.class);
List employees = query.list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado no capítulo de configuração.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado e os registros seriam criados na tabela EMPLOYEE.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara Last Name: Ali Salary: 2000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 5000
First Name: Mohd Last Name: Yasee Salary: 3000
Se você verificar sua tabela EMPLOYEE, ela deve ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 26 | Zara | Ali | 2000 |
| 27 | Daisy | Das | 5000 |
| 28 | John | Paul | 5000 |
| 29 | Mohd | Yasee | 3000 |
+----+------------+-----------+--------+
4 rows in set (0.00 sec)
mysql>
Cache é um mecanismo para aprimorar o desempenho de um sistema. É uma memória intermediária que fica entre o aplicativo e o banco de dados. A memória cache armazena itens de dados usados recentemente para reduzir o número de acessos ao banco de dados tanto quanto possível.
O cache também é importante para o Hibernate. Ele utiliza um esquema de cache multinível conforme explicado abaixo -
Cache de primeiro nível
O cache de primeiro nível é o cache de sessão e é um cache obrigatório pelo qual todas as solicitações devem passar. O objeto Session mantém um objeto sob seu próprio poder antes de confirmá-lo no banco de dados.
Se você emitir várias atualizações para um objeto, o Hibernate tenta atrasar a atualização o máximo possível para reduzir o número de instruções SQL de atualização emitidas. Se você fechar a sessão, todos os objetos que estão sendo armazenados em cache serão perdidos e persistidos ou atualizados no banco de dados.
Cache de segundo nível
O cache de segundo nível é um cache opcional e o cache de primeiro nível sempre será consultado antes que seja feita qualquer tentativa de localizar um objeto no cache de segundo nível. O cache de segundo nível pode ser configurado em uma base por classe e por coleção e principalmente responsável por objetos de cache em sessões.
Qualquer cache de terceiros pode ser usado com o Hibernate. Aorg.hibernate.cache.CacheProvider interface é fornecida, que deve ser implementada para fornecer ao Hibernate um identificador para a implementação do cache.
Cache em nível de consulta
O Hibernate também implementa um cache para conjuntos de resultados de consulta que se integra intimamente com o cache de segundo nível.
Este é um recurso opcional e requer duas regiões de cache físico adicionais que contêm os resultados da consulta em cache e os carimbos de data / hora quando uma tabela foi atualizada pela última vez. Isso só é útil para consultas que são executadas frequentemente com os mesmos parâmetros.
O Cache de Segundo Nível
O Hibernate usa o cache de primeiro nível por padrão e você não precisa fazer nada para usar o cache de primeiro nível. Vamos direto para o cache de segundo nível opcional. Nem todas as classes se beneficiam do armazenamento em cache, por isso é importante poder desabilitar o cache de segundo nível.
O cache de segundo nível do Hibernate é configurado em duas etapas. Primeiro, você deve decidir qual estratégia de simultaneidade usar. Depois disso, você configura a expiração do cache e os atributos do cache físico usando o provedor de cache.
Estratégias de simultaneidade
Uma estratégia de simultaneidade é um mediador, que é responsável por armazenar itens de dados no cache e recuperá-los do cache. Se você for habilitar um cache de segundo nível, terá que decidir, para cada classe e coleção persistente, qual estratégia de simultaneidade de cache usar.
Transactional - Use esta estratégia para dados principalmente de leitura, onde é fundamental evitar dados obsoletos em transações simultâneas, no caso raro de uma atualização.
Read-write - Novamente, use essa estratégia para dados em sua maioria de leitura, onde é fundamental evitar dados obsoletos em transações simultâneas, no caso raro de uma atualização.
Nonstrict-read-write- Esta estratégia não garante a consistência entre o cache e o banco de dados. Use essa estratégia se os dados quase nunca mudam e uma pequena probabilidade de dados desatualizados não é uma preocupação crítica.
Read-only- Uma estratégia de simultaneidade adequada para dados, que nunca muda. Use-o apenas para dados de referência.
Se vamos usar o cache de segundo nível para nosso Employee , vamos adicionar o elemento de mapeamento necessário para dizer ao Hibernate para armazenar em cache as instâncias de Employee usando a estratégia de leitura e gravação.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<cache usage = "read-write"/>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
O atributo usage = "read-write" diz ao Hibernate para usar uma estratégia de concorrência de leitura e escrita para o cache definido.
Provedor de Cache
Sua próxima etapa após considerar as estratégias de simultaneidade, você usará suas classes candidatas de cache para escolher um provedor de cache. O Hibernate força você a escolher um único provedor de cache para toda a aplicação.
Sr. Não. | Nome e descrição do cache |
---|---|
1 | EHCache Ele pode armazenar em cache na memória ou em disco e armazenamento em cluster e suporta o cache de resultado de consulta Hibernate opcional. |
2 | OSCache Oferece suporte ao armazenamento em cache na memória e no disco em uma única JVM com um rico conjunto de políticas de expiração e suporte a cache de consulta. |
3 | warmCache Um cache de cluster baseado em JGroups. Ele usa invalidação em cluster, mas não suporta o cache de consulta do Hibernate. |
4 | JBoss Cache Um cache em cluster replicado totalmente transacional também baseado na biblioteca multicast JGroups. Ele suporta replicação ou invalidação, comunicação síncrona ou assíncrona e bloqueio otimista e pessimista. O cache de consulta do Hibernate é compatível. |
Cada provedor de cache não é compatível com todas as estratégias de simultaneidade. A matriz de compatibilidade a seguir o ajudará a escolher uma combinação apropriada.
Estratégia / Provedor | Somente leitura | Nonstrictread-write | Ler escrever | Transacional |
---|---|---|---|---|
EHCache | X | X | X | |
OSCache | X | X | X | |
SwarmCache | X | X | ||
JBoss Cache | X | X |
Você especificará um provedor de cache no arquivo de configuração hibernate.cfg.xml. Escolhemos EHCache como nosso provedor de cache de segundo nível -
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name = "hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume students is the database name -->
<property name = "hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name = "hibernate.connection.username">
root
</property>
<property name = "hibernate.connection.password">
root123
</property>
<property name = "hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- List of XML mapping files -->
<mapping resource = "Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Agora, você precisa especificar as propriedades das regiões de cache. EHCache tem seu próprio arquivo de configuração,ehcache.xml, que deve estar no CLASSPATH do aplicativo. Uma configuração de cache em ehcache.xml para a classe Employee pode se parecer com isto -
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory = "1000"
eternal = "false"
timeToIdleSeconds = "120"
timeToLiveSeconds = "120"
overflowToDisk = "true"
/>
<cache name = "Employee"
maxElementsInMemory = "500"
eternal = "true"
timeToIdleSeconds = "0"
timeToLiveSeconds = "0"
overflowToDisk = "false"
/>
É isso, agora temos o cache de segundo nível habilitado para a classe Employee e o Hibernate, agora atinge o cache de segundo nível sempre que você navegar para um Employee ou quando carregar um Employee por identificador.
Você deve analisar todas as suas classes e escolher a estratégia de armazenamento em cache apropriada para cada uma das classes. Às vezes, o cache de segundo nível pode diminuir o desempenho do aplicativo. Portanto, é recomendável fazer o benchmark de seu aplicativo primeiro, sem habilitar o cache e depois habilitar o cache adequado e verificar o desempenho. Se o armazenamento em cache não está melhorando o desempenho do sistema, não há por que habilitar qualquer tipo de armazenamento em cache.
O cache de nível de consulta
Para usar o cache de consulta, você deve primeiro ativá-lo usando o hibernate.cache.use_query_cache="true"propriedade no arquivo de configuração. Definindo esta propriedade como true, você faz com que o Hibernate crie os caches necessários na memória para manter os conjuntos de consulta e identificador.
Em seguida, para usar o cache de consulta, você usa o método setCacheable (Boolean) da classe Query. Por exemplo -
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();
O Hibernate também oferece suporte a cache de baixa granularidade através do conceito de região de cache. Uma região de cache é parte do cache que recebe um nome.
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();
Este código usa o método para dizer ao Hibernate para armazenar e procurar a consulta na área de funcionários do cache.
Considere uma situação em que você precisa fazer upload de um grande número de registros em seu banco de dados usando o Hibernate. A seguir está o trecho de código para conseguir isso usando o Hibernate -
Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Employee employee = new Employee(.....);
session.save(employee);
}
tx.commit();
session.close();
Por padrão, o Hibernate irá armazenar em cache todos os objetos persistentes no cache de nível de sessão e, finalmente, sua aplicação cairia com um OutOfMemoryExceptionalgo em torno da linha 50.000. Você pode resolver esse problema, se estiver usandobatch processing com o Hibernate.
Para usar o recurso de processamento em lote, primeiro defina hibernate.jdbc.batch_sizecomo tamanho do lote para um número de 20 ou 50, dependendo do tamanho do objeto. Isso dirá ao contêiner de hibernação que cada X linhas devem ser inseridas como lote. Para implementar isso em seu código, precisaríamos fazer algumas modificações da seguinte forma -
Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Employee employee = new Employee(.....);
session.save(employee);
if( i % 50 == 0 ) { // Same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
O código acima funcionará bem para a operação INSERT, mas se você estiver disposto a fazer a operação UPDATE, poderá conseguir usando o seguinte código -
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE").scroll();
int count = 0;
while ( employeeCursor.next() ) {
Employee employee = (Employee) employeeCursor.get(0);
employee.updateEmployee();
seession.update(employee);
if ( ++count % 50 == 0 ) {
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Exemplo de processamento em lote
Vamos modificar o arquivo de configuração para adicionar hibernate.jdbc.batch_size propriedade -
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name = "hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume students is the database name -->
<property name = "hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name = "hibernate.connection.username">
root
</property>
<property name = "hibernate.connection.password">
root123
</property>
<property name = "hibernate.jdbc.batch_size">
50
</property>
<!-- List of XML mapping files -->
<mapping resource = "Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Considere a seguinte classe POJO Employee -
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Vamos criar a seguinte tabela EMPLOYEE para armazenar os objetos Employee -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
A seguir estará o arquivo de mapeamento para mapear os objetos Employee com a tabela EMPLOYEE -
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Finalmente, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo onde usaremos flush() e clear() métodos disponíveis com o objeto Session para que o Hibernate continue escrevendo esses registros no banco de dados ao invés de armazená-los em cache na memória.
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add employee records in batches */
ME.addEmployees( );
}
/* Method to create employee records in batches */
public void addEmployees( ){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
String fname = "First Name " + i;
String lname = "Last Name " + i;
Integer salary = i;
Employee employee = new Employee(fname, lname, salary);
session.save(employee);
if( i % 50 == 0 ) {
session.flush();
session.clear();
}
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return ;
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado acima.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa, que criará 100.000 registros na tabela EMPLOYEE.
Como você aprendeu no Hibernate, um objeto será criado e persistido. Uma vez que o objeto foi alterado, ele deve ser salvo de volta no banco de dados. Esse processo continua até a próxima vez que o objeto for necessário e ele será carregado do armazenamento persistente.
Assim, um objeto passa por diferentes estágios em seu ciclo de vida e Interceptor Interfacefornece métodos, que podem ser chamados em diferentes estágios para realizar algumas tarefas necessárias. Esses métodos são callbacks da sessão para o aplicativo, permitindo que o aplicativo inspecione e / ou manipule as propriedades de um objeto persistente antes de ser salvo, atualizado, excluído ou carregado. A seguir está a lista de todos os métodos disponíveis na interface do Interceptor -
Sr. Não. | Método e Descrição |
---|---|
1 | findDirty() Este método é chamado quando o flush() método é chamado em um objeto de Sessão. |
2 | instantiate() Este método é chamado quando uma classe persistente é instanciada. |
3 | isUnsaved() Este método é chamado quando um objeto é passado para o saveOrUpdate() método/ |
4 | onDelete() Este método é chamado antes de um objeto ser excluído. |
5 | onFlushDirty() Este método é chamado quando o Hibernate detecta que um objeto está sujo (ou seja, foi alterado) durante uma operação de limpeza ou atualização. |
6 | onLoad() Este método é chamado antes de um objeto ser inicializado. |
7 | onSave() Este método é chamado antes que um objeto seja salvo. |
8 | postFlush() Este método é chamado depois que um flush ocorreu e um objeto foi atualizado na memória. |
9 | preFlush() Este método é chamado antes de um flush. |
O Hibernate Interceptor nos dá controle total sobre a aparência de um objeto tanto para o aplicativo quanto para o banco de dados.
Como usar interceptores?
Para construir um interceptor, você pode implementar Interceptor classe diretamente ou estender EmptyInterceptorclasse. A seguir, estão as etapas simples para usar a funcionalidade do Hibernate Interceptor.
Criar Interceptores
Vamos estender o EmptyInterceptor em nosso exemplo, onde o método do Interceptor será chamado automaticamente quando Employeeobjeto é criado e atualizado. Você pode implementar mais métodos de acordo com seus requisitos.
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;
public class MyInterceptor extends EmptyInterceptor {
private int updates;
private int creates;
private int loads;
public void onDelete(Object entity, Serializable id,
Object[] state, String[] propertyNames, Type[] types) {
// do nothing
}
// This method is called when Employee object gets updated.
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState, String[] propertyNames,
Type[] types) {
if ( entity instanceof Employee ) {
System.out.println("Update Operation");
return true;
}
return false;
}
public boolean onLoad(Object entity, Serializable id,
Object[] state, String[] propertyNames, Type[] types) {
// do nothing
return true;
}
// This method is called when Employee object gets created.
public boolean onSave(Object entity, Serializable id,
Object[] state, String[] propertyNames, Type[] types) {
if ( entity instanceof Employee ) {
System.out.println("Create Operation");
return true;
}
return false;
}
//called before commit into database
public void preFlush(Iterator iterator) {
System.out.println("preFlush");
}
//called after committed into database
public void postFlush(Iterator iterator) {
System.out.println("postFlush");
}
}
Criar classes POJO
Agora, vamos modificar um pouco nosso primeiro exemplo, onde usamos a tabela EMPLOYEE e a classe Employee para brincar -
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
Criar tabelas de banco de dados
O segundo passo seria criar tabelas em seu banco de dados. Haveria uma tabela correspondente a cada objeto, você está disposto a fornecer persistência. Considere os objetos explicados acima, precisam ser armazenados e recuperados na seguinte tabela RDBMS -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);
Criar arquivo de configuração de mapeamento
Este passo é criar um arquivo de mapeamento que instrui o Hibernate - como mapear a classe ou classes definidas para as tabelas do banco de dados.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
</hibernate-mapping>
Criar classe de aplicativo
Por fim, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo. Aqui, deve-se notar que ao criar o objeto de sessão, usamos nossa classe Interceptor como argumento.
import java.util.List;
import java.util.Date;
import java.util.Iterator;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Add few employee records in database */
Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
Integer empID3 = ME.addEmployee("John", "Paul", 10000);
/* List down all the employees */
ME.listEmployees();
/* Update employee's records */
ME.updateEmployee(empID1, 5000);
/* Delete an employee from the database */
ME.deleteEmployee(empID2);
/* List down new list of the employees */
ME.listEmployees();
}
/* Method to CREATE an employee in the database */
public Integer addEmployee(String fname, String lname, int salary){
Session session = factory.openSession( new MyInterceptor() );
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to READ all the employees */
public void listEmployees( ){
Session session = factory.openSession( new MyInterceptor() );
Transaction tx = null;
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM Employee").list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to UPDATE salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession( new MyInterceptor() );
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to DELETE an employee from the records */
public void deleteEmployee(Integer EmployeeID){
Session session = factory.openSession( new MyInterceptor() );
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de ter definido PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado no capítulo de configuração.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo fonte MyInterceptor.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado e os registros seriam criados na tabela EMPLOYEE.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
First Name: Zara Last Name: Ali Salary: 1000
First Name: Daisy Last Name: Das Salary: 5000
First Name: John Last Name: Paul Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara Last Name: Ali Salary: 5000
First Name: John Last Name: Paul Salary: 10000
preFlush
postFlush
Se você verificar sua tabela EMPLOYEE, ela deve ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara | Ali | 5000 |
| 31 | John | Paul | 10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec
mysql>