Hibernate 첫 번째 예제 - 튜토리얼
원문 : http://www.laliluna.de/first-hibernate-example-tutorial.html
역자 : 김종대(jdkim528@korea.com)
이 튜토리얼은 Hibernate를 사용하는 간단한 예제를 보여준다. 우리는 Hibernate가 어떻게 동작하는지를 보여주는 간단한 자바 어플리케이션을 생성시킬 것이다.
(광고 생략...)
개괄
저자: Sebastian Hennebrueder
날짜: December, 19th 2005
사용된 소프트웨어와 프레임워크
Eclipse 3.x
MyEclipse 4.x가 권장되지만 선택사항임
Hibernate 3.x (3.1을 사용함)
소스 코드: http://www.laliluna.de/download/first-hibernate-example-tutorial.zip
소스들은 라이브러리들을 포함하지 않는다. hibernate.org에서 라이브러리들과 당신의 데이터베이스 드라이버를 내려 받고 그것들을 아래에 설명되어 있는 프로젝트에 추가한다. 예제는 당신의 데이터베이스 설정들과 동작하도록 구성되어야 한다! 튜토리얼을 읽기 바란다.
튜토리얼의 PDF 버전: http://www.laliluna.de/download/first-hibernate-example-tutorial-en.pdf
Hibernate2용 이전 PDF 버전: http://www.laliluna.de/download/first-hibernate-2-example-tutorial-en.pdf
짧은 개요
Hibernate는 객체 관계형 매핑을 위한 솔루션이고 영속 관리 솔루션 또는 영속 계층이다. 이것은 아마 Hibernate를 배우는 아무나 이해 가능한 것은 아니다.
당신이 생각할 수 있는 것은 아마 당신이 당신의 어플리케이션에 몇몇 기능들(비지니스 로직)을 갖도록 하고 데이터베이스 내에 데이터를 저장하고 싶어하는 것이다. 당신이 자바를 사용할 때 모든 비지니스 로직은 통상적으로 다른 클래스 타입들인 객체들과 동작한다. 당신의 데이터베이스 테이블들은 전혀 객체들이 아니다.
Hibernate는 데이터베이스 테이블들을 어떤 클래스로 매핑시키는 솔루션을 제공한다. 그것은 데이터베이스 데이터를 어떤 클래스로 복사한다. 반대 방향으로 그것은 객체들을 데이터베이스에 저장하는 것을 지원한다. 이 과정에서 객체는 하나 이상의 테이블들로 전환된다.
저장소에 데이터를 저장시키는 것은 영속이라 명명된다. 그리고 테이블들을 객체들에 복사하는 것 등등은 객체 관계형 매핑이라 명명된다.
Java 프로젝트를 생성한다
Eclipse를 사용하여 새로운 프로젝트를 생성시키기 위해 Ctrl+n (Strg+n) 키를 누른다. Java 프로젝트를 선택한다. 우리는 그것을 FirstHibernateExample라 명명할 것이다.
MyEclipse를 사용하여 Hibernate용 프로젝트를 준비한다
MyEclipse를 사용하고 있다면, 패키지 탐색기 내에서 당신의 프로젝트 상을 마우스 오른쪽 버튼 클릭하고 Add Hibernate capabilities.를 선택한다.
마법사를 계속하고 src 디렉토리 내에 새로운 hibernate.cfg.xml 을 생성시킨다.
마지막 단계에서 당신은 Hibernate SessionFactory를 생성시킬 수 있다. 나는 내 자신의 것을 생성 시키는 것을 선호한다. 당신은 아래에서 그것을 찾을 수 있다.
Hibernate용 프로젝트를 준비한다
당신이 MyEclipse를 사용하고 있지 않을 때 http://www.hibernate.org/ 웹 사이트로부터 Hibernate를 내려 받아라.
파일을 추출한다. Hibernate는 많은 라이브러리들의 목록으로 구성되어 있다. 당신은 그것들 모두를 필요로 하지 않는다. lib 디렉토리 내에 필수적인 것을 설명하고 있는 README 파일이 존재한다. 당신의 프로젝트 properties를 열고, “Java Build Path”를 선택하고, “Add External Jars”을 클릭하고 아래에 보이는 라이브러리들을 당신의 프로젝트 경로에 추가한다.
SessionFactory를 생성시킨다
세션 팩토리는 Hibernate에서 중요하다. 그것은 단위 쓰레드 당 오직 한 개의 세션 인스턴스만이 사용됨을 보증하는 설계 패턴을 구현하고 있다. 당신은 단지 이 팩토리로부터 당신의 Hibernate 세션을 얻을 것이다.
de.laliluna.hibernate 패키지 내에 HibernateSessionFactory로 명명된 클래스를 생성시키고 아래의 소스 코드를 추가한다.
/** * * @author Sebastian Hennebrueder * created Feb 22, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.hibernate; import javax.naming.InitialContext; import org.apache.log4j.Logger; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; /** * @author hennebrueder 이 클래스는 오직 한 개의 SessionFactory 만이 초기화 되고 * 컨피그레이션이 싱글톤으로 쓰레드 안전하게 행해진다는 점을 보증한다. * 실제로 그것은 단지 Hibernate SessionFactory를 포장한다. * JNDI 이름이 구성될 때 세션은 JNDI에 바인드 되고, * 그 밖의 경우 그것은 오직 로컬 상으로 저장된다. * 당신은 임의의 종류의 JTA 또는 Thread transactionFactory들을 사용하는 것이 자유롭다. */ public class InitSessionFactory { /** * Default constructor. */ private InitSessionFactory() { } /** * hibernate.cfg.xml 파일의 위치. 주의: 위치는 Hibernate가 사용하는 classpath 상에 있어야 한다 * #resourceAsStream 스타일은 그것의 구성 컨피그레이션 파일을 검색한다. * 그것은 Java 패키지 내에 있는 config 파일에 위치된다 - * 디폴트 위치는 디폴트 Java 패키지이다.<br> * <br> * 예제: <br> * <code>CONFIG_FILE_LOCATION = "/hibernate.conf.xml". * CONFIG_FILE_LOCATION = "/com/foo/bar/myhiberstuff.conf.xml".</code> */ private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml"; /** hibernate 컨피그레이션의 싱글톤 인스턴스 */ private static final Configuration cfg = new Configuration(); /** hibernate SessionFactory의 싱글톤 인스턴스 */ private static org.hibernate.SessionFactory sessionFactory; /** * 아직 초기화 되지 않았다면 컨피그레이션을 초기화 시키고 현재 인스턴스를 반환한다 * 현재 인스턴스를 반환한다 * * @return */ public static SessionFactory getInstance() { if (sessionFactory == null) initSessionFactory(); return sessionFactory; } /** * ThreadLocal Session 인스턴스를 반환한다. 필요하다면 Lazy는 * <code>SessionFactory</code>를 초기화 시킨다. * * @return Session * @throws HibernateException */ public Session openSession() { return sessionFactory.getCurrentSession(); } /** * 이 메소드의 행위는 당신이 구성했던 세션 컨텍스트에 의존한다. * 이 팩토리는 다음 프로퍼티 is intended to be used with a hibernate.cfg.xml * <property name="current_session_context_class">thread</property>를 * 포함하는 hibernate.cfg.xml과 함께 사용되게 기안되어 있다. 이것은 * 현재의 열려진 세션을 반환할 것이거나 존재하지 않을 경우 새로운 세션을 생성시킬 것이다 * * @return */ public Session getCurrentSession() { return sessionFactory.getCurrentSession(); } /** * 심지어 하나 이상의 쓰레드가 sessionFactory를 빌드하려고 시도하는 경우조차도 * 안전한 방법으로 sessionFactory를 초기화 시킨다 */ private static synchronized void initSessionFactory() { /* * [laliluna] 다시 null을 체크한다 왜냐하면 sessionFactory가 마지막 체크와 현재의 체크 사이에 * 초기화 되었을 수도 있기 때문이다 * */ Logger log = Logger.getLogger(InitSessionFactory.class); if (sessionFactory == null) { try { cfg.configure(CONFIG_FILE_LOCATION); String sessionFactoryJndiName = cfg .getProperty(Environment.SESSION_FACTORY_NAME); if (sessionFactoryJndiName != null) { cfg.buildSessionFactory(); log.debug("get a jndi session factory"); sessionFactory = (SessionFactory) (new InitialContext()) .lookup(sessionFactoryJndiName); } else{ log.debug("classic factory"); sessionFactory = cfg.buildSessionFactory(); } } catch (Exception e) { System.err .println("%%%% Error Creating HibernateSessionFactory %%%%"); e.printStackTrace(); throw new HibernateException( "Could not initialize the Hibernate configuration"); } } } public static void close(){ if (sessionFactory != null) sessionFactory.close(); sessionFactory = null; } }
Log4J 구성하기
당신이 위에서 보았듯이 우리는 log4j 라이브러리를 추가시켰다. 이 라이브러리는 소스 디렉토리 내에 컨피그레이션 파일처럼 행하거나 다음 오류로서 당신을 맞이한다.
log4j:WARN No appenders could be found for logger (TestClient). log4j:WARN Please initialize the log4j system properly.
루트 디렉토리에 log4j.properties로 명명된 파일을 생성시키고 다음을 삽입시킨다:
### direct log messages to stdout ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=debug, stdout log4j.logger.org.hibernate=info #log4j.logger.org.hibernate=debug ### log HQL query parser activity #log4j.logger.org.hibernate.hql.ast.AST=debug ### log just the SQL log4j.logger.org.hibernate.SQL=debug ### log JDBC bind parameters ### log4j.logger.org.hibernate.type=info ### log schema export/update ### log4j.logger.org.hibernate.tool.hbm2ddl=info ### log HQL parse trees #log4j.logger.org.hibernate.hql=debug ### log cache activity ### log4j.logger.org.hibernate.cache=info ### log transaction activity #log4j.logger.org.hibernate.transaction=debug ### log JDBC resource acquisition #log4j.logger.org.hibernate.jdbc=debug ### enable the following line if you want to track down connection ### ### leakages when using DriverManagerConnectionProvider ### #log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
데이터베이스 드라이버를 추가한다
Hibernate는 데이터베이스에 접근할 데이터베이스 드라이버를 필요로 한다. 프로젝트 properties를 열고, “Java Build Path”를 클릭하고, “Add External Jars”를 선택하고 당신의 데이터베이스 드라이버를 추가한다. 당신이 PostgreSQL를 사용할 때 당신은 http://jdbc.postgresql.org에서 당신의 데이터베이스 드라이버를 찾을 수 있고 MySQL을 사용하고 있다면 이곳 http://www.mysql.de/products/connector/j에서 찾을 수 있다.
데이터베이스와 테이블드을 생성시킨다.
Create a database with MySql 또는 PostgreSQL 또는 당신이 좋아하는 DBMS에 데이터베이스를 생성시킨다. 그것을 “firsthibernate”로 명명한다.
PostgreSql을 사용한다면 테이블을 생성시키기 위해 다음 스크립트를 사용하라:
CREATE TABLE "public"."honey" ( id SERIAL, name text, taste text, PRIMARY KEY(id) );
MySql을 사용하고 있다면 다음 스크립트를 사용하라:
CREATE TABLE `honey` ( `id` int(11) NOT NULL auto_increment, `name` varchar(250) default NULL, `taste` varchar(250) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1
클래스를 생성시킨다
Create a new class named “Honey” in the package “de.laliluna.example”. Add three fields id, name and taste and generate (Context menu -> Source -> Generate Getter and Setter) or type the getters and setters for the fields. Then create an empty constructor.
package de.laliluna.example; /** * @author laliluna * */ public class Honey { private Integer id; private String name; private String taste; public Honey(){ } /** * @return Returns the id. */ public Integer getId() { return id; } /** * @param id The id to set. */ public void setId(Integer id) { this.id = id; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } /** * @return Returns the taste. */ public String getTaste() { return taste; } /** * @param taste The taste to set. */ public void setTaste(String taste) { this.taste = taste; } }
매핑 파일들을 생성시킨다
이미 생성되어 있지 않다면 루트 디렉토리에 “hibernate.cfg.xml”로 명명된 새로운 파일을 생성시킨다.
hibernate 파일 내에 다음을 추가한다. 당신의 데이터베이스 구성에 적합하게 username과 password를 변경하는 것을 잊지 말라.
PostgreSQL 버전:
<?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> <property name="connection.url">jdbc:postgresql://localhost/firsthibernate</property> <property name="connection.username">postgres</property> <property name="connection.driver_class">org.postgresql.Driver</property> <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property> <property name="connection.password">p</property> <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <!-- thread is the short name for org.hibernate.context.ThreadLocalSessionContext and let Hibernate bind the session automatically to the thread --> <property name="current_session_context_class">thread</property> <!-- this will show us all sql statements --> <property name="hibernate.show_sql">true</property> <!-- mapping files --> <mapping resource="de/laliluna/example/Honey.hbm.xml" /> </session-factory> </hibernate-configuration>
MySQL 버전:
<?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> <property name="connection.url">jdbc:mysql://localhost/firsthibernate</property> <property name="connection.username">root</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="connection.password">r</property> <property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> <!-- thread is the short name for org.hibernate.context.ThreadLocalSessionContext and let Hibernate bind the session automatically to the thread --> <property name="current_session_context_class">thread</property> <!-- this will show us all sql statements --> <property name="hibernate.show_sql">true</property> <!-- mapping files --> <mapping resource="de/laliluna/example/Honey.hbm.xml" /> </session-factory> </hibernate-configuration>
이 파일은 데이터베이스에 대한 구성 우리의 경우에는 PostgreSQL 데이터베이스의 구성 그리고 모든 매핑 파일들을 포함한다. 우리의 경우 그것은 단지 파일 Honey.hbm.xml이다.
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
태그는 dialect를 구성한다. 당신의 데이터베이스에 맞게 이것을 변경하라. 당신의 데이터베이스를 위한 dialect를 찾기 위해 Hibernate 레퍼런스의 “SQL Dialects” 장에서 찾아보라.
de.laliluna.example 패키지 내에 Honey.hbm.xml을 생성시키고 그것을 다음으로 변경하라:
PostgreSQL 버전:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="de.laliluna.example.Honey" table="honey"> <id name="id" column="id" type="java.lang.Integer"> <generator class="sequence"> <param name="sequence">honey_id_seq</param> </generator> </id> <property name="name" column="name" type="java.lang.String" /> <property name="taste" column="taste" type="java.lang.String" /> </class> </hibernate-mapping>
MySQL 버전:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="de.laliluna.example.Honey" table="honey"> <id name="id" column="id" type="java.lang.Integer"> <generator class="increment"/> </id> <property name="name" column="name" type="java.lang.String" /> <property name="taste" column="taste" type="java.lang.String" /> </class> </hibernate-mapping>
이 파일에서 우리의 클래스 Honey로부터 데이터베이스 테이블 honey로의 매핑이 구성되어 있다.
테스트 클라이언트를 생성한다
“de.laliluna.example” 패키지 내에 Java 클래스 “TestClient”를 생성시킨다.
다음 소스 코드를 추가한다. 그것은 데이터베이스 내에 엔트리들을 생성시키는 메소드, 그것들을 업데이트하고 리스트하는 메소드들을 포함하고 있다.
/** * Test application for example * @author Sebastian Hennebrueder * created Jan 16, 2006 * copyright 2006 by http://www.laliluna.de */ package de.laliluna.example; import java.util.Iterator; import java.util.List; import org.apache.log4j.Logger; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import de.laliluna.hibernate.InitSessionFactory; public class TestExample { private static Logger log =Logger.getLogger(TestExample.class); /** * @param args */ public static void main(String[] args) { Honey forestHoney = new Honey(); forestHoney.setName("forest honey"); forestHoney.setTaste("very sweet"); Honey countryHoney = new Honey(); countryHoney.setName("country honey"); countryHoney.setTaste("tasty"); createHoney(forestHoney); createHoney(countryHoney); // our instances have a primary key now: log.debug(forestHoney); log.debug(countryHoney); listHoney(); deleteHoney(forestHoney); listHoney(); } private static void listHoney() { Transaction tx = null; Session session = InitSessionFactory.getInstance().getCurrentSession(); try { tx = session.beginTransaction(); List honeys = session.createQuery("select h from Honey as h") .list(); for (Iterator iter = honeys.iterator(); iter.hasNext();) { Honey element = (Honey) iter.next(); log.debug(element); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); if (tx != null && tx.isActive()) tx.rollback(); } } private static void deleteHoney(Honey honey) { Transaction tx = null; Session session = InitSessionFactory.getInstance().getCurrentSession(); try { tx = session.beginTransaction(); session.delete(honey); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); if (tx != null && tx.isActive()) tx.rollback(); } } private static void createHoney(Honey honey) { Transaction tx = null; Session session = InitSessionFactory.getInstance().getCurrentSession(); try { tx = session.beginTransaction(); session.save(honey); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); if (tx != null && tx.isActive()) tx.rollback(); } } }
축하합니다. 당신은 Hibernate 세계에서 당신의 첫 번째 단계들을 마쳤습니다.
우리는 당신이 Hibernate 세계에 빠르게 진입하기를 원했다. Hibernate를 사용하는 많은 복잡한 토픽들과 더 나은 구현이 존재한다. 예를 들어, 각각의 메소드 내에서 세션을 열고 닫는 것은 좋은 연습이 아니다. 하나의 세션은 재사용될 수 있으며 그 동안에 많은 시간을 절약한다.
당신이 최상의 실전에 대해 더 많은 것을 배우고자 원할 경우 우리의 세미나 또는 다른 튜토리얼을 살펴보길 바란다.
Copyright and disclaimer
|