Whiteship's Note

'Merge'에 해당되는 글 1건

  1. 2008.03.11 Reattaching과 Merging (2)

Reattaching과 Merging

Hibernate/Chapter 9 : 2008.03.11 13:18


detached 상태의 객체를 persistent 객체로 전이할 때에는 Reattach가 간편하긴 하지만, 여러 개의 Session에 걸쳐 있을 경우에 예상치 못한 문제가 발생할 수 있습니다.

    @Test
    public void reattaching() {
        Session session1 = sessionFactory.openSession();
        Transaction transaction = session1.beginTransaction();
       
        Member member = new Member();
        member.setName("toby");
        session1.save(member);
       
        transaction.commit();
        session1.close();
       
       member.setName("whiteship");
       
        Session session2 = sessionFactory.openSession();
        Transaction transaction2 = session2.beginTransaction();
       
      Member member2 = (Member) session2.get(Member.class, member.getId());
      session2.update(member);
       
        assertEquals("whiteship", member.getName());
       
        transaction2.commit();
        session2.close();
    }

바로 이런 경우인데요. 위의 코드는 NonUniqueObjectException 예외가 발생합니다. 왜 그런지는 비밀입니다.
암튼 위의 코드야 둘이 붙어있으니까 왜 문제가 발생하는지 잘 보이지만, 여러 세션에 걸쳐서 detacked 객체를 붙였다 땟다 한다고 생각하면, 일일히 추적해서 update()를 사용한 줄을 위쪽으로 올려주는 작업을 해야 합니다. 고통이겠죠.

    @Test
    public void merging() {
        Session session1 = sessionFactory.openSession();
        Transaction transaction = session1.beginTransaction();
       
        Member member = new Member();
        member.setName("toby");
        session1.save(member);
       
        transaction.commit();
        session1.close();
       
        member.setName("whiteship");
       
        Session session2 = sessionFactory.openSession();
        Transaction transaction2 = session2.beginTransaction();
       
      Member member2 = (Member) session2.get(Member.class, member.getId());
      Member member3 = (Member) session2.merge(member);
       
        assertEquals("whiteship", member3.getName());
       
        transaction2.commit();
        session2.close();
    }

이럴 때 사용할 수 있는 것이 merge() 입니다. 이 녀석은 재밌게 동작합니다. 저렇게 하면 아무런 문제도 발생하지 않고 원하는 대로 동작합니다.

대신 주의 해야 할 것은 member2 와 member3가 같은 레퍼런스를 가지고 있기 때문에 아래와 같은 코드가 가능합니다.

        Member member2 = (Member) session2.get(Member.class, member.getId());
        Member member3 = (Member) session2.merge(member);
       
        member2.setName("whiteship2");
       
        assertEquals("whiteship2", member3.getName());

이런 상황이 용납이 안 되는 것은 아닙니다. 하지만 사방에서 저 객체의 값을 변경하면 좀 곤란하겠죠. member2와 member(detached 상태의 객체)는 merge()의 반환값을 가져온 이상. 사장되었다고 생각하고 작업을 하는 것이 좋겠습니다.

merget()와 Persistent Context의 dirty checking이 맞물리면, 정말 SQL이 재미있게 생성되는 모습을 볼 수 있습니다.

위의 예제에서 발생되는 쿼리는 간단합니다.
- member를 넣는 insert 문
- member2를 가져오는 select문
- member3을 가져올 때(merging time)member2가 참조하던 객체를 변경하는 update문


퀴즈 그렇다면 아래의 코드는 어떤 SQL들을 만들어 낼까요?

        Session session1 = sessionFactory.openSession();
        Transaction transaction = session1.beginTransaction();
       
        Member member = new Member();
        member.setName("toby");
        session1.save(member);
       
        transaction.commit();
        session1.close();
       
        member.setName("whiteship");
       
        Session session2 = sessionFactory.openSession();
        Transaction transaction2 = session2.beginTransaction();
       
        Member member2 = (Member) session2.get(Member.class, member.getId());
        Member member3 = (Member) session2.merge(member);
       
        member2.setName("toby");
       
        assertEquals("toby", member3.getName());
       
        transaction2.commit();
        session2.close();

위와 같이 간단하게 발생되는 쿼리 종류를 써주세요. 그리고 왜!! 왜 그런 결과가 생기는지도 설명해주세요~
top

  1. Favicon of https://jjaeko.tistory.com BlogIcon 째코 2008.03.30 23:37 신고 PERM. MOD/DEL REPLY

    첫번째 세션에서 "toby" 로 저장하고 준영속 객체의 값을 "whiteship" 으로 바꾼뒤
    두번째 세션에서 첫번째 세션에서 준영속 객체가 되어버린 식별값을 가지는 객체를 가져와서
    준영속 객체를 머지 했지만 다시 원래 값인 "toby"로 값을 바꿧기 때문에 변화를 감지하지 못하고
    결국 아무 일도 일어나지 않을거 같네요
    테스트도 통과할듯 싶은데요 member2와 member3의 참조값은 동일하니까..

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.03.31 08:37 PERM MOD/DEL

    와~ 맞습니다. toby->whiteship->toby로 다시 바꿨기 때문에 중간에 whiteship으로 update하는 불필요한 UPDATE문은 발생하지 않습니다.

    물론 테스트도 통과하구요. 딩동댕~!

Write a comment.