728x90
반응형
원문 출처 : http://javacan.tistory.com/entry/105#comment2347957
작성자 : 최범균
실제로 사용할 때 연관 객체를 읽어오는 걸, lazy 방식이라고 한다. Hibernate는 lazy 방식으로 연관 객체를 읽어올 때 다음과 같이 프록시 객체를 사용한다.
lazy 방식으로 지정된 경우, Hibernate는 위 그림에서 볼 수 있듯이 연관된 객체를 곧바로 읽어오지 않는다. 대신 연관된 객체와 연결될 수 있는 프록시 객체를 생성한다. 연관된 객체가 필요할 때 실제 연관될 객체가 생성되서 프록시와 연결된다.
many-to-one 관계에서 lazy 방식을 적용하기 위해서는 다음과 같이 연관될 클래스에 대한 정보를 담고 있는 class 태그의 lazy 속성값을 true로 지정해주어야 한다. (Bid-Item의 관계가 many-to-one)
위와 같이 lazy 속성을 true로 지정하게 되면 Hibernate는 Item 클래스를 위한 프록시 클래스를 자동으로 생성해서 프록시로 사용한다.
one-to-one 관계에서도 마찬가지로 lazy 속성을 사용해서 lazy 방식을 적용할 수 있다. 예를 들어, 아래와 같이 one-to-one 관계를 맺을 때, 양쪽 모두 lazy 방식으로 읽어오도록 설정할 수 있다.
콜렉션을 읽어올 때에도 lazy 방식을 사용할 수 있다. 예를 들어, set 태그에 다음과 같이 lazy 속성을 추가함으로써 lazy 방식으로 콜렉션을 읽어오도록 명시할 수 있다.
lazy 방식을 사용할 때 주의할 점은 객체가 영속 상태일 때에만, 즉 Session과 연결되어 있는 경우에만 lazy 방식으로 데이터를 읽어올 수 있다는 것이다. 예를 들어, 아래의 코드처럼 lazy 방식으로 읽어온 프로퍼티를 준영속 상태에서 읽어올 수 없으며, 이런 경우 예외가 발생하게 된다.
따라서, lazy 방식으로 읽어온 프로퍼티를 준영속 상태에서 사용해야 하는 경우에는 사전에 미리 lazy 방식으로 읽어온 프로퍼티를 초기화해야 한다. 이럴 때 사용할 수 있는 메소드가 Hibernate.initialize()이다. 위와 같은 경우 다음과 같이 Session을 종료하기 전에 Hibernate.initialize() 메소드를 호출해주면 된다.
outer-join 속성을 사용한 연관 객체 로딩
lazy 방식은 연관된 객체가 실제로 사용되기 전까지 최대한 늦게 객체를 로딩하는 반면에 outer-join 방식은 최대한 빨리 연관된 객체를 로딩한다. outer-join 방식은 외부 조인을 사용해서 한번의 SQL 쿼리로 연관 객체와 관련된 모든 데이터를 읽어오므로 데이터베이스 조회 회수를 줄이면서 동시에 연관 객체를 읽어오게 된다.
outer-join 속성값을 사용해서 outer-join 방식을 설정할 수 있는데, outer-join 속성에 사용할 수 있는 값을 다음과 같이 세가지가 존재한다.
작성자 : 최범균
실제로 사용할 때 연관 객체를 읽어오는 걸, lazy 방식이라고 한다. Hibernate는 lazy 방식으로 연관 객체를 읽어올 때 다음과 같이 프록시 객체를 사용한다.
lazy 방식으로 지정된 경우, Hibernate는 위 그림에서 볼 수 있듯이 연관된 객체를 곧바로 읽어오지 않는다. 대신 연관된 객체와 연결될 수 있는 프록시 객체를 생성한다. 연관된 객체가 필요할 때 실제 연관될 객체가 생성되서 프록시와 연결된다.
many-to-one 관계에서 lazy 방식을 적용하기 위해서는 다음과 같이 연관될 클래스에 대한 정보를 담고 있는 class 태그의 lazy 속성값을 true로 지정해주어야 한다. (Bid-Item의 관계가 many-to-one)
<class name="Item" table="ITEM" lazy="true">
...
</class>
<class name="Bid" table="BID">
...
<many-to-one
name="item"
column="ITEM_ID"
class="Item"
not-null="true" />
...
</class>
...
</class>
<class name="Bid" table="BID">
...
<many-to-one
name="item"
column="ITEM_ID"
class="Item"
not-null="true" />
...
</class>
위와 같이 lazy 속성을 true로 지정하게 되면 Hibernate는 Item 클래스를 위한 프록시 클래스를 자동으로 생성해서 프록시로 사용한다.
one-to-one 관계에서도 마찬가지로 lazy 속성을 사용해서 lazy 방식을 적용할 수 있다. 예를 들어, 아래와 같이 one-to-one 관계를 맺을 때, 양쪽 모두 lazy 방식으로 읽어오도록 설정할 수 있다.
<class name="Item" table="ITEM" lazy="true">
...
<one-to-one name="detail"
class="ItemDetail"
cascade="save-update" />
...
</class>
<class name="ItemDetail" table="ITEM_DETAIL" lazy="true">
...
<one-to-one name="item"
class="Item"
constrained="true" />
</class>
...
<one-to-one name="detail"
class="ItemDetail"
cascade="save-update" />
...
</class>
<class name="ItemDetail" table="ITEM_DETAIL" lazy="true">
...
<one-to-one name="item"
class="Item"
constrained="true" />
</class>
콜렉션을 읽어올 때에도 lazy 방식을 사용할 수 있다. 예를 들어, set 태그에 다음과 같이 lazy 속성을 추가함으로써 lazy 방식으로 콜렉션을 읽어오도록 명시할 수 있다.
<class name="javacan.hibernate.test.Item" table="ITEM" .. >
...
<set name="bids" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="ITEM_ID" />
<one-to-many class="javacan.hibernate.test.Bid" />
</set>
</class>
...
<set name="bids" inverse="true" cascade="all-delete-orphan" lazy="true">
<key column="ITEM_ID" />
<one-to-many class="javacan.hibernate.test.Bid" />
</set>
</class>
lazy 방식을 사용할 때 주의할 점은 객체가 영속 상태일 때에만, 즉 Session과 연결되어 있는 경우에만 lazy 방식으로 데이터를 읽어올 수 있다는 것이다. 예를 들어, 아래의 코드처럼 lazy 방식으로 읽어온 프로퍼티를 준영속 상태에서 읽어올 수 없으며, 이런 경우 예외가 발생하게 된다.
Session session = sessions.openSession();
Transaction tx = session.beginTransaction();
// Item의 bids 프로퍼티와 관련 객체를 lazy 방식으로 로딩
Item item = (Item)session.get(Item.class, someId);
tx.commit();
session.close();
// 준영속 상태에서 lazy 방식의 프로퍼티에 접근 -> 예외 발생
Iterator iter = item.getBids().iterator();
Transaction tx = session.beginTransaction();
// Item의 bids 프로퍼티와 관련 객체를 lazy 방식으로 로딩
Item item = (Item)session.get(Item.class, someId);
tx.commit();
session.close();
// 준영속 상태에서 lazy 방식의 프로퍼티에 접근 -> 예외 발생
Iterator iter = item.getBids().iterator();
따라서, lazy 방식으로 읽어온 프로퍼티를 준영속 상태에서 사용해야 하는 경우에는 사전에 미리 lazy 방식으로 읽어온 프로퍼티를 초기화해야 한다. 이럴 때 사용할 수 있는 메소드가 Hibernate.initialize()이다. 위와 같은 경우 다음과 같이 Session을 종료하기 전에 Hibernate.initialize() 메소드를 호출해주면 된다.
Session session = sessions.openSession();
Transaction tx = session.beginTransaction();
// Item의 bids 프로퍼티와 관련 객체를 lazy 방식으로 로딩
Item item = (Item)session.get(Item.class, someId);
Hibernate.initialize(item.getBids());
tx.commit();
session.close();
// 사전에 초기화 되었으므로 예외 발생안함
Iterator iter = item.getBids().iter();
Transaction tx = session.beginTransaction();
// Item의 bids 프로퍼티와 관련 객체를 lazy 방식으로 로딩
Item item = (Item)session.get(Item.class, someId);
Hibernate.initialize(item.getBids());
tx.commit();
session.close();
// 사전에 초기화 되었으므로 예외 발생안함
Iterator iter = item.getBids().iter();
outer-join 속성을 사용한 연관 객체 로딩
lazy 방식은 연관된 객체가 실제로 사용되기 전까지 최대한 늦게 객체를 로딩하는 반면에 outer-join 방식은 최대한 빨리 연관된 객체를 로딩한다. outer-join 방식은 외부 조인을 사용해서 한번의 SQL 쿼리로 연관 객체와 관련된 모든 데이터를 읽어오므로 데이터베이스 조회 회수를 줄이면서 동시에 연관 객체를 읽어오게 된다.
outer-join 속성값을 사용해서 outer-join 방식을 설정할 수 있는데, outer-join 속성에 사용할 수 있는 값을 다음과 같이 세가지가 존재한다.
- auto - 기본값으로서 프록시가 가능한 경우 lazy 방식으로 읽어오고, 그렇지 않은 경우 outer-join 방식으로 읽어온다.
- true - 프록시가 가능한 경우에도, 항상 outer-join 방식으로 읽어온다.
- false - 프로시를 사용하지 않더라도, 항상 outer-join 방식을 사용하지 않는다.
<many-to-one name="item" class="Item" outer-join="true">
728x90