프로그래밍n학습자료(2018~)/Hibernate

[Hibernate]1. Hibernate(하이버네이트) ORM 시작 , 예제

단세포소년 2018. 3. 8. 16:48
반응형

참고

http://www.javamakeuse.com/2015/03/tutorial-hibernate-4-subselect-fetching.html

https://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/

https://stackoverflow.com/questions/32984799/fetchmode-join-vs-subselect

http://kwonnam.pe.kr/wiki/java/jpa/one-to-one

https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

https://stackoverflow.com/questions/21762328/java-hibernate-onetoone-mapping

https://www.journaldev.com/2916/hibernate-one-to-one-mapping-example-annotation

https://dzone.com/tutorials/java/hibernate/hibernate-example/hibernate-mapping-one-to-one-using-annotations-1.html

http://www.baeldung.com/hibernate-one-to-many

https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/

https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/

http://jdm.kr/blog/141

http://websystique.com/hibernate/hibernate-one-to-one-unidirectional-with-shared-primary-key-annotation-example/

https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

https://www.mkyong.com/hibernate/hibernate-many-to-many-relationship-example-annotation/

http://www.baeldung.com/hibernate-many-to-many

http://websystique.com/hibernate/hibernate-many-to-one-bidirectional-annotation-example/

https://stackoverflow.com/questions/3585034/how-to-map-a-composite-key-with-hibernate

https://vladmihalcea.com/the-best-way-to-map-a-composite-primary-key-with-jpa-and-hibernate/

https://www.callicoder.com/hibernate-spring-boot-jpa-composite-primary-key-example/

http://www.javainterviewpoint.com/hibernate-composite-primary-key-tutorial/

https://dwuysan.wordpress.com/2012/02/22/joincolumn-is-part-of-the-composite-primary-keys/

http://www.javawebtutor.com/articles/hibernate/hibernate_query_language_hql_example.php

 

https://www.javatpoint.com/hibernate-tutorial

 

 

오랜만에 글을 올린다. 대부분의 글은 원노트에서 작성하고 블로그에 올리려고 했는데 티스토리의 Blog API가 없어져서 그림있는 건 올리기 불편하다.


글쓴이가 처음으 코드 하이라이트를 사용해 봤다. 또한 어떤 글꼴이 가독성이 좋은 테스트하다 보니 폰트가 제각각일 수 있다.

 

Hibernate ORM 프로젝트에 자주 적용하며 알게 내용을 정리해 보았다. 많은 기능이 있지만 글쓴이가 자주 사용하는 기능 위주로 작성하였다.

 

의식의 흐름대로 작성한 내용도 많이 존재한다.

 

 

 

Hibernate ORM

Hibernate ORM 자바 언어를 위한 객체 관계 매핑 프레임워크이다.

간단히 말해 관계형 디비 테이블을 자바 객체로 맵핑 시켜 사용하겠다는 것이다.

 

사용하는 여러가지 이유가 있겠지만 글쓴이의 경우 재사용성과 디비 종류 변경시 대응, 쿼리 결과를 자바 객체로 바로 매핑되어 사용하기 편하기 때문에 이용한다. 또한 연결풀등 신경쓸께 별로 없다.

 

글에서는 중점적으로 다룰 내용은 어노테이션을 통해 자바 객체와 테이블 관계를 맺는 예제와 HQL 이용하는 예제, 기능들이다.

 

 

키워드

OneToOne, OneToMany, ManyToOne, ManyToMany, Primary Key, Composite Primary Key, join table, SubSelect, NamedNativeQuery, Unidirectional, Bidirectional , HQL, Fetch LAZY, Fetch EAGER, orphanRemoval, Cascade, Extends Dialect, Column LAZY Loading ....

 

 

 

 

ORM 장점/단점

장점

-재사용성이 좋음

-쿼리 많이 몰라도

-객체로 쿼리 결과가 자동으로 맵핑되므로 편함

-DB 종류 바뀌어도 대응이 쉬움

 

 

단점

-원시적으로 다가가고 싶을 힘듬, nativeSQL기능이 있긴한데 이거 쓰면 ORM쓰는 이유가 있나 싶다.

-성능을 위해서는 쿼리를 알긴 해야함.

-hibernate 지원하지 않는 sql function Dialect를 상속받아 등록해야함, 예를 들어 Bitwise(비트연산)자가 hibernate 해석을 못해 dialect 상속받고 function 마냥 만들어서 썼음.

 

 

 

 

 

 

 

 

 

라이브러리 다운로드

http://hibernate.org/orm/ : hibernate ORM 다운로드

 

 

DB Connection Pool

DB 연결을 효율적으로 관리하고 연결끊김시 자동으로 연결해주는 도구이다. Hibernate ORM 기본 Connection Pool c3p0 있지만 이는 개발용이지 서비스용은 아니다.

 

글쓴이는 vibur 라는 DB Connection Pool 사용한다.

 

 

 

Hibernate 사용을 위한 라이브러리

hibernate

vibur-dbcp

vibur-object-pool

vibur-dbcp-hibernate5

concurrentlinkedhashmap-lru

slf4j-api

log4j-api

log4j-core

log4j-slf4j-impl

 

아래는 글쓴이의 Gradle 의존 설정(build.gradle)이다.

hibernate 기본적으로 slf4j 통해 로그를 기록한다. 예제 환경에서 로그를 남기기 싫다면

slf4j-api 대신 slf4j-simple 의존시키면 된다.

 

dependencies {

    // This dependency is exported to consumers, that is to say found on their compile classpath.

    api 'org.apache.commons:commons-math3:3.6.1'

 

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.

    implementation 'com.google.guava:guava:21.0'

 

    // Use JUnit test framework

    testImplementation 'junit:junit:4.12'

   

    // Json Paser

    compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.0'

    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.0'

    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.0'

   

   

    // Netty

    compile group: 'io.netty', name: 'netty-all', version: '4.1.14.Final'

   

   

    //hibernate

    compile fileTree(dir: 'libs/hibernate/required', include: ['*.jar'])

    compile fileTree(dir: 'libs/hibernate/optional', include: ['*.jar'])

    compile fileTree(dir: 'libs/hibernate/optional/ehcache', include: ['*.jar'])

    compile fileTree(dir: 'libs/hibernate/optional/infinispan', include: ['*.jar'])

    compile fileTree(dir: 'libs/hibernate/optional/proxool', include: ['*.jar'])

    compile fileTree(dir: 'libs/hibernate/optional/c3p0', include: ['*.jar'])

   

    //vibur

    compile group: 'com.googlecode.concurrentlinkedhashmap', name: 'concurrentlinkedhashmap-lru', version: '1.4.2'

    compile group: 'org.vibur', name: 'vibur-dbcp', version: '19.1'

    compile group: 'org.vibur', name: 'vibur-object-pool', version: '19.1'

    compile group: 'org.vibur', name: 'vibur-dbcp-hibernate5', version: '19.1'

   

    // mysql jdbc

    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.43'

   

    // log

    compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.8.2'

    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'

    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.8.2'

    compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'

 

   // compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25'

   

}

 

 

 

 

Hibernate 설정 ( hibernate.cfg.xml)

글쓴이의 Hibernate 설정 예이다.

 

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration SYSTEM

"http://www.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.connection.password">dbapasword</property>

            <property name="hibernate.connection.url">jdbc:mysql://192.168.0.49:3306/DATABASE_NAME?useSSL=false&amp;characterEncoding=UTF-8</property>

            <property name="hibernate.default_schema">DATABASE_NAME</property>

            <property name="hibernate.connection.username">dba</property>

           

            <property name="hibernate.connection.CharSet">UTF-8</property>

            <property name="hibernate.connection.characterEncoding">UTF-8</property>

            <property name="hibernate.connection.useUnicode">true</property>

           

                       <!-- SQL dialect

                     <property name="dialect">org.hibernate.dialect.MySQL57Dialect</property>

                     -->

             <property name="dialect">org.shh.db.MySQL57Dialect</property>

 

 

 

<!-- Enable Hibernate's automatic session context management -->

                           <property name="current_session_context_class">thread</property>

 

 

<!-- JDBC connection pool (use the built-in) -->

                <!-- <property name="connection.pool_size">1</property>-->

 

 

 

            <!-- Vibur DBCP specific properties: -->

                           <property name="hibernate.connection.provider_class"> org.vibur.dbcp.integration.ViburDBCPConnectionProvider</property>

                    <property name="hibernate.vibur.poolInitialSize">30</property>

                    <property name="hibernate.vibur.poolMaxSize">30</property>

                    <property name="hibernate.vibur.connectionIdleLimitInSeconds">30</property>

                    <property name="hibernate.vibur.testConnectionQuery">isValid</property>

                    

                    <property name="hibernate.vibur.logQueryExecutionLongerThanMs">500</property>

                    <property name="hibernate.vibur.logStackTraceForLongQueryExecution">true</property>

                    <property name="hibernate.vibur.statementCacheMaxSize">200</property>                

 

 

 

            <!-- Echo all executed SQL to stdout -->

            <property name="show_sql">true</property>

<property name="format_sql">true</property>

<property name="use_sql_comments">false</property>

 

<!-- Table Class -->

                         <mapping class="org.shh.db.table.Alm_History"/>

                         

                         <!-- View Class -->

                         <mapping class="org.shh.db.table.Field_Info_View"/>

 

        </session-factory>

    </hibernate-configuration>

 

 

 

 

Hibernate 간단 사용

hibernate 설정 초기화

SessionFactory sessionFactory = null;

StandardServiceRegistry registry = null;

 

registry = new StandardServiceRegistryBuilder().configure(new File("hibernate 설정 파일 경로"))

.build();

sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

hibernate 설정 파일을 통해 초기화하고 세션팩토리를 생성하는 법이다.

작업은 보통 DB 한번의 작업이면 된다. seesionFactory 통해 세션 연결을 얻어와서 쿼리를 실행한다.

 

 

hibernate 통한 쿼리 실행

 

Session session = sessionFactory.openSession();

 

Transaction tx=null;

 

tx = session.beginTransaction();

 

session.saveOrUpdate(obj);

 

tx.commit();

 

session.close();

seesionFactory 통해 세션 연결을 얻어와서 쿼리를 실행한다. 세션을 사용후에는 close()해주면 된다.

 

 

 

Hibernate 객체 맵핑시키기

일단 예제를 위한 테이블 스키마

CREATE TABLE `person` (

  `idx` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(45) CHARACTER SET utf8 DEFAULT NULL,

  `age` int(11) NOT NULL DEFAULT '0',

  `create_at` datetime DEFAULT NULL,

  PRIMARY KEY (`idx`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

객체 생성 어노테이션을 통한 맵핑

맵핑 디폴트 생성자가 존재하여야 한다. 주의하자.

package org.onecellboy.db.hibernate.table;

 

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;

 

@Entity

@Table(name = "person")

public class Person {

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY)

@Column(name = "idx",columnDefinition="int")

private int idx;

 

@Column(name = "name",columnDefinition="VARCHAR(45)")

private String name;

 

@Column(name = "age",columnDefinition="int")

private int age;

 

@Column(name = "create_at",columnDefinition="DATETIME")

private Date create_at;

 

public int getIdx() {

return idx;

}

 

public void setIdx(int idx) {

this.idx = idx;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public int getAge() {

return age;

}

 

public void setAge(int age) {

this.age = age;

}

 

public Date getCreate_at() {

return create_at;

}

 

public void setCreate_at(Date create_at) {

this.create_at = create_at;

}

}

 

 

hibernate.cfg.xml 설정에 맵핑 클래스를 추가하자.

<mapping class="org.onecellboy.db.hibernate.table.Person"/>

 

 

 

테스트 코드

package org.onecellboy.db.hibernate;

 

import java.io.File;

import java.util.Date;

 

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.boot.MetadataSources;

import org.hibernate.boot.registry.StandardServiceRegistry;

import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import org.junit.BeforeClass;

import org.junit.Test;

import org.onecellboy.db.hibernate.table.Person;

 

public class HibernateTest {

 

static SessionFactory sessionFactory = null;

static StandardServiceRegistry registry = null;

 

@BeforeClass

public static void init()

{

 

System.setProperty("log4j.configurationFile", "./conf/hibernate/log4j2.xml");

 

registry = new StandardServiceRegistryBuilder().configure(new File("./conf/hibernate/hibernate.cfg.xml")) .build();

 

sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();

 

 

}

 

 

 @Test

  public void test1()

  {

 Session openSession = sessionFactory.openSession();

 Transaction tx=null;

 

 Person person = new Person();

 person.setAge(10);

 person.setCreate_at(new Date());

 person.setName("소년");

 

 tx= openSession.beginTransaction();

 

 openSession.save(person);

 

 int person_idx = person.getIdx();

 System.out.println("person idx = "+person_idx);

 System.out.println("----------");

 

 person=null;

 person = openSession.get(Person.class, person_idx);

 

 System.out.println("person idx = "+person.getIdx());

 System.out.println("person age = "+person.getAge());

 System.out.println("person create_at = "+person.getCreate_at());

 System.out.println("person name = "+person.getName());

 

 

 tx.commit();

 openSession.close();

  }

}

 

결과

Hibernate:

    insert

    into

        person

        (age, create_at, name)

    values

        (?, ?, ?)

person idx = 1

----------

person idx = 1

person age = 10

person create_at = Thu Dec 28 16:16:51 KST 2017

person name = 소년


반응형