Whiteship's Note


[하이버네이트 VS JPA] 객체 다루기

Hibernate/etc : 2010.07.27 17:09


JPA를 언젠간 써야 할텐데 아직도 하이버네이트가 그냥 편해서... @_@;; 암튼 이 둘은 객체를 다루는 API가조금 다른데 그걸 정리해둡니다.

 하이버네이트(Session) JPA(EntityManager) 설명 
save() persist()  저장(정확하게는 Pesistent 상태로 변경) 
 get() find()  DB에서 가져오기 
 load()  getReference() 프록시 가져오기 
 delete() remove()  삭제(정확하게는 Deleted 상태로 변경) 
update()  없음  reattach 다시 부착하기(정확하게는 Detached 상태에서 Persistent 상태로 변경) 
 merge() merge()  merge 병합하기(get() 해온 다음에 Detached 객체의 상태를 복사해간다. 


왠지 CRUD가 다 있어 보이지만 사실 아래 두 줄은 Update 관련 API가 아니라 Detached 상태의 객체를 Persistent 상태로 만들기 용 메서드가 뭐 이것들을 이용해서 Detached 상태 객체를 DB에 반영해서 Update 쿼리를 발생시킬 수도 있지만.. 사실 진정한 Update는 API로 존재하지 않는다. 

즉.. Persistent 상태의 객체를 가지고 어떤 속성을 변경했다 치자.. 이때 굳이 어떤 API를 써서 Update 문을 발생시키지 않아도 된다는 것이다. 

Session session = getSession(); 
Transaction tx = session.beginTransaction(); 
Book book = (Book) session.get(Book.class, 12); 
book.setName("토비의 스프링 3"); 
tx.commit(); 
session.close(); 

저렇게 변경하고 아무것도 실행하지 않는다. 왜일까? 퀴즈닷.
top

  1. Favicon of http://lf.hisfy.com/ BlogIcon 엽우 2010.07.27 20:49 PERM. MOD/DEL REPLY

    setName을 호출하고 트랜잭션이 커밋되면서(아니면 세션이 닫히면서?) 자동으로 업데이트가 되는 거 아닌가요? 하이버네이트는 대충 공부해서 쓰다 보니 정확한 답은 모르겠네요. ^^;

    Favicon of http://whiteship.me BlogIcon 기선 2010.07.28 07:25 PERM MOD/DEL

    맞습니다. 그런걸 바로 Auto Dirty Checking 이라고 합니다.

Write a comment.


@Configurable + 톰캣

Spring/Chapter 6 : 2008.01.16 10:55


테스트 코드는 다음과 같습니다.

public class MemberTestServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        Member member = new Member();
        if(member.getMemberRepository() == null)
            System.out.println("Opps Repository Null");
        if(member.getMemberRepository().getSessionFactory() == null)
            System.out.println("Opps SessionFactory Null");
        System.out.println("Good!!!");
    }

}

간단하죠. 뷰에 디스패칭을 하지도 않았습니다. 그냥 콘솔에 Good!!만 출력하도록 했습니다. 그 이외의 경우(Null)에는 화면에 뭐가 Null인지 출력하도록 했죠. 그리고 이 녀석을 web.xml에 등록했습니다.

    <servlet>
        <servlet-name>memberTest</servlet-name>
        <servlet-class>web.MemberTestServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>memberTest</servlet-name>
        <url-pattern>/memberTest.do</url-pattern>
    </servlet-mapping>

그리고 브라우저에서 /memberTest.do 를 호출하고 콘솔 창을 봤습니다.

사용자 삽입 이미지

사용자 삽입 이미지

결론 : @Configurable은 웹 서버에서도 잘 동작 합니다.
top

  1. 김경태 2008.01.21 12:11 PERM. MOD/DEL REPLY

    친철하시게도 직접 테스트까지 해서 올려주시다니 감사합니다.
    다른일로 테스트를 못해보다가 오늘 해봤는데 -javaagent 옵션은 줬는데 다른 곳에 실수가 있었더군요.
    블로그에서 항상 많이 배우고 있습니다 ^^ 감사합니다.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.01.21 13:45 PERM MOD/DEL

    넹..그냥 저도 안 해본거라서 공부도 할 겸 해본거랍니다.ㅋ;

Write a comment.


@Configurable + @Entity

Spring/Chapter 6 : 2008.01.16 10:23


참조 : Spring: Component Scan + Load Time Weaver (LTW)

아침에 올라온 댓글을 보고 확인해봤습니다.

질문은 @Configurable과 JPA 그리고 Jetty를 사용했을 때, @Configurable이 동작하지 않아서 도메인 객체가 가지고 있는 레퍼런스 타입의 객체들이 세팅되지 않고 null 인 상태라는 제보였습니다.

예상으로는 웹 서버를 동작 시키실 때, -javaagent 옵션을 주지 않으신 게 아닌가 싶습니다.

사용자 삽입 이미지
이클립스에서 톰캣을 사용하는 이런 화면에서 가운데 보이는 Open lunch configuration에서 옵션을 줄 수 있습니다.

사용자 삽입 이미지
일단 서버에서 테스트 하려면 Sevlet 에서 코드를 작성해서 확인해봐야겠지만, 그 전에 @Entity랑 @Configurable이 같이 묶여도 이상이 없다는 것은 확인하고 넘어가야겠기에 테스트를 해봤습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"file:web/WEB-INF/applicationContext.xml"})
public class MemberTest {

    @Test
    public void injectionTest() throws Exception {
        Member member = new Member();
        assertNotNull(member);
        assertNotNull(member.getMemberRepository());
        assertNotNull(member.getMemberRepository().getSessionFactory());
    }

}

물론 이 테스트를 돌릴 때에도 -javaagent 옵션을 주셔야 합니다. 이 경우에는 junit에 주어야겠죠.

사용자 삽입 이미지

테스트는 통관합니다. 설정은 다음과 같습니다.
    <tx:annotation-driven />

    <context:load-time-weaver />

    <context:spring-configured />

    <context:component-scan base-package="domain" />

    <bean id="member" class="domain.Member" abstract="true"
        scope="prototype" p:member-dao-ref="memberDao" />

이밖에도 sessionFactory, datasource, transactionManager 가 빈으로 등록되어 있지만 생략하겠습니다.

어쨋든 조금 쉬었다가 Servlet에서 위의 코드를 실행해보겠습니다.
top

Write a comment.


JPA @Transient

Hibernate/Annotation : 2007.09.27 16:46


@Entity 애노테이션이 붙은 클래스의 모든 속성들은 기본으로 모두 테이블의 필드로 생성하게 됩니다. 만약 어떤 속성을 테이블의 필드로 만들고 싶지 않다면, @Transient 애노테이션을 해당 속성 또는 해당 속성의 getter위에 붙여주면 됩니다.

@Entity
public class Member {
    private Long memberId;
    private String password;
    @Transient
    private String confirmPassword;
    ...
}

회원가입을 할 때 확인하는 패스워드의 경우 제대로 입력했는지 확인하기 위해서 한 번 더 입력을 하는데, 이러한 속성은 DB에 저장할 필요가 없기 때문에, @Transient로 설정해 줄 수 있습니다.

'Hibernate > Annotation' 카테고리의 다른 글

@CollectionOfElements 애노테이션  (0) 2008.09.19
Table 애노테이션  (0) 2008.06.19
JPA @Transient  (0) 2007.09.27
JPA @JoinColumn  (1) 2007.09.22
JPA @ManyToOne  (0) 2007.09.22
JPA @OneToMany  (0) 2007.09.22
top

Write a comment.


JPA @JoinColumn

Hibernate/Annotation : 2007.09.22 15:18


참조 :http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#JoinColumn
링크에 내용이 상당히 많아서 정리는 나중에 하기로 하고...

사용자 삽입 이미지

이름이 암시 하듯이 Join 컬럼 설정을 할 때 사용합니다. 위의 관계에서 Post에 Catergory 의 주키를 외례키로 가짐으로써 Join을 하고 있으니... Post Entity의 getCategory()에 @JoinColumn을 붙여 줍니다.

그러면 Post 테이블을 만들 때 join column 이름을 기본으로 Entity 명 + 언더바 + 주키 를 사용합니다.

public class Category {

    private Long categoryId;

    ..
}

현재 Category 클래스가 위와 같기 때문에 외례키(join column)이 categoty_categoryId 와 같은 형태로 생기게 됩니다. 별로 멋진 이름은 아닌 것 같으니 다음과 같이 설정해 줍니다.

    @ManyToOne(fetch=FetchType.LAZY, optional=false)
    @JoinColumn(name="categoryId")
    public Category getCategory() {
        return category;
    }

그리고  이전 글에서 잠시 고민했었던 cascading 설정은 Category를 지우면 해당 Categorry에 모든 Post마저 삭제 되도록 Category에 설정해 주겠습니다. 이밖에도 모든 cascading을 적용하도록 아예 all로 하겠습니다.

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "category", cascade = { CascadeType.ALL })
    public Set<Post> getPosts() {
        if (posts == null)
            posts = new HashSet<Post>();
        return posts;
    }

자 이제 설정은 마쳤고 제대로 설정을 한 건지, 원하는 대로 동작 하는지 테스트를 해봐야겠습니다.

'Hibernate > Annotation' 카테고리의 다른 글

@CollectionOfElements 애노테이션  (0) 2008.09.19
Table 애노테이션  (0) 2008.06.19
JPA @Transient  (0) 2007.09.27
JPA @JoinColumn  (1) 2007.09.22
JPA @ManyToOne  (0) 2007.09.22
JPA @OneToMany  (0) 2007.09.22
top

  1. Favicon of http://theworldismyparish.tistory.com BlogIcon 탁월한실력과 깊이있는 영감 2014.04.24 00:21 신고 PERM. MOD/DEL REPLY

    좋은 자료 감사합니다.

Write a comment.


JPA @ManyToOne

Hibernate/Annotation : 2007.09.22 14:58


참조 : http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#ManyToOne
사용자 삽입 이미지

자 이번에는 Post쪽에서 생각해 보겠습니다. "하나의 Post는 하나의 Category와 연관을 맺고 있습니다." 그럼 1:1 인가요? ㅋㅋ 아니죠. "또 다른 하나의  Post가 위의 Post가 연관을 맺고 있는 Category와 연관을 맺을 수 있습니다." 따라서 다:1 즉 ManyToOne의 관계이 있습니다.

사용자 삽입 이미지

@ManyToOne에 설정할 수 있는 속성들은 위와 같습니다. 이 중에서 세 개는 이미 @OneToMany에서 살펴보았고, 새로운 것은 딱 하나 optional 이 있습니다.

optional 은 "부가적인", "임의의"란 뜻으로 해당 속성이 임의적으로 있을 수도 있고, 없을 수도 있는지를 설정하는 것 같습니다.

속성

설명

기본값

cascade

관계를 맺고 있는 타겟 쪽에 어떠한 persistence operation들을 연쇄적으로 적용하고 싶을 때 설정합니다.

 

ALL, MERGE, PERSIST, REFRESH, REMOVE 등의 값을 사용하여 여러 개의 cascade 속성을 설정할 수 있습니다.

 

참조무결성을 위한 설정으로 보이며, Hibernate @Cascade 를 사용하여 보다 다양한 cascade 옵션을 사용할 수 있습니다.

비어있는 CascadeType 배열

fetch

연관을 맺고 있는 Entity들을 요청하는 순간 가져오는 설정이 LAZY ,

 

해당 Entity를 가져올 때 미리 연관을 맺고 있는 Entity들까지 모두 가져오는 것이 EAGER 입니다.

FetchType.LAZY

optinal

해당 속성 또는 필드에 빈 값(null)이 들어갈 수 있는지 여부를 나타냅니다.

 

반드시 값이 필요하다면, true로 설정합니다.

true

targetEntity

만약 Generic을 사용하지 않은 Collection일 때는 이 속성을 관계의 주인이 되는 쪽 클래스로 설정해 주어야 합니다.

타입을 명시한 Collection을 사용했을 때는 해당 타입으로 사용합니다.


다시 예제로 돌아가서 Post가 owning entity인데, 이 녀석을 삭제하거나, 변경한다고 해서, Category도 삭제되거나 변경되어야 하지는 않아도 될 것 같습니다. 흠.. 오히려 Category를 삭제하면 Post들이 모두 삭제 되어야 할 것 같은데 그러면 Cattegory에서 cascade 속성을 설정해야 하나;; 흠...

Post 객체를 불러올 때 Post와 연관을 맺고 있는 Category도 가져와야 할 필요는 없어 보입니다.

Post는 꼭 어느 Category엔가에는 들어야 할 것이기 때문에 외례키가 null일 경우는 없을 것 같습니다.

위 정황을 종합하여 다음과 같이 설정할 수 있겠습니다.

@ManyToOne(fetch=FetchType.LAZY, optional=false)

public Category getCategory() {

       return category;

}


여기서 이만 끝나면 좋겠지만, 아직 끝나지 않았습니다. @JoinColumn 이라는 녀석을 붙여줘야 합니다. 다음 글에서 살펴보겠습니다.

'Hibernate > Annotation' 카테고리의 다른 글

@CollectionOfElements 애노테이션  (0) 2008.09.19
Table 애노테이션  (0) 2008.06.19
JPA @Transient  (0) 2007.09.27
JPA @JoinColumn  (1) 2007.09.22
JPA @ManyToOne  (0) 2007.09.22
JPA @OneToMany  (0) 2007.09.22
top

Write a comment.


JPA @OneToMany

Hibernate/Annotation : 2007.09.22 14:35


참조 : http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#OneToMany
사용자 삽입 이미지
위와 같은 관계에 있을 때 Category도 자신에 속해있는 Post를 참조할 수 있고 Post도 자신이 속한 Category를 참조할 수 있다면 Java 코드는 다음과 같이 작성할 수 있습니다.

public class Category {

    private Long categoryId;

    private String categoryName;

    private Set<Post> posts;

    ...
}

public class Post {

    private Long postId;

    private Category category;
 
    ...
}

Category 입장에서 Post를 보면 "Category 하나는 여러 Post와 연관을 맺습니다." 따라서 OneToMany 관계 입니다.

@OneToMany 애노테이션을 getter위에 붙여 줍니다.
사용자 삽입 이미지
설정 할 수 있는 속성은 위에 보이는 것과 같이 네 개가 있습니다.

cascade의 사전적인 의미는 "작은 폭포" "계단식 정보 전달" 이라는 뜻이 있습니다. 이것으로 추축할 때 어느쪽 Entity에 영향을 주면 다른 쪽 Entity에도 어떤 영향을 줄 수 있는 설정이라는 것으로 생각할 수 있습니다.

fetch의 사전적인 의미는 "가지고 오다" "자아내다" 라는 뜻이 있습니다. 즉 해당 Entity를 불러올 때 연관을 맺고 있는 상대방(OneToMany이기 때문에 상대방은 Many쪽이 되겠죠.)들을 가져오는 것과 관련된 속성이라고 생각할 수 있습니다.

mappedBy는 "누군가에 의해 관계를 맺고 있다." 즉, 누군가 한테 종속되어 있다. 라는 설정으로 생각할 수 있겠습니다.

targetEntity는 연관을 맺고 있는 타겟을 지칭하는 듯해 보입니다.

속성

설명

기본값

cascade

관계를 맺고 있는 타겟 쪽에 어떠한 persistence operation들을 연쇄적으로 적용하고 싶을 때 설정합니다.

 

ALL, MERGE, PERSIST, REFRESH, REMOVE 등의 값을 사용하여 여러 개의 cascade 속성을 설정할 수 있습니다.

 

참조무결성을 위한 설정으로 보이며, Hibernate @Cascade 를 사용하여 보다 다양한 cascade 옵션을 사용할 수 있습니다.

비어있는 CascadeType 배열

fetch

연관을 맺고 있는 Entity들을 요청하는 순간 가져오는 설정이 LAZY ,

 

해당 Entity를 가져올 때 미리 연관을 맺고 있는 Entity들까지 모두 가져오는 것이 EAGER 입니다.

FetchType.LAZY

mappedBy

관계가 양방향 일 때는 mappedBy 속성에 관계의 주인이 되는 쪽에서 어떤 속성으로 접근을 하는지 설정해 줍니다.

if the relationship is unidirectional, the persistence provider determines the field that owns the relationship.

targetEntity

만약 Generic을 사용하지 않은 Collection일 때는 이 속성을 관계의 주인이 되는 쪽 클래스로 설정해 주어야 합니다.

타입을 명시한 Collection을 사용했을 때는 해당 타입으로 사용합니다.


다시 Category와 Post의 관계로 돌아가서...

Category와 Post 관계 중에 어느 쪽이 관계의 주인이 되는지 생각해 보겠습니다. "관계의 주인" 영어 문서에는 owner side, owning entity등으로 표햔을 하고 있는데, 아무래도 직관적으로 생각해 봤을 때 DB 테이블 간의 관계를 설정할 때 상대방의 주키를 자신의 외례키로 가지는 쪽을 말하는 것 같습니다.

위의 관계라면 Post 에서 Catergory를 외례키로 가지고 있을 것이기 때문에, Post를 owning entity로 볼 수 있습니다.

그리고 Category 엔티티를 읽어 올 때 거기에 딸려 있는 모든 Post를 미리 읽어오게 하고 싶지 않습니다. 그러면 Category 목록만 보고 있는데도 그 안에 딸려 있는 모든 Post들을 DB에서 가져오게 될 텐데 그러면 엄청나게 많은 부하가 생길 것 같기 때문입니다. 그래서 fetch의 기본값인 LAZY를 사용하겠습니다.

cascade 속성은 owning entity에서 설정해주면 될 것 같고, targetEntity는 사용할 필요가 없습니다. 저는 Generic을 사용했기 때문에 별도로 명시해줄 필요가 없습니다.

위의 상황을 종합하여 다음과 같이 설정할 수 있습니다.

@OneToMany(fetch=FetchType.LAZY, mappedBy="category")

public Set<Post> getPosts() {

       if(posts == null) posts = new HashSet<Post>();

       return posts;

}


지금 예제는 양방향 관계이기 때문에 Owning Entity쪽 즉 Post 클래스의 getCategory()에 @ManyTonOne 설정을 하도록 하겠습니다. 너무 길어서 다음글로 이어집니다.

'Hibernate > Annotation' 카테고리의 다른 글

@CollectionOfElements 애노테이션  (0) 2008.09.19
Table 애노테이션  (0) 2008.06.19
JPA @Transient  (0) 2007.09.27
JPA @JoinColumn  (1) 2007.09.22
JPA @ManyToOne  (0) 2007.09.22
JPA @OneToMany  (0) 2007.09.22
top

Write a comment.


JPA(Java Persistent API)가 뭐지..

Hibernate/study : 2006.12.28 17:48


지난 스터디 때 처음 들어본 단어 JPA[각주:1]를 공부해야 한다는 말씀을 듣었습니다. 설명도 살짝 들었습니다.

EJB와 관련지어 설명해 주셨는데 EJB를 공부해본 적도 없고 경험이 없기 때문에 이해하지 못하고 외울 수 밖에 없었습니다. EJB의 Entity bean과 연관지어 설명해 주신 것이 기억이 나서 찾아 보았습니다.

위키피디아에 있는 Entitry Bean의 정의입니다.
An Entity Bean is a type of Enterprise JavaBean, a server-side Java EE component, that represents persistent data maintained in a database. An entity bean can manage its own persistence (Bean managed persistence) or can delegate this function to its EJB Container (Container managed persistence). An entity bean is identified by a primary key. If the container in which an entity bean is hosted crashes, the entity bean, its primary key, and any remote references survive the crash.

In EJB 3.0, entity beans were superseded by the Java Persistence API.
Entity Bean은 database에서 관리되는 persistent data를 java 프로그램에서 표현하기 위해 사용되는 하나의 타입인 것 같습니다. 이 빈들은 주키로 관리가 되는데...EJB 3.0에서는 JPA에 의해 대체 됐다고 하는군요.

위키피디아에서 JPA를 찾아봤습니다.
The Java Persistence API, sometimes referred to as JPA, is a Java programming language framework that allows developers to manage relational data in Java Platform, Standard Edition and Java Platform, Enterprise Edition applications.

Java 플렛폼 기반으로 관계형 Data를 프로그램에서 다룰 때 사용하는 프레임웍이라는 짧은 설명입니다.
세가지 구성요소를 들고 있는데 다음과 같습니다.(Persistence consists of three areas:)
    * the API, defined in the javax.persistence package
    * the Java Persistence Query Language
    * object/relational metadata


좀더 자세한 내용을 찾고 싶어 sun에서 찾아 보았습니다.
http://java.sun.com/developer/technicalArticles/J2EE/jpa/index.html
J2EE tutorial에서 JPA 부분
J2EE API에서 JPA부분


  1. 물론 처음 들어본 단어는 이 밖에도 많았지요. [본문으로]

'Hibernate > study' 카테고리의 다른 글

숙제  (0) 2007.01.19
Transaction  (2) 2007.01.02
JUnit 으로 Hibernate 테스트  (0) 2007.01.01
Detached Objects  (0) 2007.01.01
Object identity  (2) 2007.01.01
Persistent Object  (0) 2007.01.01
Study To Do List  (2) 2006.12.29
Transient Object  (0) 2006.12.28
JPA를 필드 위에 써보기  (0) 2006.12.28
@Column 조사  (2) 2006.12.28
JPA(Java Persistent API)가 뭐지..  (2) 2006.12.28
top

TAG JPA
  1. Favicon of https://jjaeko.tistory.com BlogIcon 째코 2008.01.17 13:04 신고 PERM. MOD/DEL REPLY

    제목이 같은건 고의가 아닙니다 -0-;;
    2006년 12월달이면 제가 자바 시작하고 얼마 지나지 않았을 때인데 저랑 너무 많은 차이가 나네요

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.01.17 20:58 PERM MOD/DEL

    에고 이런 글을 썼는지도 잊어버렸었는데 감사합니다. JPA가 저런 뜻이었군요;

Write a comment.