Exemplo de Tutorial do Hibernate Tomcat JNDI DataSource

Bem-vindo ao tutorial de exemplo do Hibernate Tomcat JNDI DataSource. Já vimos como usar a ferramenta Hibernate ORM em uma aplicação Java autônoma, hoje aprenderemos como usar o Hibernate com DataSource no contêiner de servlets Tomcat. Usar o Hibernate em uma aplicação web é muito fácil, tudo o que precisamos fazer é configurar as propriedades do DataSource no arquivo de configuração do Hibernate. Primeiro, precisamos configurar o banco de dados de teste e o DataSource JNDI no contêiner do Tomcat.

Configuração do Exemplo de Banco de Dados do Hibernate DataSource JNDI

I am using MySQL for my example, below script is executed to create a simple table and insert some values into it. employee.sql

CREATE TABLE `Employee` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `role` varchar(20) DEFAULT NULL,
  `insert_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

INSERT INTO `Employee` (`id`, `name`, `role`, `insert_time`)
VALUES
	(3, 'Pankaj', 'CEO', now());
INSERT INTO `Employee` (`id`, `name`, `role`, `insert_time`)
VALUES
	(14, 'David', 'Developer', now());

O nome do esquema do banco de dados é TestDB.

Configuração do Tomcat JNDI DataSource

Para configurar o contêiner do Tomcat para inicializar o DataSource, precisamos fazer algumas alterações nos arquivos server.xml e context.xml do Tomcat. server.xml

<Resource name="jdbc/MyLocalDB" 
      global="jdbc/MyLocalDB" 
      auth="Container" 
      type="javax.sql.DataSource" 
      driverClassName="com.mysql.jdbc.Driver" 
      url="jdbc:mysql://localhost:3306/TestDB" 
      username="pankaj" 
      password="pankaj123" 
      
      maxActive="100" 
      maxIdle="20" 
      minIdle="5" 
      maxWait="10000"/>

Adicione o recurso acima no elemento GlobalNamingResources do server.xml. context.xml

<ResourceLink name="jdbc/MyLocalDB"
              global="jdbc/MyLocalDB"
              auth="Container"
              type="javax.sql.DataSource" />

Adicione acima do ResourceLink no arquivo context.xml, é necessário para que as aplicações possam acessar o recurso JNDI com o nome jdbc/MyLocalDB. Basta reiniciar o servidor, você não deverá ver nenhum erro nos logs do servidor Tomcat. Se houver configurações erradas, como senha incorreta, você receberá a exceção correspondente no log do servidor. Você também precisa garantir que o arquivo jar do driver do MySQL esteja dentro do diretório lib do Tomcat, caso contrário, o Tomcat não será capaz de criar conexão com o banco de dados e você receberá ClassNotFoundException nos logs. Agora, nossa configuração de banco de dados e servidor Tomcat JNDI está pronta, vamos avançar para criar nossa aplicação web usando o Hibernate.

Exemplo de Fonte de Dados do Hibernate Projeto Web Dinâmico

Crie um projeto web dinâmico no Eclipse e, em seguida, configure-o como um projeto Maven. Nossa estrutura final do projeto ficará como na imagem abaixo. Note que estou usando o Tomcat-7 para a implantação do meu projeto e o adicionei ao caminho de construção, para que não precisemos adicionar separadamente as dependências da API Servlet em nosso projeto. O Tomcat-7 suporta Servlet 3 specs e estaremos usando anotações para criar nossos servlets. Se você não está familiarizado com as anotações do Servlet 3, deve verificar o Tutorial do Servlet para Iniciantes. Vamos analisar cada um dos componentes um por um.

Dependências do Hibernate Maven

Nosso arquivo pom.xml final fica assim.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>HibernateDataSource</groupId>
	<artifactId>HibernateDataSource</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	
	<dependencies>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>4.3.5.Final</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.0.5</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.3</version>
				<configuration>
					<warSourceDirectory>WebContent</warSourceDirectory>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
		<finalName>${project.artifactId}</finalName>
	</build>
</project>

I am using Hibernate latest version 4.3.5.Final, hibernate-core dependency is added for Hibernate. mysql-connector-java dependency is added because we are using MySQL database, although scope is provided because it’s already part of the tomcat container libraries. Even if we don’t add MySQL driver dependencies, our project will compile and run fine. However it’s better to include it so that if someone will look into the project dependencies, it will be clear that we are using MySQL database.

Configuração do Hibernate DataSource

Nosso arquivo de configuração do Hibernate com o datasource fica assim. hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.datasource">java:comp/env/jdbc/MyLocalDB</property>
        <property name="hibernate.current_session_context_class">thread</property>
        
        <!-- Mapping with model class containing annotations -->
	<mapping class="com.journaldev.servlet.hibernate.model.Employee"/>
    </session-factory>
</hibernate-configuration>

hibernate.connection.datasource é uma propriedade usada para fornecer o nome do DataSource que será utilizado pelo Hibernate para operações no banco de dados.

Exemplo de Classe Modelo de DataSource do Hibernate

Conforme pode ser visto no arquivo de configuração do Hibernate, estamos utilizando anotações em nossa classe modelo Employee. Nosso bean modelo parece o seguinte. Employee.java

package com.journaldev.servlet.hibernate.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name="Employee", 
	   uniqueConstraints={@UniqueConstraint(columnNames={"ID"})})
public class Employee {

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="ID", nullable=false, unique=true, length=11)
	private int id;
	
	@Column(name="NAME", length=20, nullable=true)
	private String name;
	
	@Column(name="ROLE", length=20, nullable=true)
	private String role;
	
	@Column(name="insert_time", nullable=true)
	private Date insertTime;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public Date getInsertTime() {
		return insertTime;
	}
	public void setInsertTime(Date insertTime) {
		this.insertTime = insertTime;
	}
}

O bean modelo é o mesmo que usamos no Tutorial Inicial do Hibernate, você deve conferir se tiver alguma confusão relacionada a alguma das anotações utilizadas.

Ouvinte de Servlet JNDI do Hibernate DataSource Tomcat

Como precisamos inicializar o SessionFactory do Hibernate para usá-lo na aplicação e também destruir o SessionFactory quando a aplicação web for encerrada, o melhor lugar para fazer isso é na implementação de um ServletContextListener. HibernateSessionFactoryListener.java

package com.journaldev.servlet.hibernate.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.jboss.logging.Logger;

@WebListener
public class HibernateSessionFactoryListener implements ServletContextListener {

	public final Logger logger = Logger.getLogger(HibernateSessionFactoryListener.class);
	
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
    	SessionFactory sessionFactory = (SessionFactory) servletContextEvent.getServletContext().getAttribute("SessionFactory");
    	if(sessionFactory != null && !sessionFactory.isClosed()){
    		logger.info("Closing sessionFactory");
    		sessionFactory.close();
    	}
    	logger.info("Released Hibernate sessionFactory resource");
    }

    public void contextInitialized(ServletContextEvent servletContextEvent) {
    	Configuration configuration = new Configuration();
    	configuration.configure("hibernate.cfg.xml");
    	logger.info("Hibernate Configuration created successfully");
    	
    	ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
    	logger.info("ServiceRegistry created successfully");
    	SessionFactory sessionFactory = configuration
				.buildSessionFactory(serviceRegistry);
    	logger.info("SessionFactory created successfully");
    	
    	servletContextEvent.getServletContext().setAttribute("SessionFactory", sessionFactory);
    	logger.info("Hibernate SessionFactory Configured successfully");
    }
	
}

Se você não está familiarizado com os ouvintes de servlet, por favor leia Tutorial de Ouvinte de Servlet.

Exemplo de Implementação de Servlet Hibernate Tomcat JNDI

Vamos escrever um servlet simples onde passaremos o ID do funcionário como parâmetro de solicitação e ele imprimirá as informações do funcionário do banco de dados, obviamente usaremos o Hibernate para consultar o banco de dados e obter as informações do funcionário. GetEmployeeByID.java

package com.journaldev.servlet.hibernate;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.jboss.logging.Logger;

import com.journaldev.servlet.hibernate.model.Employee;

@WebServlet("/GetEmployeeByID")
public class GetEmployeeByID extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	public final Logger logger = Logger.getLogger(GetEmployeeByID.class);
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int empId = Integer.parseInt(request.getParameter("empId"));
		logger.info("Request Param empId="+empId);
		
		SessionFactory sessionFactory = (SessionFactory) request.getServletContext().getAttribute("SessionFactory");
		
		Session session = sessionFactory.getCurrentSession();
		Transaction tx = session.beginTransaction();
		Employee emp = (Employee) session.get(Employee.class, empId);
		tx.commit();
		PrintWriter out = response.getWriter();
        response.setContentType("text/html");
        if(emp != null){
        out.print("<html><body><h2>Employee Details</h2>");
        out.print("<table border=\"1\" cellspacing=10 cellpadding=5>");
        out.print("<th>Employee ID</th>");
        out.print("<th>Employee Name</th>");
        out.print("<th>Employee Role</th>");
        
            out.print("<tr>");
            out.print("<td>" + empId + "</td>");
            out.print("<td>" + emp.getName() + "</td>");
            out.print("<td>" + emp.getRole() + "</td>");
            out.print("</tr>");
        out.print("</table></body><br/>");
        
        out.print("</html>");
        }else{
        	out.print("<html><body><h2>No Employee Found with ID="+empId+"</h2></body></html>");
        }
	}

}

É uma classe de servlet muito simples, estou usando a anotação @WebServlet para fornecer o padrão URI para ele.

Testando a Aplicação de Exemplo de Fonte de Dados Hibernate DataSource Tomcat JNDI

Nossa aplicação está pronta agora, basta exportá-la como um arquivo war e implantá-la no contêiner Tomcat. Abaixo estão algumas capturas de tela quando invocamos o servlet de nossa aplicação. Note que estou passando o parâmetro de solicitação empId na string de consulta da URL da solicitação. Você também verá os logs gerados pela nossa aplicação nos logs do servidor.

May 08, 2014 8:14:16 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: hibernate.cfg.xml
May 08, 2014 8:14:16 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: hibernate.cfg.xml
May 08, 2014 8:14:16 PM org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
May 08, 2014 8:14:16 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextInitialized
INFO: Hibernate Configuration created successfully
May 08, 2014 8:14:16 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextInitialized
INFO: ServiceRegistry created successfully
May 08, 2014 8:14:16 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
May 08, 2014 8:14:17 PM org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
May 08, 2014 8:14:17 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
May 08, 2014 8:14:17 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
May 08, 2014 8:14:17 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextInitialized
INFO: SessionFactory created successfully
May 08, 2014 8:14:17 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextInitialized
INFO: Hibernate SessionFactory Configured successfully
May 08, 2014 8:14:32 PM com.journaldev.servlet.hibernate.GetEmployeeByID doGet
INFO: Request Param empId=3
May 08, 2014 8:15:22 PM com.journaldev.servlet.hibernate.GetEmployeeByID doGet
INFO: Request Param empId=3

Se você desimplantar a aplicação ou parar o servidor, verá logs do servidor destruindo a SessionFactory.

May 08, 2014 11:31:16 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextDestroyed
INFO: Closing sessionFactory
May 08, 2014 11:31:16 PM com.journaldev.servlet.hibernate.listener.HibernateSessionFactoryListener contextDestroyed
INFO: Released Hibernate sessionFactory resource

Isso é tudo para o Exemplo de DataSource do Hibernate para o contêiner Tomcat, espero que seja fácil de entender e implementar. Baixe o projeto de exemplo a partir do link abaixo e explore para aprender mais.

Baixe o Projeto de DataSource do Hibernate

Source:
https://www.digitalocean.com/community/tutorials/hibernate-tomcat-jndi-datasource-example-tutorial