Tomcat JNDI DataSource 예제 자습서

환영합니다. Hibernate Tomcat JNDI DataSource 예제 튜토리얼에 오신 것을 환영합니다. 이미 스텐드얼론 Java 애플리케이션에서 Hibernate ORM 도구를 사용하는 방법을 살펴보았으며, 오늘은 Tomcat 서블릿 컨테이너에서 DataSource와 함께 Hibernate를 사용하는 방법을 배우겠습니다. 웹 애플리케이션에서 Hibernate를 사용하는 것은 매우 쉽습니다. 필요한 것은 hibernate 구성 파일에서 DataSource 속성을 구성하는 것뿐입니다. 우선 테스트 데이터베이스와 Tomcat 컨테이너에서 JNDI DataSource를 설정해야 합니다.

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());

데이터베이스 스키마 이름은 TestDB입니다.

Tomcat JNDI DataSource 구성

DataSource를 초기화하도록 tomcat 컨테이너를 구성하려면 tomcat server.xml 및 context.xml 파일에 일부 변경을 해야 합니다. 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"/>

위의 자원을 GlobalNamingResources 요소에 추가하세요. context.xml

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

파일에 위의 ResourceLink를 추가하십시오. 이렇게하면 응용 프로그램에서 이름이 jdbc/MyLocalDB인 JNDI 리소스에 액세스 할 수 있습니다. 서버를 다시 시작하면 tomcat 서버 로그에 오류가 표시되지 않아야합니다. 암호가 잘못된 등 잘못된 구성이있는 경우 서버 로그에서 해당 예외가 발생합니다. 또한 MySQL 드라이버 jar 파일이 tomcat lib 디렉토리 내에 있어야합니다. 그렇지 않으면 tomcat이 데이터베이스 연결을 생성 할 수 없으며 로그에서 ClassNotFoundException이 발생합니다. 이제 데이터베이스와 tomcat 서버 JNDI 설정이 준비되었으니, hibernate을 사용하여 웹 애플리케이션을 생성하는 것으로 이동합시다.

Hibernate DataSource 예제 동적 웹 프로젝트

Eclipse에서 동적 웹 프로젝트를 생성한 다음 Maven 프로젝트로 구성하십시오. 최종 프로젝트 구조는 아래 이미지와 같습니다. 프로젝트 배포에 Tomcat-7을 사용하고 빌드 패스에 추가했으므로 별도로 Servlet API 종속성을 프로젝트에 추가할 필요가 없습니다. Tomcat-7은 Servlet 3 specs를 지원하며 서블릿을 만들기 위해 주석을 사용할 것입니다. Servlet 3 주석에 익숙하지 않다면 초보자를 위한 Servlet 튜토리얼을 확인해야 합니다. 각 구성 요소를 하나씩 살펴 보겠습니다.

Hibernate Maven 종속성

최종 pom.xml 파일은 아래와 같습니다.

<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.

Hibernate DataSource 구성

데이터 소스를 포함한 하이버네이트 구성 파일은 아래와 같습니다. 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 속성은 Hibernate이 데이터베이스 작업에 사용할 DataSource 이름을 제공하는 데 사용됩니다.

Hibernate DataSource 예제 모델 클래스

hibernate 구성 파일에서 볼 수 있듯이, 우리는 모델 클래스 Employee에서 주석을 사용하고 있습니다. 모델 빈은 다음과 같이 보입니다. 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;
	}
}

모델 빈은 Hibernate 초보자 튜토리얼에서 사용한 것과 동일합니다. 주석에 관련된 혼란이 있으면 확인해 보세요.

Hibernate DataSource Tomcat JNDI Servlet Listener

SessionFactory를 초기화해야 하므로 애플리케이션에서 사용하고 웹 애플리케이션이 파괴될 때 SessionFactory를 파괴해야 합니다. 이 작업을 수행하기에 가장 적절한 장소는 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");
    }
	
}

만약 서블릿 리스너에 익숙하지 않다면, 서블릿 리스너 튜토리얼을 읽어보세요.

하이버네이트 톰캣 JNDI 예제 서블릿 구현

우리는 직원 ID를 요청 매개변수로 전달하고 데이터베이스에서 직원 정보를 출력할 간단한 서블릿을 작성할 것입니다. 당연히 우리는 하이버네이트를 사용하여 데이터베이스를 쿼리하고 직원 정보를 가져올 것입니다. 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>");
        }
	}

}

이것은 매우 간단한 서블릿 클래스입니다. 나는 @WebServlet 어노테이션을 사용하여 URI 패턴을 제공합니다.

하이버네이트 데이터 소스 톰캣 JNDI 예제 애플리케이션 테스트

저희 애플리케이션이 준비되었습니다. 이제 war 파일로 내보내고 톰캣 컨테이너에 배포하면 됩니다. 저희 애플리케이션 서블릿을 호출할 때 일부 스크린샷이 아래에 있습니다. 요청 URL 쿼리 문자열에서 empId 요청 매개변수를 전달하고 있음을 주의해주세요. 또한 서버 로그에서 우리 애플리케이션에서 생성된 로그를 볼 수 있습니다.

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

애플리케이션을 언디플로이하거나 서버를 중지하면 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

이것이 톰캣 컨테이너용 Hibernate DataSource 예제에 관한 모든 내용입니다. 이해하고 구현하기 쉬우리라고 기대합니다. 아래 링크에서 샘플 프로젝트를 다운로드하여 더 많이 배우고 연습해보세요.

Hibernate DataSource 프로젝트 다운로드

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