참고
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
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/
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&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 = 소년 |
'프로그래밍n학습자료(2018~) > Hibernate' 카테고리의 다른 글
[Hibernate] 6. Hibernate(하이버네이트) 테이블 관계 - Many To Many (0) | 2018.03.08 |
---|---|
[Hibernate] 5. Hibernate(하이버네이트) 테이블 관계 - One To Many ( 중간 관계 테이블 있을 시) (0) | 2018.03.08 |
[Hibernate] 4. Hibernate(하이버네이트) 테이블 관계 - One To Many ( 중간 관계 테이블 없을 시) (0) | 2018.03.08 |
[Hibernate] 3. Hibernate(하이버네이트) 테이블 관계 - One To One (0) | 2018.03.08 |
[Hibernate] 2. Hibernate(하이버네이트) 테이블 관계 맵핑-단방향/양방향 (0) | 2018.03.08 |