하이버네이트에 대하여

hibernate

Hibernate Framework

하이버네이트는 데이터베이스와 상호작용하기위한 자바 어플리케이션 개발자툴이다. 오픈소스이며 가볍고 , ORM(Object Relational Mapping) tool 이다. 하이버네이트는 데이터지속성을 위해 JPA(Java Persistence API)의 기준을 구현한다.

  • ORM Tool

    ORM 툴은 데이터 생성 , 조작 , 접근 등을 간단하게 해준다. 객체를 데이터베이스에 저장된 데이터에 매핑하는 프로그래밍 기술이다.

    Java Application -> Object -> ORM -> Database

    ORM은 내부적으로 데이터베이스와 상호작용 하기 위해 JDBC API를 사용한다.

  • JPA 이란?

    Java Persistence API(JPA)는 특정한 기능성과 ORM 툴의 표준을 제공해주는 자바 명세서이다.

    javax.persistence 패키지는 JPA 클래스들과 인터페이스들을 갖고있다.

 

하이버네이트의 장점

  1. 오픈소스이며 가볍다.

    하이버네이트는 LGPL 라이센스 안에서 오픈소스이며 가볍다.

  2. 빠른 속도

    하이버네이트안에 내부적으로 캐시를 사용하기 때문에 빠른 속도를 가지고 있다. first level cachesecond level cache 두가지 타입의 캐시를 가지고 있다. fisrt level cache는 디폴트다.

  3. 독립적인 데이터베이스 쿼리

    HQL(Hibernate Query Language)는 SQL의 객체지향 버전이다. 데이터베이스의 독립적인 쿼리를 생성해주기 때문에 다른 데이터베이스에 쓰는 특정한 쿼리문을 쓰지 않아도 된다. 만약 프로젝트에서쓰는 데이터베이스가 바뀌면 SQL 쿼리를 바꿔줘야하는 경우가 생기는 경우가 있는데 하이버네이트는 그러지않아도 되서 유지보수에 많은 이점이 있다.

  4. 테이블 자동 생성

    데이터베이스의 테이블을 생성해주는 기능을 제공해준다. 그래서 데이터베이스를 만들 필요가 없다.

  5. 복잡한 Join의 간단함

    여러개의 테이블에서 데이터를 뽑아오는일은 하이버네이트를 사용하면 간단해진다.

  6. 정적쿼리와 데이터베이스 상태를 제공해줌

    하이버네이트는 쿼리 캐시 도와주고 쿼리와 데이터베이스 상태에 관한 정적으로 제공해준다.

 

하이버네이트 구조

하이버네이트는 지속 객체 , 세션 팩토리 , 트랜잭션 팩토리, 커넥션 팩토리 , 세션 , 트랜잭션 등 많은 객체들을 포함하고 있다.

하이버네이트는 1. 자바 어플리케이션 계층 2. 하이버네이트 프레임워크 계층 3. 백엔드 api 계층 4. 데이터베이스 계층으로 4가지 계층으로 나눌 수 있다.

img

 

하이버네이트 필수 라이브러리

  • dom4j
  • Xalan
  • Xerces
  • cglib
  • log4j
  • commons
  • SLF4J

필자가 사용한 Maven

스프링 버전에따라 필수라이브러리가 내장되는 경우도 있다.

하이버네이트 설정

하이버네이트는 자바클래스와 데이터베이스테이블을 어떻게 연동시킬지에 대한 맵핑정보를 정의하는 등 사전에 많은 지식을 필요로 한다. 또한 데이터베이스와 다른 관련 파라미터와 관련된 설정도 필요하다. 이러한 모든 정보는 일반적으로 hibernate.properties라고하는 표준 Java 파일 또는 hibernate.cfg.xml 이라는 XML 파일로 제공된다.

하이버네이트를 설정하기위해 hibernate.cfg.xml 파일을 만들고 수정할 것이다.

하이버네이드 Properties

기본적인 데이터베이스 구성을 설정하려면 아래의 나와있는 프로퍼티들은 중요하다.

  • hibernate.dialect

    이 속성은 선택한 데이터베이스에 관한 SQL문을 적절히 만들어준다.

  • hibernate.connection.driver_class

    JDBC 드라이버 클래스이다.

  • hibernate.connection.url

    데이터베이스 인스턴스에 대한 JDBC URL이다.

  • hibernate.connection.username

    데이터베이스 username

  • hibernate.connection.password

    데이터베이스 비밀번호

  • hibernate.connection.pool_size

    데이터베이스 커넥션풀에서 기다리는 커넥션의 수를 몇개 제한할것인지.

  • hibernate.connection.autocommit

    사용될 JDBC 커넥션에게 autocommit을 허가해준다.

어플리케이션 서버 및 JNDI와 함께 데이터베이스를 사용하는 경우 다음 등록정보를 구성해야한다.

  • hibernate.connection.datasource

    어플리케이션에 사용중인 어플리케이션 서버 컨텍스트에 정의된 이름

  • hibernate.jndi.class

    JNDI의 initialContext 클래스

  • hibernate.jndi.<JNDIpropertynaame>

    JNDI InitialContext에게 전달해주고 싶은 JNDI 속성

  • hibernate.jndi.url

    사용할 JNDI의 URL

  • hibernate.connection.username

    데이터베이스 username

  • hibernate.connection.password

    데이터베이스 비밀번호

MySQL 데이터베이스와 하이버네이트

hibernate.cfg.xml

 

하이버네이트 SessionFactory

SessionFactory는 인터페이스이다. SessionFactory는 hibernate.cfg.xml 파일 또는 hibernate.properties 파일에서 가져온 모든 DB 관련 프로퍼티 세부 정보를 포함하는 Configuration 객체를 제공함으로써 생성 된다. SessionFactory는 Session 객체를 위한 팩토리이다.

모든 애플리케이션에서 데이터베이스 당 하나의 SessionFactory 구현을 생성할 수 있다. 애플리케이션이 여러 데이터베이스를 참조하는 경우 데이터베이스 당 하나의 SessionFactory를 만들어야 한다.

SessionFactory는 좀 무거운 객체이다. 일반적으로 애플리케이션이 시작하는 동안 만들어지고 나중에 사용하기 위해 보관된다. SessionFactory는 스레드 안전 객체이며 애플리케이션의 모든 스레드에서 사용된다.

하이버네이트 Sessions

세션은 데이터베이스와 물리적 연결을 얻는데 사용된다. 세션객체는 가볍고 데이터베이스와 상호 작용이 필요할 때마다 인스턴스화되도록 설계되어있다. persistent 객체는 세션 객체를 통해 저장되고 검색된다.

세션 객체는 일반적으로 스레드로부터 안전하지 않기 때문에 오랫동안 열어두면 안되고, 필요에따라 생성하고 없애야한다. 세션의 주요기능은 매핑된 Entity 클래스(DB테이블과 매칭되는 오브젝트) 의 인스턴스에 대한 오퍼레이션을 제공, 생성 , 읽기 및 삭제하는 것이다.

인스턴스는 특정 시점에서 다음 세가지 상태 중 하나로 존재할 수 있다.

  • transient

    세션과 관련이없고 데이터베이스에 표현이 없고 식별자(Primary 키 값) 값이 없다.

  • persistent

    Persistent 인스턴스는 식별자 값(Primary 키 값)인 데이터베이스 표현을 가지며 세션과 연관된다.

  • detached

    하이버네이트 세션을 닫으면 persistent 인스턴스는 detached 인스턴스가 된다.

만약 persistent 클래스가 직렬화가 가능하다면 세션 instance도 직렬화가 가능하다. 일반적인 트랜잭션은 다음과 같은 코드를 사용해야한다.

만약 세션이 예외를 던지면 트랜잭션을 롤백해야하며 세션을 버려야한다.

세션 인터페이스 메소드

세션 인터페이스가 제공하는 메소드는 많이 있지만, 몇 가지 중요한 메소드만 나열 할 것이다.

  • Transaction beginTransaction()

    작업을 시작하고 연관된 트랜잭션 오브젝트를 리턴함, 트랜잭션을 활성화하고 DB 상호 작용이 완료되면 반환 된 트랜잭션 객체에 대해 commit() 메소드를 호출해야한다. 문제가 발생하면 트랜잭션 객체에서 rollback()를 호출해야하낟.

  • void cancleQuery()

    현재 실행한 쿼리를 취소한다.

  • void clear()

    세션을 완전히 지운다.

  • Connection close()

    JDBC 연결을 해제 및 정리 후 세션을 종료한다

  • Criteria createCriteria(Class persistentClass)

    지정된 엔티티 클래스또는 엔티티 클래스의 부모클래스에 대해 새로운 Criteria 인스턴스를 만든다.

  • Criteria createCriteria(String entityName)

    지정된 엔티티 이름에 대한 새로운 Criteria 인스턴스를 만든다

  • Serializable getIdentifier(Object object)

    세션과 관련이 있는 지정된 엔티티의 식별자 값을 리턴한다.

  • SQLQuery createSQLQuery(String queryString)

    주어진 queryString으로 새로은 SQL쿼리 인스턴스를 만든다.

  • void delete(Object object)

    DB에서 persistent 인스턴스를 삭제

  • Query createQuery(String queryString)

    주어진 queryString으로 새로운 쿼리의 인스턴스를 만든다.

  • save()

    먼저 생성된 식별자를 할당하여 주어진 transient 인스턴스를 persist화 한다.

  • update()

    persistent 인스턴스를 주어진 detached 인스턴스 식별자로 update 한다.

  • saveOrUpdate()

    저장되지 않는 값 확인의 방법에 따라 지정된 인스턴스를 save 하거나 update 한다. 연결이 cascade="save-update"로 매핑된 경우 이 작업은 점차 진행된다.

  • merge()

    Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".

    - persist()

    Make a transient instance persistent. This operation cascades to associated instances if the association is mapped with cascade="persist".

    flush()

    Force this session to flush. Must be called at the end of a unit of work, before committing the transaction and closing the session. Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.

    delete()

    Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving Session or a transient instance with an identifier associated with existing persistent state. This operation cascades to associated instances if the association is mapped with cascade="delete".

 

Persistent 클래스

하이버네이트의 전체 개념은 자바 클래스 속성에서 값을 가져와서 데이터베이스 테이블에 넣어주는(persist) 것이다. 매핑 문서는 하이버네이트가 클래스로부터 값을 가져오는 방법을 결정하고 테이블과 관련 필드로 매핑하는 것을 도와준다.

객체나 인스턴스가 데이터베이스 테이블에 저장될 자바 클래스는 하이버네이트에서 persistent 클래스라고 부른다. 하이버네이트는 POJO(Plain Old Java Object) 프로그래밍 모델이라고도 하는 간단한 규칙을 따르는 것이 가장 좋다.

persistent 클래스의 주요 규칙은 다음과 같다. 그러나 규칙들 중 어느 것도 필수는 아니다.

  • persistent 클래스가 될 자바 클래스는 디폴트 생성자가 있어야한다
  • 하이버네이트와 데이터베이스 내에 객체를 쉽게 식별 할 수 있도록 모든 클래스는 ID를 포함해야 한다. 이 등록 정보는 데이터베이스 테이블의 기본 키 (Primary key)에 매핑된다
  • persistent를 사용할 속성에는 javaBean 스타일로 private인 getter와 setter를 필요로 한다
  • 하이버네이트의 주요 특징인 프록시는 persistent 클래스가 접근자가 final이 아니거나 모든 public 메소드를 선언하는 인터페이스의 구현에 의존한다.

간단한 POJO 예제

위에 언급한 몇개의 규칙을 기본으로 다음과 같은 POJO 클래스를 정의할 수 있다.

 

Mapping Files

객체 / 관계형 매핑은 주로 XML 문서에서 정의된다. 이 매핑 파일은 하이버네이트에게 클래스들을 매핑하는 방법을 적어놓는다.

많은 하이버네이트 사용자들이 XML을 직접 작성하기로 선택하지만, 매핑 문서를 생성하기위한 많은 도구가 존재한다. 여기에는 고급 하이버네이트 사용자를 위한 XDoclet, Middlegen 및 AndroMDA도 있다.

앞전에 만든 POJO 클래스를 살펴보자

지속성(persistence)를 제공하려는 각 오브젝트에 해당하는 하나의 테이블이 있다. 위에 객체를 다음 RDBMS 테이블에 저장하고 가져온다고 생각해보자.

위의 두 엔티티를 기반으로 하이버네이트에게 정의 된 클래스를 데이터베이스 테이블에 매핑하는 방법을 알려주는 매핑 파일을 정의 할 수 있다.

<classname>.hbm.xml 형식의 파일 매핑문서로 저장해야 한다. Employee.hbm.xml 파일 매핑 문서로 저장하자.

  • 맵핑문서는 <hibernate-mapping>을 루트 엘리먼트로 가지는 XML 문서이다.
  • <class> 엘리먼트는 자바클래스에서 데이터 테이블로의 특정한 매핑을 정의할때 사용한다. class 엘리먼트의 name 속성을 이용해서 자바 클래스를 명시해주고 (패키지 포함해서), 데이터베이스 테이블이름은 table 속성으로 명시해준다.
  • <meta> 엘리먼트는 선택적이다. 클래스에 대한 설명을 만들때 사용한다.
  • <id> 엘리먼트는 클래스의 고유 ID 속성을 데이터베이스 테이블의 기본키에 매핑한다. id 엘리먼트의 name 속성은 클래스의 property를 참조하고 column 속성은 데이터베이스의 열을 참조한다. type 속성은 하이버네이트 매핑타입을 가지고 있으며, 이 매핑 타입은 자바에서 SQL 데이터 타입으로 변환할 것이다.
  • id 엘리먼트 내의 <generator> 엘리먼트는 기본키 값을 자동으로 생성하는데 사용된다. generator 엘리먼트의 클래스 속성은 기본 데이터베이스의 기능에 따라 기본키를 만들기 위해 하이버네이트가 identity , sequence 또는 hilo 알고리즘을 선택하도록 natvie로 설정된다.
  • <propery> 엘리먼트는 자바 클래스 속성을 데이터베이스 테이블의 열에 매핑하는데 사용된다. name 속성은 poperty를 참조하고 column 속성은 데이터베이스의 열을 참조한다. type 속성은 하이버네이트 매핑타입을 가지고 있으며, 이 매핑 타입은 JAVA에서 SQL 데이터 타입으로 변환 될것이다.

이 외에도 많은 엘리먼트 속성들이 많다.

 

하이버네이트 실행하기위한 main 클래스

위에 예제를 천천히 따라오면서 파일이 다 있는지 확인해보자

  • Employee.java

    DTO 역할을 해주는 persistent 클래스

  • Employee.hbm.xml

    하이버네이트에게 정의 된 클래스를 데이터베이스 테이블에 매핑하는 방법을 알려주는 매핑 파일

  • hibernate.cfg.xml

    하이버네이트의 설정파일이 담겨있는 설정파일

main 클래스 생성

마지막으로 main() 메소드를 만들고 실행 해 볼것이다. Employee의 레코드를 저장한 다음 CRUD를 적용해 볼 것이다.

컴파일 및 실행

위에 언급한 어플리케이션을 컴파일하고 실행하기 위한 단계들이다. 컴파일 및 실행을 하기전에 PATH 설정을 적절하게 했는지 확인하자.

  • hibernate.cfg.xml 구성 파일 생성
  • Employee.hbm.xml 매핑 파일 생성
  • Employee.java 소스 파일 생성
  • ManageEmployee.java 파일 생성
  • ManageEmployee 실행

결과

 

O/R 매핑

지금까지 하이버네이트에 사용하는 가장 기본적인 O/R 매핑을 공부했다. 그러나 우리가 디테일하게 배워야할 중요한 3가지 매핑이 있다.

  • collections 매핑 (Collections Mappings)
  • 엔티티 클래스간의 매핑 (Association Mappings)
  • 컴포넌트 매핑 (Component Mappings)

Collections 매핑

엔티티또는 클래스가 특정 변수에 대한 값의 collection을 가지고 있으면, 자바에서 사용 가능한 collection 인터페이스 중 하나를 사용하여 그 값을 매핑할 수 있다. 하이버네이트는 java.util.Map , java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List의 인스턴스와 persistent 엔티티 또는 값의 배열을 persist(지속화) 할 수 있다.

  • java.util.Set

    <set> 엘리먼트와 매핑되고 java.util.HashSet으로 초기화 된다.

  • java.util.SortedSet

    <set>엘리먼트와 매핑되고 java.util.TreeSet으로 초기화 된다. sort 속성은 비교 자 또는 자연 순서대로 설정할 수 있다.

  • java.util.List

    <list>엘리먼트와 매핑되고 java.util.ArrayList로 초기화 된다.

  • java.util.Collection

    <bag>엘리먼트나 <ibag> 엘리먼트와 매핑되고 java.util.ArrayList로 초기화 된다.

  • java.util.Map

    <map> 엘리먼트와 매핑되고 java.util.TreeMap으로 초기화된다.

배열은 하이버네이트에서 자바 primitive 값 타입에 대해 <primitive-array>를 사용하고 다른 모든 경우에는 <array>를 사용하여 지원된다. 그러나 이런것들은 거의 사용되지 않는다.

하이버네이트에 의해 직접적으로 지원되지 않는 사용자 정의 collection 인터페이스를 매핑하고자 하면 하이버네이트에게 사용자 정의 collection 의미에 대해 알려줘야한다. 하지만 이런 방법은 어려워서 사용을 권장하지 않는다.

Assocation 매핑

엔티티 클래스와 테이블 관계 매핑은 ORM의 가장 중요한 요소다. 다음은 객체 사이의 관계를 표현할 수 있는 네가지 방법이 있다. 연관 매핑은 양방향 일 수도있고, 단방향 일 수도 있다.

  • Many-to-One
  • One-to-One
  • One-to-Many
  • Many-to-Many

컴포넌트 매핑

엔티티 클래스가 다른 클래스에 대한 참조를 멤버 변수로 가질 수 있다. 참조 된 클래스가 자신의 라이플 사이클을 가지지 않고 소유하는 엔티티 클래스의 라이프 사이클에 완전히 의존한다면, 참조된 클래스는 컴포넌트 클래스라고 불린다.

 

하이버네이트 어노테이션

지금까지 하이버네이트가 POJO에서 데이터베이스 테이블로 데이터를 변환하기 위해 XML 매핑 파일을 사용하는 방법을 보았다. 하이버네이트 어노테이션은 XML 파일을 사용하지 않고 매핑을 정의하는 가장 새로운 방법이다.

하이버네이트 어노테이션은 객체 및 관계형 테이블 매핑을 위한 메타 데이터를 제공하는 강력한 방법이다. 모든 메타 데이터는 코드와 함께 POJO 자바 파일에 포함되어 있으며 개발 중에 테이블 구조와 POJO를 동시에 이해할 수 있다.

어플리케이션을 다른 EJB 3 호환 ORM 어플리케이션으로 이식 할 수 있게하려면 주석을 사용하여 매핑 정보를 나타내야하지만, 더 큰 유연성을 원한다면 XML 기반 매핑을 사용해야 한다.

하이버네이트를 위한 환경 설정

우선, JDK 5.0을 사용하고 있는지 확인하고 JDK5.0 이상으로 잡아주자 그리고 Hiberante 3.x 어노테이션 패키지를 설치해야한다. Maven이나 라이브러리에 hibernate-annotaions.jar , hibernate-commons-annotations.jar , ejb3-persistence 를 추가하자.

어노테이션 예제

위에서 언급했듯이, 모든 메타 데이터는 코드와 함께 POJO 자바 파일에 포함되어있다. 개발 중에 동시에 테이블 구조와 POJO를 이해하는데 도움이 된다

다음 EMPLOYEE 테이블을 사용하여 객체를 저장한다고 생각하자.

다음은 주석이 있는 Employee 클래스를 EMPLOYEE 테이블로 매핑하기위한 어노테이션들이다.

하이버네이트는 @Id 주석이 필드에 있으면 감지하여 런타임시 필드를 통해 객체의 프로퍼티에 직접 액세스해야한다고 말해준다. @Id 주석을 getId() 메소드에 배치하면 기본적으로 getter 및 setter 메소드를 통해 프로퍼티에 접근할 수 있다. 따라서 모든 주석은 필드에 붙이거나 getter 메소드에 붙여도 된다.

@Entity 어노테이션

EJB 3 표준 어노테이션은 javax.persistence 패키지에 포함되어 있으므로 패키지를 import 해주자. 다음으로 Employee 클래스에 @Entity 어노테이션을 달아주자, 이 클래스는 Entity 빈이므로 접근자가 최소 protected인 빈 생성자가 하나 있어야한다.

@Table 어노테이션

@Table 어노테이션을 사용하면 데이터베이스에서 엔티티를 persist화 할 때 사용될 테이블의 세부사항을 지정할 수 있다.

@Table 주석은 네 가지 속성을 제공하기 때문에 테이블의 이름 , 카탈로그 및 스키마 그리고 테이블 열의 제약 조건을 override가 가능하다. 지금은 EMPLOYEE 라는 테이블 이름만 사용하고 있다.

@Id 와 @GeneratedValue 어노테이션

각각의 엔티티는 기본 키를 가지는데 이때 @Id 어노테이션을 사용하여 어떤 필드가 기본키 인지 알려줄 수 있다. 기본키는 테이블 구조에 따라 한 개 일수도 여러 개 일수도 있다.

기본적으로 @Id 어노테이션은 사용할 가장 적합한 기본 키 생성 전략을 자동으로 결정하지만, @GeneratedValue 주석을 적용하여 재정의 할 수 있다. 여기서는 재 정의 하지 않겠다.

@Column 어노테이션

@Column 어노테이션은 필드 또는 프로퍼티에 매핑 될 열의 세부정보를 지정하는데 사용된다 다음과 같이 가장 일반적으로 사용되는 속성과 함께 어노테이션을 사용할 수 있다.

  • name

    명시적으로 컬럼 이름을 구별해준다.

  • length

    특히 String 값에 대한 값을 매핑하는데 사용되는 열의 크기를 조절한다.

  • nullable

    스키마가 생성 될 때 컬럼이 NOT NULL로 표시되도록 한다.

  • unique

    unique 한 값을 갖도록 한다.

 

마지막으로 어플리케이션을 실행하기 클래스를 만들자.

hibernate.cfg.xml

마지막에 Employee.hbm.xml 을 삭제하거나 주석처리하자.

컴파일 및 실행

위에 언급한 어플리케이션을 컴파일하고 실행하기 위한 단계들이다. 컴파일 및 실행을 진행하기 전에 PATH 밑 ClassPath를 정확히 설정했는지 확인하자.

  • Employee.hbm.xml 매핑 파일 삭제
  • 위와 같이 Employee.java 소스 파일을 생성
  • 위와 같이 ManageEmployee.java 소스 파일을 생성
  • ManageEmployee 메인 메소드 실행

다음과 같은 결과를 얻을 것이고, EMPLOYEE 테이블에 값이 넣어질 것이다.

 

 

 

댓글

이 블로그의 인기 게시물

Filter url 제외시키기

[Spring,Java] Validator 구현하기

[Spring] Mock framework에 대하여