Exemplo de Tutorial de Hibernate Tomcat JNDI DataSource

Bem-vindo ao tutorial de exemplo do Hibernate Tomcat JNDI DataSource. Já vimos como usar a ferramenta Hibernate ORM em um aplicativo Java autônomo, hoje aprenderemos como usar o Hibernate com DataSource no contêiner de servlet Tomcat. Usar o Hibernate em um aplicativo da 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 Banco de Dados de Exemplo 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 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 de 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 deve ver erros nos logs do servidor Tomcat. Se houver configurações erradas, como a senha errada, você receberá a exceção correspondente no log do servidor. Você também precisa garantir que o arquivo jar do driver MySQL esteja dentro do diretório lib do Tomcat, caso contrário, o Tomcat não será capaz de criar a conexão com o banco de dados e você receberá ClassNotFoundException nos logs. Agora nossa configuração de JNDI do banco de dados e servidor Tomcat 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 depois o configure como um projeto Maven. A estrutura final do nosso projeto será como na imagem abaixo. Note que estou usando Tomcat-7 para o deployment do meu projeto e o adicionei ao build path, para que não precisemos adicionar separadamente as dependências da API Servlet em nosso projeto. O Tomcat-7 suporta as especificações Servlet 3 e estaremos usando anotações para criar nossos servlets. Se você não estiver familiarizado com as anotações Servlet 3, deveria dar uma olhada no Tutorial Servlet para Iniciantes. Vamos analisar cada um dos componentes um por um.

Dependências Maven do Hibernate

Nosso arquivo pom.xml final se parece com o abaixo.

<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 DataSource do Hibernate

Nosso arquivo de configuração do hibernate com o datasource se parece com abaixo. 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>

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

Exemplo de Modelo de DataSource do Hibernate

Como você pode ver no arquivo de configuração do Hibernate, estamos usando anotações em nossa classe de modelo Employee. Nosso bean de 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 de modelo é o mesmo que usamos no Tutorial para Iniciantes do Hibernate, você deve verificar se tiver alguma confusão relacionada a alguma das anotações usadas.

Ouvinte de Servlet Tomcat JNDI do DataSource do Hibernate

Já que precisamos inicializar o SessionFactory do Hibernate para que possamos usá-lo na aplicação e também quando a aplicação web for destruída, precisamos destruir o SessionFactory. Então, o melhor lugar para fazer isso é em uma implementação de 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 não estiver familiarizado com os ouvintes de servlets, por favor, leia o Tutorial do 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 de URI para ele.

Aplicação de Exemplo de Teste do Hibernate DataSource Tomcat JNDI

Nossa aplicação está pronta agora, basta exportá-la como arquivo war e implantá-la no contêiner tomcat. Abaixo estão algumas capturas de tela quando invocamos nosso servlet de 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á nossos logs de 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á os logs do servidor para destruir 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 Fonte de Dados do Hibernate para o contêiner tomcat, espero que seja fácil de entender e implementar. Baixe o projeto de exemplo no link abaixo e explore-o para aprender mais.

Baixar Projeto de Fonte de Dados do Hibernate

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