쏘댕

Hibernate - 큐브리드 2 JOIN 본문

공부/Java

Hibernate - 큐브리드 2 JOIN

ssodang 2015. 10. 5. 19:57

Spring data JPA를 적용해보겠다고 별짓을 다했는뎅 어디가 어떻게 어디서부터 잘못된건지 설정이 꼬여가지고 안된다......

다음번에 새로운 마음으로 다시해야지..................


이번엔 쪼인을 해보쟈


일단 지난번에 test_table 추가에 이어서 조인 테스트를 위한 테이블 추가!

(이름이 온통 엉망인데... 좋은 이름이 안생각난다.. @_@)


테이블 추가했으니 모델도 추가!

public class JoinTest {
private long id;
private long testId;
private JoinKeyword joinKeyword;

public enum JoinKeyword {
RELATION_A, RELATION_B
}

/* getter, setter */
}


TestModel.java에는 JoinTest를 추가한다

(뭔가 조인을 하기위해 모델 안에 인자가 추가되는게 그림이 이상한데.. 이방법말고도 있을텐뎅... 더 찾아봐야지)

public class TestModel {

private long id;
private String name;
private Date date;
private Member creator;
private TestEnum testEnum;
private JoinTest joinTest;

/* 이하 생략! */
}


지난번에 매핑 설정하던 mapper.hbm.xml에 추가를 한다. 아래와 같이!
(mapper도 곧 테이블별로 분리할 예정!!)

<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="paycoUniqueId" type="String" column="reg_user_uid"></property>
<property name="paycoId" type="String" column="reg_user"></property>
</component>
<property name="testEnum" column="test_enum">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.nhnent.deploy.admin.model.TestModel$TestEnum</param>
<param name="useNamed">true</param>
</type>
</property>

<join table="join_table" optional="true">
<key column="test_id"></key>
<component name="joinTest" class="JoinTest">
<property name="id" type="long" column="id" generated="insert"></property>
<property name="joinKeyword" column="join_keyword">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.nhnent.deploy.admin.model.JoinTest$JoinKeyword</param>
<param name="useNamed">true</param>
</type>
</property>
</component>
</join>
</class>

<class name="JoinTest" table="join_table">
<id name="id" type="long" column="id">
<generator class="identity"></generator>
</id>
<property name="testId" type="long" column="test_id"></property>
<property name="joinKeyword" column="join_keyword">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">com.nhnent.deploy.admin.model.JoinTest$JoinKeyword</param>
<param name="useNamed">true</param>
</type>
</property>
</class>


여기서 optional="true"가 신기하다

optional 속성을 안주면

Hibernate:
    select
        testmodel0_.id as id1_5_,
        testmodel0_.name as name2_5_,
        testmodel0_.reg_date as reg_date3_5_,
        testmodel0_.reg_user_uid as reg_user4_5_,
        testmodel0_.reg_user as reg_user5_5_,
        testmodel0_.test_enum as test_enu6_5_,
        testmodel0_1_.id as id2_2_,
        testmodel0_1_.join_keyword as join_key3_2_
    from
        test_table testmodel0_
    inner join
        join_table testmodel0_1_
            on testmodel0_.id=testmodel0_1_.test_id
    where
        testmodel0_.id=?

이렇게 inner join이 되고,

optional="true"를 추가하면

Hibernate:
    select
        testmodel0_.id as id1_5_,
        testmodel0_.name as name2_5_,
        testmodel0_.reg_date as reg_date3_5_,
        testmodel0_.reg_user_uid as reg_user4_5_,
        testmodel0_.reg_user as reg_user5_5_,
        testmodel0_.test_enum as test_enu6_5_,
        testmodel0_1_.id as id2_2_,
        testmodel0_1_.join_keyword as join_key3_2_
    from
        test_table testmodel0_
    left outer join
        join_table testmodel0_1_
            on testmodel0_.id=testmodel0_1_.test_id
    where
        testmodel0_.id=?

이렇게 left outer join이 된다.


실행해본 Test코드는 아래와 같다!

확인에 급급해서.... 그저 sout만 찍었다.. ㅎ_ㅎ

@Test
public void selectJoinTest() {

// begin
HibernateUtil.beginTransaction();

/* select by id */

long testModelId = 22;
Query query = HibernateUtil.getCurrentSession().createQuery("from TestModel t left join t.joinTest j on j.testId = t.id where t.id = :id");
query.setParameter("id", testModelId);
TestModel testModel = (TestModel)query.uniqueResult();
System.out.println(testModel.toString());

// commit
HibernateUtil.commitTransaction();

}


그런데!! 이렇게 명시하지 않아도 암묵적 조인이 된다고해서 그것도 해봤따


/* select by joinKeyword */

JoinTest.JoinKeyword joinKeyword = JoinTest.JoinKeyword.RELATION_B;

/* 명시적 조인 */
Query explicitQuery = HibernateUtil.getCurrentSession().createQuery("from TestModel t left join t.joinTest j on j.testId = t.id where j.joinKeyword = :keyword");
explicitQuery.setParameter("keyword", joinKeyword);
List<TestModel> explicitTestModels = explicitQuery.list();
for (TestModel t : explicitTestModels) {
System.out.println(t.toString());
}

/* 암묵적 조인 */
Query implicitQuery = HibernateUtil.getCurrentSession().createQuery("from TestModel t where t.joinTest.joinKeyword = :keyword");
implicitQuery.setParameter("keyword", joinKeyword);
List<TestModel> implicitTestModels = implicitQuery.list();
for (TestModel t : implicitTestModels) {
System.out.println(t.toString());
}

Assert.assertEquals(explicitTestModels, implicitTestModels);


실행된 쿼리는 명시적, 암묵적 조인 둘 다 아래와 같다.

    select
        testmodel0_.id as id1_5_,
        testmodel0_.name as name2_5_,
        testmodel0_.reg_date as reg_date3_5_,
        testmodel0_.reg_user_uid as reg_user4_5_,
        testmodel0_.reg_user as reg_user5_5_,
        testmodel0_.test_enum as test_enu6_5_,
        testmodel0_1_.id as id2_2_,
        testmodel0_1_.join_keyword as join_key3_2_
    from
        test_table testmodel0_
    left outer join
        join_table testmodel0_1_
            on testmodel0_.id=testmodel0_1_.test_id
    where
        testmodel0_1_.join_keyword=?


당연히 assertEquals 결과도 동일하다고 나오는데,

심지어 하이버네이트는 같은 트랜잭션 안에서 동일한 쿼리는 결과를 캐싱한다고 했던거 같은데 @_@

그래서 완전히 같은 결과를 가져왔을지도 @_@


하지만 내가 제일 신기한건 @_@

위에 언급한 optional="true" 상태로 save를 했을때다.

@Test
public void insertForJoinTest() {

HibernateUtil.beginTransaction();

Member member = new Member("uuid", "ssod***@e-mail.com");

/* joinTest 모델 set한 상태로 insert */
TestModel testModelWithJoin = new TestModel("test_1", new Date(), member, TestModel.TestEnum.TEST_A);
testModelWithJoin.setJoinTest(new JoinTest(testModelWithJoin.getId(), JoinTest.JoinKeyword.RELATION_B));
HibernateUtil.getCurrentSession().save(testModelWithJoin);

/* joinTest 모델 없는 상태로 insert */
TestModel testModelWithoutJoin = new TestModel("test_2", new Date(), member, TestModel.TestEnum.TEST_B);
HibernateUtil.getCurrentSession().save(testModelWithoutJoin);

HibernateUtil.commitTransaction();

}


JoinTest 모델을 set한 후 save를 실행하면

Hibernate:
    insert
    into
        test_table
        (id, name, reg_date, reg_user_uid, reg_user, test_enum)
    values
        (NULL, ?, ?, ?, ?, ?)
Hibernate:
    select
        last_insert_id()
Hibernate:
    insert
    into
        join_table
        (join_keyword, test_id)
    values
        (?, ?)
Hibernate:
    select
        testmodel_1_.id as id2_2_,
        testmodel_1_.join_keyword as join_key3_2_
    from
        test_table testmodel_
    left outer join
        join_table testmodel_1_
            on testmodel_.id=testmodel_1_.test_id
    where
        testmodel_.id=?


이렇게나 알아서 양쪽에 넣어준다...............

마지막에 결과 select는 왜하는건지 사실 모르겠는뎅..


그리고 JoinTest 모델을 안넣고 save 하면

Hibernate:
    insert
    into
        test_table
        (id, name, reg_date, reg_user_uid, reg_user, test_enum)
    values
        (NULL, ?, ?, ?, ?, ?)
Hibernate:
    select
        last_insert_id()
Hibernate:
    select
        testmodel_1_.id as id2_2_,
        testmodel_1_.join_keyword as join_key3_2_
    from
        test_table testmodel_
    left outer join
        join_table testmodel_1_
            on testmodel_.id=testmodel_1_.test_id
    where
        testmodel_.id=?


test_table만 insert 딱 하고 결과 select


요게 optional 값을 true로 안주면 두번째 실행처럼 join으로 설정되어있는 모델을 셋팅하지 않으면 insert 시 에러가 발생한다.

Hibernate:
    insert
    into
        test_table
        (id, name, reg_date, reg_user_uid, reg_user, test_enum)
    values
        (NULL, ?, ?, ?, ?, ?)
Hibernate:
    select
        last_insert_id()
Hibernate:
    insert
    into
        join_table
        (join_keyword, test_id)
    values
        (?, ?)

org.hibernate.exception.GenericJDBCException: could not execute statement


요렇게 무조건적으로다가 저걸 insert할려고 찾으니 필수값이 null이여서 에러를 뱉는다.


이제 one-to-many 랑 many-to-one 이런것도 해봐야겠따






Comments