관리 메뉴

nkdk의 세상

Quick Start Hibernate 본문

My Programing/EJB

Quick Start Hibernate

nkdk 2008. 5. 23. 18:02

목표 :

  Hibernate를 이용하여 코멘드라인 애플리케이션을 in-memory 데이터베이스(HSQL)를 활용하여 작성한다.


참고자료 : Hibernate-reference.pdf


단계 :

1. 하이버네이트를 사용하기 위한 기본 라이브러리 획득

2. 첫번째 persistent class 작성

3. Hibernate mapping 파일 작성

4. HIbernate Configuration 파일 작성

5. Ant 빌드

6. Helper 클래스 (하이버네이트에서 유용한 유틸성 헬퍼 클래스)

7. Hibernate에 작업요청을 하는 클래스 작성

8. HSQL 실행 (in memory 데이터베이스)

9. 실행해보고 결과 확인하기


단계 1 : 하이버네이트를 사용하기 위한 기본 라이브러리 획득

Hibernate 패키지를 다운로드 받게되면 lib폴더에 다양한 .jar파일들이 존재한다. 이 Quick Start를 실행하기 위해서 반드시 필요한 jar파일을 살펴보자.

-----------------------------------------

antlr.jar

cglib.jar

asm.jar

asm-attrs.jars

commons-collections.jar

commons-logging.jar

hibernate3.jar

jta.jar

dom4.jar

log4j.jar

-----------------------------------------

이것이 hibernate를 이용하여 작업하기 위한 최소 단위의 라이브러리이다.


단계 2 : 첫번째 persistent class 작성

Hibernate는 ORM이다. 그러므로 데이터베이스와 매핑할 수 있는 퍼시스턴스 클래스를 작성해야 한다. 보통 이때 작성되는 것이 우리가 일반적으로 이야기 하는 POJO를 작성하게 된다.

package events;

import java.util.Date;

public class Event {

 private Long id;
 private String title;
 private Date date;
 
 public Event() {}

 public Date getDate() {
  return date;
 }

 public void setDate(Date date) {
  this.date = date;
 }

 public Long getId() {
  return id;
 }

 private void setId(Long id) {
  this.id = id;
 }

 public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }
 
}


1. 일반적인 자바의 형식에 따라 필드들을 getter/setter을 이용하여 작성한다.

2. id에 해당하는 부분은 테이블의 PK에 해당하는 부분과 매핑된다.

   보통 private 접근 제한자를 이용하는것을 추천하고 있다.(일반적으로 DB의 PK를 사용자가 임의로 조정하지 않을므로 이역시 자바 클래스를 유일하게 식별하는 필드이므로 임의로 조정할 수 없게 하는것이 옳다.)

    대부분의 Hibernate의 Persisitant class에서는 이러한 ID를 필요로 할 것이다.

3. 아규먼트가 없는 생상자 즉, 디폴트 생성자는 반드시 포함해야 한다.

    Hibernate는 Java Reflection을 이용하여 객체의 인스턴스를 생성하기 때문이다.

    기본생성자의 경우 private로 설정해도 된다. 그러나 package 이하의 가시성을 두어야 runtime proxy generation과 빠른 데이터 검색을 할 수 있게 된다.


단계 3. Hibernate mapping 파일 작성

  Hibernate는 자료를 저장하고 로드해올 persistent class에 대한 정보를 필요로 한다.

  이러한 정보를 제공하는 것이 Hiberante mapping파일이며 이 매핑파일은 데이터 베이스의 어떤 테이블에 접근할지, 어떠한 칼럼을 가져올지에 대한 정보를 담고 있다.

<?xml version="1.0" ?>
<!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping>

 <class name="events.Event" table="EVENTS">
  <id name="id" column="EVENT_ID">
   <generator class="native"/>
  </id>
 
  <property name="date" type="timestamp" column="EVENT_DATE"/>
  <property name="title"/>
 </class>
</hibernate-mapping>


1. 매핑 파일을 만들기 위해서는 반드시 DTD설정부분을 넣어주어야 한다. 이 부분을 입력하게 되면 HIbernate가 실행될 때 hibernate3.jar 내에 존재하는 dtd를 조회하여 xml의 적법성을 검사하게 된다.

2. hibernate-mapping 태스 사이에는 class 엘리먼트가 들어간다.

    <class name="events.Event" table="EVENTS"> 는 events.Event 라는 persitant class가 실제 데이터베이스의 EVENTS라는 테이블과 매핑됨을 의미한다.

3. <id name="id" column="EVENT_ID"> 와 같이 identifier의 속성을 HIbernate가 알아서 지정하고 접근하도록 설정한다. id라는 Event persistant class의 필드는 테이블의 EVENT_ID와 매핑됨을 의미한다.

4. <generator class="native"/> 이것은 클래스 고유값을 우리가 컨트롤 하는것이 아니라. Hibernate가 직접 EVENT_ID를 PK로 하는 테이블에서 자동으로 할당하라는 의미가 된다.

    여기서 native는 차후 설정할 Hibernate 설정파일에 지정한 데이터베이스가 가지는 최선의 전략에 의존하여 직접 지정함을 의미한다.

5. property 는 일반적인 persistant class의 속성갑과, 테이블 필드값을 매핑시켜주는 태그이다. 이 부분은 각각 getter/setter과 매핑되어 동작하게 된다.

    <property name="title"/>와 같이 column이 없는경우 name인 persisitant class 속성값과 이름이 동일한 테이블 필드값을 자동으로 매핑하라는 의미이다. 이때 클래스의 데이터타입과 이름을 따라감에 주의하기 바란다.

    <property name="date" type="timestamp" column="EVENT_DATE"/>에서 type는 자바클래스의 데이터 타입을 결정하기 모호할경우(EVENT_DATE가 timestamp데이터 타입일수도 있고, time 데이터 타입을수 있기 때문에 이를 해소해야 한다.) 직접 변경된 타입을 지정해 준다.


스텝 4. HIbernate Configuration 파일 작성

  Hibernate는 애플리케이션과 DB가 어떠한 커넥션을 통해서 이루어 지는지에 대한 정보(Connection Pool, JTA, Simple JDBC)를 필요로하게 되며 이것을 설정하는 것이 config 파일이다.

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <!-- Database connection settings  -->
  <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
  <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
  <property name="connection.username">sa</property>
  <property name="connection.password"></property>
 
  <!-- JDBC Connection Pool  -->
  <property name="connection.pool_size">1</property>
 
  <!-- SQL Dialect  -->
  <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
 
  <!-- Enable Hibernate's automatic session context management  -->
  <property name="current_session_context_class">thread</property>
 
  <!-- Disable the second-level cache  -->
  <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
 
  <!-- Echo all executed SQL to stdout  -->
  <property name="show_sql">true</property>
 
  <!-- Drop and re-create the database schema on startup  -->
  <property name="hbm2ddl.auto">create</property>
 
  <mapping resource="events/Event.hbm.xml"/>
 
 </session-factory>
</hibernate-configuration>

1. 특정 데이터베이스에서 하이버네이트의 SessionFactory와 연동되는 항목에 대한 설정이다.

    다양한 데이터베이스를 사용한다면 다양한 session-factory태그를 설정해 주면 될것이다.

2. 첫번째 property는 JDBC연결에 대한 설정이다. 이 것은 일반적인 데이터베이스 설정과 유사하다.

3. dialect 프로퍼티는 Hivernate가 생성할 다앙한 SQL을 특정 데이터베이스의 문법에 의거하여 생성하도록 하는 부분이다.

    여기서는 org.hibernate.dialect.HSQLDialect로 in-memory 데이터베이스인 HSQL을 사용한다는 것을 의미하고 있다.

4. hbm2ddl.auto 는 데이터베이스를 자동으로 생성할지 여부에 대한 설정이다. 이 값을 create라고 한다면 매번 hibernate를 가동할때마다 해당 스키마를 다시 생성함을 의미한다.


스텝 5. Ant 빌드

 <project name="hibernate-tutorial" default="compile">
 <property name="sourcedir" value="${basedir}/src"/>
 <property name="targetdir" value="${basedir}/bin"/>
 <property name="librarydir" value="${basedir}/lib"/>
 
 <path id="libraries">
  <fileset dir="${librarydir}">
   <include name="*.jar"/>
  </fileset>
 </path>
 
 <target name="clean">
  <delete dir="${targetdir}"/>
  <mkdir dir="${targetdir}"/>
 </target>
 
 <target name="compile" depends="clean, copy-resources">
  <javac srcdir="${sourcedir}" destdir="${targetdir}" classpathref="libraries"/>
 </target>
 
 <target name="copy-resources">
  <copy todir="${targetdir}">
   <fileset dir="${sourcedir}">
    <exclude name="**/*.java"/>
   </fileset>
  </copy>
 </target>
</project>


C:/hibernateTurorial/>ant

를 수행하면 해당 내용이 빌드 된다. Eclipse를 사용하면 자동 빌드를 이용하면 될것이다.


스텝 6. Helper 클래스 (하이버네이트에서 유용한 유틸성 헬퍼 클래스)

  이제 설정은 거의 끝이 났다. Hibernate를 이용하기 위해서는 config에서 수행했던 SessionFactory를 이용해야한다. 이 SessionFactory객체를 이용하여 session을 획득하고 이를 이용하여 데이터베이스 작업을 수행하게 된다.

  session객체는 단일 스레드에서 작업의 한 단위를 의미한다. SessionFactory는 global영역에서 Thread Safe한 객체이며 오직 한번만 생성되게 된다. 그러므로 다음과 같은 헬퍼 클래스가 유용하게 사용될 것이다.

package util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
 private static final SessionFactory sessionFactory;
 
 static {
  try {
   sessionFactory = new Configuration().configure().buildSessionFactory();
  }
  catch (Throwable ex) {
   System.err.println("initial SessionFactory creation failed." + ex);
   throw new ExceptionInInitializerError(ex);
  }
 
 }
 
 public static SessionFactory getSessionFactory()
 {
  return sessionFactory;
 }
}



1. 이 클래스는 static 초기화를 수행하며 JVM에 로드될때 오직 한번만 실행되는 Singleton 패턴이다.

2. 이것은 애플리케이션 서버에서 SessionFactory를 JNDI로부터 룩업을 통해서 획득하게 된다.


현재까지 내용을 수행하면 다음과 같은 디렉토리 구조가 생성된다.

+lib

  <hibernate and third-party libraries>

+src

  + events

    Event.java

    Event.hbm.xml

  + util

    HibernateUtil.java

  hibernate.cfg.xml

+data -- 이부분은 HSQL용으로 그냥 생성해 두기 바란다.

build.xml


스텝 7. Hibernate에 작업요청을 하는 클래스 작성

  마지막으로 수행할 작업은 이제까지 작성해놓은 기본적인 persistant class와 util, 각종 설정파일을 이용하여 실제 데이터를 저장하는 작업을 해보는 것이다.

package events;

import java.util.Date;
import java.util.List;

import org.hibernate.Session;

import util.HibernateUtil;

public class EventManager {

 public static void main(String[] args)
 {
  EventManager mgr = new EventManager();
 
  String command = "store";
 
  if(command.equals("store")) {
   System.out.println("데이터 저장");
   mgr.createAndStoreEvent("My Event", new Date());
  }
 
  command = "list";
  if(command.equals("list")) {
   System.out.println("데이터 리스트 출력");
   List events = mgr.listEvents();
   for(int i=0; i<events.size();i++)
   {
    Event theEvent = (Event)events.get(i);
    System.out.println("Event: " + theEvent.getTitle() + " Time : " + theEvent.getDate());
   }
  }
  HibernateUtil.getSessionFactory().close();
 }

 private List listEvents() {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();
 
  List result = session.createQuery("from Event").list();
 
  session.getTransaction().commit();
 
  return result;
 }

 private void createAndStoreEvent(String title, Date date) {
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();
 
  Event theEvent = new Event();
  theEvent.setTitle(title);
  theEvent.setDate(date);
 
  session.save(theEvent);
 
  session.getTransaction().commit();
 
 }
}



스텝 8. HSQL 실행 (in memory 데이터베이스)

  1. lib폴더에 hsqldb.jar이 존재하는지 확인한다. 없다면 찾아서 넣어주자.

  2. cd data 해서 data디렉토리로 이동한다.

  3. java -classpath ../lib/hsqldb.jar org.hsqldb.Server 을 수행한다.

  4. 종료하고 싶다면 Ctrl + C를 이용하여 종료하면 된다. (윈도우의 경우)


스텝 9. 실행해보고 결과 확인하기

  실행 결과를 확인해보자. 어떠한 결과가 나오는지 

  <target name="run" depends="compile">
  <java fork="true" classname="events.EventManager" classpathref="libraries">
   <classpath path="${targetdir}"/>
   <arg value="${action}"/>
  </java>
 </target>

을 ant에 추가해준다.


c:/hibernateTutorial/>ant run -Dactioin=store 를 실행한다.


Source위치 :

svn://210.108.170.154/java/trunk/HIbernateTest