쏘댕

[Hibernate] 하이버네이트 - 큐브리드 본문

공부/Java

[Hibernate] 하이버네이트 - 큐브리드

ssodang 2015. 9. 1. 15:06


하이버네이트로 개발하기 위해 테스트 테이블을 만들고, CRUD를 실행해보쟈

DB는 CUBRID



이름 그대로 test_table을 만들고 몇가지 앞으로 필요한 데이터형을 확인하기 위해 bigint, varchar, datetime을 사용했다.

test_enum은 java enum을 넣기 위해 추가했다.


[!] 참고

처음에는 reg_date 컬럼명을 그냥 date로 했었다.

근데 요게 테이블 생성은 되는데, 하이버네이트가 만든 쿼리를 날리니까 에러가 난다 ㅎㅎ


TestModel 클래스는 똑같이 매핑되도록 아래와 같이 한다.

(생성자는 편의를 위해서 만들어둠!)

TestEnum은 그냥 Enum이니까 생략

TestModel.java

public class TestModel {
private long id;
private String name;
private Date date;
private TestEnum testEnum;

public TestModel() {
}

public TestModel(long id, String name, Date date, TestEnum testEnum) {
this.id = id;
this.name = name;
this.date = date;
this.testEnum = testEnum;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getDate() {
return date;
}

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

public TestEnum getTestEnum() {
return testEnum;
}

public void setTestEnum(TestEnum testEnum) {
this.testEnum = testEnum;
}
}


그리고!

TestModel.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.ssodang.hibernate.model">
<class name="TestModel" table="test_table">
<id name="id" type="java.lang.Long" column="id">
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String" column="name"></property>
<property name="date" type="java.util.Date" column="reg_date"></property>
<property name="testEnum" column="test_enum">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.ssodang.hibernate.model.TestEnum</param>
<param name="useNamed">true</param>
</type>
</property>
</class>
</hibernate-mapping>

[!] 참고

useNamed : true 파라미터 셋팅을 안하면 DB에 Enum 숫자로 쌓인다.

ex) TestEnum { TEST_A, TEST_B }  =>  if (useNamed == false) 0, 1  /  (useNamed true) 'TEST_A', 'TEST_B'


설정에 위 xml을 추가한다

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">cubrid.jdbc.driver.CUBRIDDriver</property>
<property name="connection.url"><!-- db connection url --></property>
<property name="connection.username"><!-- user name --></property>
<property name="connection.password"><!-- password --></property>
<property name="dialect">org.hibernate.dialect.CUBRIDDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">10</property>
<property name="current_session_context_class">thread</property>
<!-- Mapping files will go here.... -->
<mapping resource="TestModel.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>


Test를 해보쟈

package com.ssodang.hibernate.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.ssodang.hibernate.model.TestEnum;
import com.ssodang.hibernate.model.TestModel;

/**
* Created by SSODANG on 2015-08-31.
*/
public class HibernateCRUDTest {

@Test
public void insertTest() {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();

TestModel testModel = new TestModel(1, "test", new Date(), TestEnum.TEST_A);
session.save(testModel);

session.getTransaction().commit();
}
}


잘 들어가는 것 확인!!


Enum Class를 모델 안에 선언해보니 안되는 것 같아서 수정도 해봐야겠따

오호

<class name="TestModel" table="test_table">
<id name="id" type="java.lang.Long" column="id">
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String" column="name"></property>
<property name="date" type="java.util.Date" column="reg_date"></property>
<property name="testEnum" column="test_enum">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.ssodang.hibernate.model.TestModel$TestEnum</param>
<param name="useNamed">true</param>
</type>
</property>
</class>


com.ssodang.hibernate.model.TestModel.TestEnum 이라서 안된거였다 @_@

com.ssodang.hibernate.model.TestModel$TestEnum 이렇게 $로 해야되는구나


CRUD 다 안하고 insert 만 해봤지만 여기까지 정리 끝!


요거 싱기하네


==================================================================


추가!!


클래스 내의 커스텀 클래스!

예를들어 TestModel에 생성한 Date뿐만 아니라 생성한 Member도 추가하고 싶다면!

"test_table"에는 reg_user(통용되는 유저 id), reg_user_uid(유저의 unique key) 요렇게 두 컬럼을 추가


[!] 참고

=> Member 테이블을 내가 같은 DB에 관리하고 있다면 uid만 저장해도 되지만,

유저 정보를 내가 관리하지 않는 별도의 회원DB에서 필요할 때에만 API를 통해 가져오고 저장하지 않기 때문에

reg_user에는 마스킹된 id (ex. 'ssod***@email.com') 만 남기고 reg_user_uid를 별도로 남겼다.

그래서 Member 클래스는 구현되어 있지만 멤버 정보(phonnum 등)를 직접 DB를 통해 읽어오는게 아님!


Member.java

public class Member {

private String uniqueId; // uid
private String userId;
private String role;
private String email;
private String phone;

// ... getter setter ...

}


TestModel.java

public class TestModel {
private long id;
private String name;
private Date date;
private Member creator;
private TestEnum testEnum;

public enum TestEnum { // 위에서 얘기한대로 클래스 안으로 가져옴

TEST_A, TEST_B
}

// ... getter setter ...

}


요거 진행하다가 소소하게 typedef도 적용함 ㅎㅎ

TestModel.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.ssodang.hibernate.model">

<!-- typedef 으로 미리 정의해 둘 수 있다 -->
<typedef class="java.lang.String" name="String" />
<typedef class="java.lang.Long" name="long" />
<typedef class="java.util.Date" name="Date" />
<typedef class="com.ssodang.hibernate.model.Member" name="Member"
/>

<class name="TestModel" table="test_table">
<id name="id" type="long" column="id">
<generator class="identity"></generator>
</id>
<property name="name" type="String" column="name"></property>
<property name="date" type="Date" column="reg_date"></property>
<component name="creator" class="Member">
<property name="uniqueId" type="String" column="reg_user_uid"></property>
<property name="userId" type="String" column="reg_user"></property>
</component>
<property name="testEnum" column="test_enum">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.ssodang.hibernate.model.TestModel$TestEnum</param>
<param name="useNamed">true</param>
</type>
</property>
</class>

</hibernate-mapping>


요렇게 component로 추가하면 된다!

설정한개만 하면 되니까 편하긴 편한거같당 ^________________^




==================================================================


또 추가!!


Hibernate 여러번 Session Transaction 코드 여러번 쓰기 힘드니깐 Util로 만든다. (Hibernate3 프로그래밍 책 참고)

HibernateUtil.java

package com.ssodang.hibernate.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
* Created by SSODANG on 2015-08-31.
*/
public class HibernateUtil {

private static final Log log = LogFactory.getLog(HibernateUtil.class);

private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
log.error("Initial SessionFactory creation failed. {}", ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}

public static void closeSession() {
getCurrentSession().close();
}

public static Transaction beginTransaction() {
return getCurrentSession().beginTransaction();
}

public static void commitTransaction() {
getCurrentSession().getTransaction().commit();
}

public static void rollbackTransaction() {
if (getCurrentSession().isOpen()) {
Transaction tx = getCurrentSession().getTransaction();
if (tx != null && tx.isActive()) {
tx.rollback();
}
}
}

}

이렇게 다 해놓으면!

코드가

@Test
public void insertTest() {

SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();

Member member = new Member("1w88sf62g570h7809e28", "ssod***@email.com");
TestModel testModel = new TestModel(1, "test", new Date(), member, TestModel.TestEnum.TEST_A);
session.save(testModel);

session.getTransaction().commit();

}

요랬던게

@Test
public void insertTest() {

HibernateUtil.beginTransaction();

Member member = new Member("1w88sf62g570h7809e28", "ssod***@email.com");
TestModel testModel = new TestModel(1, "test", new Date(), member, TestModel.TestEnum.TEST_A);

HibernateUtil.getCurrentSession().save(testModel);

HibernateUtil.commitTransaction();

}

이렇게 간편해진다!


그럼 이번엔 셀렉트를 해보쟈

@Test
public void selectTestModelTest() {

// begin
HibernateUtil.beginTransaction();


/* select by id */

long testModelId = 15;

/* A-1 : currentSession.get(타겟클래스, 키값)
* class="identity"로 설정되어있는 컬럼으로 select 해오는 방식 */
TestModel testModel1 = (TestModel)HibernateUtil.getCurrentSession().get(TestModel.class, testModelId);
System.out.println(testModel1);

Assert.assertEquals(testModel1.getId(), testModelId);

/* A-2 : query 방식
* from 절과 where 절에 기존 쿼리 방식으로 써서 결과를 가져온다.
* myBatis에서 #{id} 등의 방식으로 사용하는 입력내용 부분은 :id로 표기하고
* 테이블 명이 아닌 java 클래스 명을 쓴다 */
Query query = HibernateUtil.getCurrentSession().createQuery("from TestModel where id = :id");
query.setParameter("id", testModelId);
TestModel testModel2 = (TestModel)query.uniqueResult(); // id로 검색이므로 유니크! 아니면 .list()로 List<> 반환
System.out.println(testModel2.toString());

Assert.assertEquals(testModel2.getId(), testModelId);

/* A-1과 A-2의 결과가 같은 것 확인 */
Assert.assertEquals(testModel1, testModel2);


/* 조건으로 select */

String testUserId = "t***@gmail.com";

/* B-1 : 조건 변수 파라미터로 검색! */
query = HibernateUtil.getCurrentSession().createQuery(
"from TestModel where creator.userId = :userId and ROWNUM between 1 and 5 order by date");
// ROWNUM은 비록 빨간줄이 뜨지만 실행하면 잘 수행된당.. 뭐지 @_@
query.setParameter("userId", testUserId);
List<TestModel> result1 = query.list();

Assert.assertTrue(result1.size() <= 5);

for (TestModel test : result1) {
Assert.assertEquals(test.getCreator().getUserId(), testUserId);
System.out.println(test.toString());
}

/* B-2 : 조건이 변수가 아닌경우의 단순 쿼리 검색! */
query = HibernateUtil.getCurrentSession().createQuery(
"from TestModel where creator.userId = 't***@gmail.com' and ROWNUM between 1 and 5 order by date");
// myBatis 같은거 쓸때랑 마찬가지로 변수 아니고 고정 값이면 파라미터 셋팅 없이 요렇게 쿼리에 넣는다
List<TestModel> result2 = query.list();

Assert.assertTrue(result2.size() <= 5);

for (TestModel test : result2) {
Assert.assertEquals(test.getCreator().getUserId(), testUserId);
System.out.println(test.toString());
}


/* 당연하게도 B-1과 B-2의 결과가 같은 것 확인 */
Assert.assertEquals(result1, result2);


// commit
HibernateUtil.commitTransaction();

}


그리고..  퇴근해야지..ㅎㅎㅎㅎㅎㅎ




Comments