Synchronized KO translation between 3.2 branch and trunk

git-svn-id: https://svn.jboss.org/repos/hibernate/branches/Branch_3_2/Hibernate3/doc@10956 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Christian Bauer 2006-12-08 08:07:27 +00:00
parent cff47ee5ba
commit 1873cef798
22 changed files with 940 additions and 686 deletions

View File

@ -9,28 +9,56 @@
Blog : http://blog.naver.com/jdkim528/ Blog : http://blog.naver.com/jdkim528/
[Down/Config/Build] [Down/Config/Build]
cvs 클라이언트를 갖고 있다면, * 기존의 CVS에서 SVN으로 바뀌면서 신규 사용자들을 위한 길잡이를 작성할 필요가
1)연결 유형 : pserve/extssh 중 하나를 선택합니다 생겼네요...
2)사용자이름 : anonymous
3)호스트 : cvs.sourceforge.net 필자는 개인적으로 TortoiseSVN과 Subclipse를 사용하고 있으나 Subclpse를 중심으로
4)포트 : 기본값 설명할까 합니다.(선호하는 svn 클라이언트가 있다면 해당 클라이언트의 설정에
5)저장소경로 : /cvsroot/hibernate 따라 설정한 후에 사용하셔도 될 것입니다.)
6)모듈 : Hibernate3/doc/reference
위와 같이 연결 정보를 입력 하신 후 REFERENCE 전체를 내려받으셔도 되지만, [Subclipse 설치]
한글 번역본만 필요하시다면 다음과 같이 하셔도 됩니다.
[가]. 공통 모듈 받기 Subclipse를 설치하는 방법은 http://subclipse.tigris.org/install.html 을 참조하여
위에서 6)모듈을 Hibernate3/doc/reference/support로 지정하시고 eclipse의 도움말>소프트웨어갱신>찾기 및 설치 메뉴를 통해 쉽게 설치할 수 있습니다.
로컬 컴퓨터의 디렉토리 [로컬 경로]/reference/ 하에 받습니다
[나]. 한글본 모듈 받기 [Subclipse Checkout]
위에서 6)모듈을 Hibernate3/doc/reference/ko로 지정하고 0) Subclipse 설치가 끝났으면 이클립스를 재시작하십시오.
로컬 컴퓨터의 디렉토리 [로컬 경로]/reference/ 하에 받습니다. 1) 이클립스의 Perspective 열기에서 SVN Repository exploring을 열어 저장소를 등록하여 사용하거나
[다]. 빌드 파일 받기 이클립스의 패키지 탐색기에서 마우스 오른쪽 팝업 메뉴에서 "프로젝트"를 생성시킵니다.
그런 다음 /doc/reference/build.xml 파일을 내려 받은 다음 여기서는 "프로젝트" 생성 방법을 설명합니다.
2) 이클립스의 패키지 탐색기에서 마우스 오른쪽 팝업 메뉴에서 "프로젝트"를 클릭한다
3) 팝업 창의 "SVN" 노드에서 "Checkout Projects from SVN"을 선택한다
4) "다음" 버튼을 클릭한다
5) "Create a new respository location"을 선택한다
6) 다음" 버튼을 클릭한다
7) Location url에 "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" 또는
"https://hibernate.labs.jboss.com/repos/hibernate/trunk" 을 입력합니다.
8) "Hibernate3" 노드는 선택하거나 하위의 특정 노드를 선택하고 "완료" 버튼을 클릭한다.
9) 프로젝트 명을 hibernate3 등의 원하는 이름으로 명명한다.
10) checkout이 실행됩니다.
[TortoiseSVN 설치]
TortoiseSVN 클라이언트를 설치하셨다면, 시스템을 재시작 하십시오.
1)레파지토리를 위한 폴더를 하나 생성시킵니다.(D:\repo)
2)윈도우탐색기에서 D:\repo를 마우스 오른쪽 클릭한 후 TortoiseSVN 메뉴에서
"Create repository Here..."를 클릭하면 팝업이 뜨는데,
파일시스템/버클리DB 형식 중 하나를 선택하고 OK 버튼을 누르세요.
3)hibernate를 내려 받기 위한 폴더를 하나 생성시키세요(D:\repo\Hibernate3)
4)D:\repo\hibernate 폴더를 마우스 오른쪽 클릭한 후,
TortoiseSVN 팝업 메뉴에서 CheckOut을 클릭하십시오.
5)URL repository에 "http://anonhibernate.labs.jboss.com/trunk/Hibernate3" 또는
"https://hibernate.labs.jboss.com/repos/hibernate/trunk" 를 입력하고,
OK 버튼을 클릭하십시오
6)모두 내려받으신 다음에 D:\repo\Hibernate3\doc\reference로 이동합니다.
7)이제 빌드하시면 됩니다.
*) 한글 번역본만 필요하시다면 다음과 같이 하셔도 됩니다.
/doc/reference/build.xml 파일을
아래 예와 같이 한글 번역본 외의 부분들을 주석처리합니다. 아래 예와 같이 한글 번역본 외의 부분들을 주석처리합니다.
[라]. 빌드하기 []. 빌드하기
그런 다음 [로컬 경로]/reference/ 에서 ant all.doc로 빌드하시면 됩니다. 그런 다음 [로컬 경로]/reference/ 에서 ant all.doc로 빌드하시면 됩니다.
빌드 시간은 2분 가량 소요됩니다. 빌드 시간은 2분 가량 소요됩니다.
[마]. 문서 보기 []. 문서 보기
디렉토리 [로컬 경로]/reference/build/ko/ 디렉토리에 빌드된 문서를 보시기 바랍니다. 디렉토리 [로컬 경로]/reference/build/ko/ 디렉토리에 빌드된 문서를 보시기 바랍니다.
그럼 하이버네이트와 함께 즐거운 시간을 보내세요. 그럼 하이버네이트와 함께 즐거운 시간을 보내세요.

View File

@ -92,17 +92,17 @@ fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
<font-triplet name="Mincho" style="italic" weight="bold"/> <font-triplet name="Mincho" style="italic" weight="bold"/>
</font> </font>
--> -->
<font metrics-file="Gulim.xml" kerning="yes" embed-file="gulim.ttc"> <font metrics-file="Hankc.xml" kerning="yes" embed-file="Hankc.ttf">
<font-triplet name="Gulim" style="normal" weight="normal"/> <font-triplet name="Hankc" style="normal" weight="normal"/>
<font-triplet name="Gulim" style="normal" weight="bold"/> <font-triplet name="Hankc" style="normal" weight="bold"/>
<font-triplet name="Gulim" style="italic" weight="normal"/> <font-triplet name="Hankc" style="italic" weight="normal"/>
<font-triplet name="Gulim" style="italic" weight="bold"/> <font-triplet name="Hankc" style="italic" weight="bold"/>
</font> </font>
<font metrics-file="Gaeul.xml" kerning="yes" embed-file="Gaeul.ttf"> <font metrics-file="Bangwool.xml" kerning="yes" embed-file="Bangwool.ttf">
<font-triplet name="가을체" style="normal" weight="normal"/> <font-triplet name="Bangwool" style="normal" weight="normal"/>
<font-triplet name="가을체" style="normal" weight="bold"/> <font-triplet name="Bangwool" style="normal" weight="bold"/>
<font-triplet name="가을체" style="italic" weight="normal"/> <font-triplet name="Bangwool" style="italic" weight="normal"/>
<font-triplet name="가을체" style="italic" weight="bold"/> <font-triplet name="Bangwool" style="italic" weight="bold"/>
</font> </font>
</fonts> </fonts>

View File

@ -33,7 +33,7 @@
<bookinfo lang="ko"> <bookinfo lang="ko">
<title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title> <title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title>
<subtitle>하이버네이트 참조 문서</subtitle> <subtitle>하이버네이트 참조 문서</subtitle>
<releaseinfo lang="ko">3.1</releaseinfo> <releaseinfo lang="ko">3.2 cr3</releaseinfo>
</bookinfo> </bookinfo>
<toc lang="ko" /> <toc lang="ko" />

View File

@ -78,19 +78,19 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>Persistent objects and collections</term> <term>영속 객체들과 콜렉션들</term>
<listitem> <listitem>
<para> <para>
persistent 상태와 비지니스 기능을 포함하는 수명이 짧고, 단일 쓰레드인 객체들. 이것들은 통상의 JavaBeans/POJO들일 persistent 상태와 비지니스 기능을 포함하는 수명이 짧고, 단일 쓰레드인 객체들. 이것들은 통상의 JavaBeans/POJO들일
수 있고, 오직 그것들에 대한 오직 특별한 것은 그것들이 현재 (정확하게 한 개의) <literal>Session</literal>과 연관되어 수 있고, 오직 그것들에 대한 오직 특별한 것은 그것들이 현재 (정확하게 한 개의) <literal>Session</literal>과 연관되어
있다는 점이다. <literal>Session</literal>이 닫히자마자, 그것들은 분리될(detached 상태가 될) 것이고 어플리케이션 있다는 점이다. <literal>Session</literal>이 닫히자마자, 그것들은 분리될(detached 상태가 될) 것이고 어플리케이션
레이어에서 사용하는 것이 자유로와진다(예를 들면. 프리젠테이션으로의 데이터 전송 객체들로서 직접적으로 그리고 프리젠테이션으로부터 레이어에서 사용하는 것이 자유로와진다(예를 들면. 직접적으로 프리젠테이션 계층으로
데이터 전송 객체들로서 직접으로). 데이터 전송 객체들로서 그리고 직접으로 프리젠테이션 계층으로부터 데이터 전송 객체들로서).
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term>Transient and detached objects and collections</term> <term>전이(Transient, 필자 주-과도) 객체들과 콜렉션들</term>
<listitem> <listitem>
<para> <para>
<literal>Session</literal>과 현재 연관되어 있지 않은 영속 클래스들의 인스턴스들. 그것들은 어플리케이션에 의해 초기화 <literal>Session</literal>과 현재 연관되어 있지 않은 영속 클래스들의 인스턴스들. 그것들은 어플리케이션에 의해 초기화
@ -236,7 +236,7 @@
</para> </para>
</sect1> </sect1>
<sect1 id="architecture-current-session" revision="1"> <sect1 id="architecture-current-session" revision="2">
<title>컨텍스트 상의 세션들</title> <title>컨텍스트 상의 세션들</title>
<para> <para>
Hibernate를 사용하는 대부분의 어플리케이션들은 어떤 양식의 "컨텍스트상의(contextual)" 세션들을 필요로 한다. 여기서 Hibernate를 사용하는 대부분의 어플리케이션들은 어떤 양식의 "컨텍스트상의(contextual)" 세션들을 필요로 한다. 여기서
@ -264,7 +264,7 @@
<para> <para>
그것의 계약에 대한 상세한 논의는 <literal>org.hibernate.context.CurrentSessionContext</literal> 인터페이스에 그것의 계약에 대한 상세한 논의는 <literal>org.hibernate.context.CurrentSessionContext</literal> 인터페이스에
관한 javadocs를 보라. 그것은 하나의 메소드, <literal>currentSession()</literal>를 정의하며, 그 구현은 관한 javadocs를 보라. 그것은 하나의 메소드, <literal>currentSession()</literal>를 정의하며, 그 구현은
현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 개의 구현들을 부수적으로 현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 개의 구현들을 부수적으로
포함하고 있다. 포함하고 있다.
</para> </para>
@ -284,7 +284,7 @@
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para> <para>
두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는 처음의 두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는
"하나의 세션 - 하나의 데이터베이스 트랜잭션" 프로그래밍 모형을 제공한다. 하나의 Hibernate 세션의 시작과 끝은 "하나의 세션 - 하나의 데이터베이스 트랜잭션" 프로그래밍 모형을 제공한다. 하나의 Hibernate 세션의 시작과 끝은
데이터베이스 트랜잭션의 존속 기간에 의해 정의된다. 만일 (예를 들면 순수 J2SE에서 또는 JTA/UserTransaction/BMT의 경우에) 데이터베이스 트랜잭션의 존속 기간에 의해 정의된다. 만일 (예를 들면 순수 J2SE에서 또는 JTA/UserTransaction/BMT의 경우에)
당신이 프로그램 상의 트랜잭션 경계구분을 사용할 경우, 당신은 당신의 코드로부터 기본 트랜잭션 시스템을 은폐시키는데 당신이 프로그램 상의 트랜잭션 경계구분을 사용할 경우, 당신은 당신의 코드로부터 기본 트랜잭션 시스템을 은폐시키는데

View File

@ -48,8 +48,7 @@
</id> </id>
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, create table Person ( personId bigint not null primary key, addressId bigint not null )
addressId bigint not null )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -79,8 +78,7 @@ create table Address ( addressId bigint not null primary key )
</id> </id>
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, create table Person ( personId bigint not null primary key, addressId bigint not null unique )
addressId bigint not null unique )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -135,8 +133,7 @@ create table Address ( personId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, create table Address ( addressId bigint not null primary key, personId bigint not null )
personId bigint not null )
]]></programlisting> ]]></programlisting>
<para> <para>
@ -177,8 +174,7 @@ create table Address ( addressId bigint not null primary key,
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId not null, create table PersonAddress ( personId not null, addressId bigint not null primary key )
addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -211,8 +207,7 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
addressId bigint not null )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -247,8 +242,7 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
addressId bigint not null unique )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -279,9 +273,7 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
addressId bigint not null,
primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -319,8 +311,7 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, create table Person ( personId bigint not null primary key, addressId bigint not null )
addressId bigint not null )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -386,8 +377,7 @@ create table Address ( addressId bigint not null primary key )
property-ref="address"/> property-ref="address"/>
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key, create table Person ( personId bigint not null primary key, addressId bigint not null unique )
addressId bigint not null unique )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -459,8 +449,7 @@ create table Address ( personId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -505,8 +494,7 @@ create table Address ( addressId bigint not null primary key )
</class>]]></programlisting> </class>]]></programlisting>
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
addressId bigint not null unique )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>
@ -543,9 +531,7 @@ create table Address ( addressId bigint not null primary key )
<programlisting><![CDATA[ <programlisting><![CDATA[
create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
addressId bigint not null,
primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
]]></programlisting> ]]></programlisting>

View File

@ -92,7 +92,7 @@
<sect2 id="mapping-declaration-doctype" revision="2"> <sect2 id="mapping-declaration-doctype" revision="3">
<title>Doctype</title> <title>Doctype</title>
<para> <para>
@ -102,6 +102,56 @@
당신이 인터넷 연결을 사용하는 DTD에 대한 룩업들을 겪게 될 경우, 당신의 classpath의 컨텐츠에 대해 당신의 DTD 선언을 당신이 인터넷 연결을 사용하는 DTD에 대한 룩업들을 겪게 될 경우, 당신의 classpath의 컨텐츠에 대해 당신의 DTD 선언을
체크하라. 체크하라.
</para> </para>
<sect3 id="mapping-declaration-entity-resolution">
<title>EntityResolver</title>
<para>
앞서 언급했듯이, Hibernate는 먼저 그것의 classpath에서 DTD들을 해석하려고 시도할 것이다.
Hibernate가 이것을 행하는 방법은 그것이 xml 파일들을 읽어들이는데 사용하는 SAXReader에 맞춤형
<literal>org.xml.sax.EntityResolver</literal> 구현을 등록하는 것이다. 이 맞춤형
<literal>EntityResolver</literal>는 두 개의 다른 systemId namespace들을 인지해낸다.
</para>
<itemizedlist>
<listitem>
<para>
<literal>hibernate namespace</literal>는 resolver가
<literal>http://hibernate.sourceforge.net/</literal>로 시작하는 하나의
systemId와 만날때마다 인지된다; resolver는 Hibernate 클래스들을 로드시켰던 클래스로더를 통해
이들 엔티티들을 해석하려고 시도한다.
</para>
</listitem>
<listitem>
<para>
<literal>user namespace</literal>는 resolver가 <literal>classpath://</literal>
URL 프로토콜을 사용하는 systemId를 만날때마다 인지된다; resolver는 (1)현재 쓰레드 컨텍스트
클래스로더와 (2)Hibernate 클래스들을 로드시켰던 클래스로더를 통해 이들 엔티티들을 해석하려고
시도할 것이다.
</para>
</listitem>
</itemizedlist>
<para>
user namespacing을 활용하는 예제:
</para>
<programlisting><![CDATA[<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
<!ENTITY types SYSTEM "classpath://your/domain/types.xml">
]>
<hibernate-mapping package="your.domain">
<class name="MyEntity">
<id name="id" type="my-custom-id-type">
...
</id>
<class>
&types;
</hibernate-mapping>]]></programlisting>
<para>
여기서 <literal>types.xml</literal><literal>your.domain</literal> 패키지 내에 있는 리소스이고
맞춤형 <xref linkend="mapping-types-custom">typedef</xref>를 포함한다.
</para>
</sect3>
</sect2> </sect2>
<sect2 id="mapping-declaration-mapping" revision="3"> <sect2 id="mapping-declaration-mapping" revision="3">
@ -692,6 +742,17 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>sequence-identity</literal></term>
<listitem>
<para>
실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서
실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는
JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에
대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</para> </para>
@ -1082,7 +1143,7 @@
</para> </para>
</sect2> </sect2>
<sect2 id="mapping-declaration-timestamp" revision="3" > <sect2 id="mapping-declaration-timestamp" revision="4" >
<title>timestamp (옵션)</title> <title>timestamp (옵션)</title>
<para> <para>
@ -1090,7 +1151,7 @@
버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로 버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로
어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다. 어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다.
</para> </para>
<programlistingco> <programlistingco>
<areaspec> <areaspec>
<area id="timestamp1" coords="2 70"/> <area id="timestamp1" coords="2 70"/>
@ -1123,7 +1184,7 @@
가진 자바빈즈 스타일의 프로퍼티 이름. 가진 자바빈즈 스타일의 프로퍼티 이름.
</para> </para>
</callout> </callout>
<callout arearefs="timestamp3"> <callout arearefs="timestamp3">
<para> <para>
<literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>): <literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>):
Hibernate가 프로퍼티 값에 접근하는데 사용할 방도. Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
@ -1140,18 +1201,18 @@
<callout arearefs="timestamp5"> <callout arearefs="timestamp5">
<para> <para>
<literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>): <literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>):
Hibernate는 어느 장소로부터 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가? Hibernate는 어디서 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가?
Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야 하기 때문에 데이터베이스 기반의 데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야
timestamp들은 오버헤드를 초래하지만, 클러스터링된 환경들의 용도로 더 안전할 것이다. 또한 모든 하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든
<literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져 <literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져
는 반면에, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용에 대해 안전하지 않을 지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용 안전하지 않을
수 있음을 노트하라(예를 들면 오라클 8). 수 있음을 노트하라(예를 들면 오라클 8).
</para> </para>
</callout> </callout>
<callout arearefs="timestamp6"> <callout arearefs="timestamp6">
<para> <para>
<literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>): <literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다. 이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다.
<xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라. <xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라.
</para> </para>
</callout> </callout>
@ -2202,7 +2263,8 @@
<title>join</title> <title>join</title>
<para> <para>
<literal>&lt;join&gt;</literal> 요소를 사용하면, 한 개의 클래스의 프로퍼티들을 몇 개의 테이블들로 매핑시키는 것이 <literal>&lt;join&gt;</literal> 테이블들 사이에 1대일 관계가 존재할 때,
요소를 사용하여 하나의 클래스에 속한 프로퍼티들을 몇 개의 테이블들로 매핑시키는 것이
가능하다. 가능하다.
</para> </para>

View File

@ -28,8 +28,6 @@ session.close();]]></programlisting>
<para> <para>
당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다: 당신은 또한 second-level 캐시를 가진 상호작용이 완전하게 불가능한 프로세스 내에서 이런 종류의 작업을 행하고 싶어할 수도 있다:
You also might like to do this kind of work in a process where interaction with
the second-level cache is completely disabled:
</para> </para>
<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting> <programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
@ -94,7 +92,6 @@ tx.commit();
session.close();]]></programlisting> session.close();]]></programlisting>
</sect1> </sect1>
<sect1 id="batch-statelesssession"> <sect1 id="batch-statelesssession">
<title>StatelessSession 인터페이스</title> <title>StatelessSession 인터페이스</title>
@ -140,7 +137,7 @@ session.close();]]></programlisting>
</sect1> </sect1>
<sect1 id="batch-direct" revision="2"> <sect1 id="batch-direct" revision="3">
<title>DML-스타일 연산들</title> <title>DML-스타일 연산들</title>
<para> <para>
@ -151,9 +148,9 @@ session.close();]]></programlisting>
(<xref linkend="queryhql">HQL</xref>)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다. (<xref linkend="queryhql">HQL</xref>)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다.
</para> </para>
<para> <para>
<literal>UPDATE</literal><literal>DELETE</literal> 문장들의 유사-구문은 다음과 같다: <literal>UPDATE</literal><literal>DELETE</literal> 문장들에 대한 유사 구문은 다음과 같다:
<literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지 : <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지:
</para> </para>
<itemizedlist spacing="compact"> <itemizedlist spacing="compact">
@ -201,10 +198,34 @@ tx.commit();
session.close();]]></programlisting> session.close();]]></programlisting>
<para> <para>
한 개의 HQL <literal>DELETE</literal>를 실행하기 위해, 동일한 <literal>Query.executeUpdate()</literal> 메소드를 HQL <literal>UPDATE</literal> 문장들은 디폴트로 영향받는 엔티티들에 대한
사용하라: <xref linkend="mapping-declaration-version">version</xref> 또는
<xref linkend="mapping-declaration-timestamp">timestamp</xref> 프로퍼티 값들에 영향을 주지 않는다;
이것은 EJB3 명세서에서 유지되고 있다. 하지만 당신은 하이버네이트로 하여금 <literal>versioned update</literal>
사용을 통해 <literal>version</literal> 또는 <literal>timestamp</literal> 프로퍼티 값들을 적절하게
재설정하도록 강제할 수 있다. 이것은 <literal>UPDATE</literal> 키워드 뒤에 <literal>VERSIONED</literal> 키워드를
추가시켜서 성취된다.
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();]]></programlisting>
<para>
맞춤형 version 타입들(<literal>org.hibernate.usertype.UserVersionType</literal>)은
<literal>update versioned</literal> 문장과 함께 사용하는 것이 허용되지 않음을 노트하라.
</para> </para>
<para>
HQL <literal>DELETE</literal>를 실행하려면, 같은 메소드 <literal>Query.executeUpdate()</literal>
사용하라:
</para>
<programlisting><![CDATA[Session session = sessionFactory.openSession(); <programlisting><![CDATA[Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); Transaction tx = session.beginTransaction();

View File

@ -107,7 +107,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
schema="schema_name" schema="schema_name"
lazy="true|extra|false" lazy="true|extra|false"
inverse="true|false" inverse="true|false"
cascade="all|none|save-update|delete|all-delete-orphan" cascade="all|none|save-update|delete|all-delete-orphan|delete-orphan"
sort="unsorted|natural|comparatorClass" sort="unsorted|natural|comparatorClass"
order-by="column_name asc|desc" order-by="column_name asc|desc"
where="arbitrary sql where condition" where="arbitrary sql where condition"

View File

@ -184,8 +184,7 @@
<property name="purchaseDate"/> <property name="purchaseDate"/>
<property name="price"/> <property name="price"/>
<property name="quantity"/> <property name="quantity"/>
<many-to-one name="item" class="eg.Item"/> <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
<!-- class attribute is optional -->
</composite-element> </composite-element>
</set> </set>
</class>]]></programlisting> </class>]]></programlisting>

View File

@ -653,8 +653,15 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
선택할 것이다. 선택할 것이다.
<para> <para>
<emphasis role="strong">eg.</emphasis> <emphasis role="strong">eg.</emphasis>
<literal>on_close</literal> (디폴트) | <literal>after_transaction</literal> | <literal>auto</literal> (디폴트) | <literal>on_close</literal> |
<literal>after_statement</literal> | <literal>auto</literal> <literal>after_transaction</literal> | <literal>after_statement</literal>
</para>
<para>
이 설정이 <literal>SessionFactory.openSession</literal>로부터 반환된 <literal>Session</literal>들에만
영향을 준다는 점을 노트하라. <literal>SessionFactory.getCurrentSession</literal>을 통해 얻어진
<literal>Session</literal>들의 경우, 사용하기 위해 구성된 <literal>CurrentSessionContext</literal> 구현이
그들 <literal>Session</literal>들에 대한 연결 해제를 제어한다. <xref linkend="architecture-current-session"/>
보라.
</para> </para>
</entry> </entry>
</row> </row>
@ -864,7 +871,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</tgroup> </tgroup>
</table> </table>
<table frame="topbot" id="configuration-misc-properties" revision="9"> <table frame="topbot" id="configuration-misc-properties" revision="10">
<title>여러가지 프로퍼티들</title> <title>여러가지 프로퍼티들</title>
<tgroup cols="2"> <tgroup cols="2">
<colspec colname="c1" colwidth="1*"/> <colspec colname="c1" colwidth="1*"/>
@ -882,12 +889,12 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</entry> </entry>
<entry> <entry>
"현재" <literal>Session</literal>의 영역화를 위한 하나의 (맞춤) 방도를 "현재" <literal>Session</literal>의 영역화를 위한 하나의 (맞춤) 방도를
한다. 빌드되어 있는 방도들에 대한 추가 정보는 공한다. 빌드되어 있는 방도들에 대한 추가 정보는
<xref linkend="architecture-current-session"/>를 보라. <xref linkend="architecture-current-session"/>를 보라.
<para> <para>
<emphasis role="strong">예.</emphasis> <emphasis role="strong">예.</emphasis>
<literal>jta</literal> | <literal>thread</literal> | <literal>jta</literal> | <literal>thread</literal> |
<literal>custom.Class</literal> <literal>managed</literal> | <literal>custom.Class</literal>
</para> </para>
</entry> </entry>
</row> </row>
@ -899,7 +906,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
Chooses the HQL 파서 구현을 선택한다. Chooses the HQL 파서 구현을 선택한다.
<para> <para>
<emphasis role="strong">예.</emphasis> <emphasis role="strong">예.</emphasis>
<literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> 또는 <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
<literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal> <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
</para> </para>
</entry> </entry>
@ -909,7 +916,8 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<literal>hibernate.query.substitutions</literal> <literal>hibernate.query.substitutions</literal>
</entry> </entry>
<entry> <entry>
Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑(예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다). Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑
(예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다).
<para> <para>
<emphasis role="strong">예.</emphasis> <emphasis role="strong">예.</emphasis>
<literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal> <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
@ -921,8 +929,10 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<literal>hibernate.hbm2ddl.auto</literal> <literal>hibernate.hbm2ddl.auto</literal>
</entry> </entry>
<entry> <entry>
<literal>SessionFactory</literal>가 생성될 때 스키마 DDL을 데이터베이스로 자동적으로 유효성 검사하거나 내보내기 한다. <literal>create-drop</literal>의 경우, <literal>SessionFactory</literal>가 생성될 때, 자동적으로 유효성을 검사하거나
<literal>SessionFactory</literal>가 명시적으로 닫혀질 때,, 데이터베이스 스키마가 드롭될 것이다. schema DDL을 데이터베이스로 내보내기 한다. <literal>create-drop</literal>의 경우,
<literal>SessionFactory</literal>가 명시적으로 닫혀질 때 데이터베이스 스키마가
드롭될 것이다.
<para> <para>
<emphasis role="strong">예.</emphasis> <emphasis role="strong">예.</emphasis>
<literal>validate</literal> | <literal>update</literal> | <literal>validate</literal> | <literal>update</literal> |
@ -935,8 +945,10 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<literal>hibernate.cglib.use_reflection_optimizer</literal> <literal>hibernate.cglib.use_reflection_optimizer</literal>
</entry> </entry>
<entry> <entry>
런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티). Reflection은 문제가 발생할 시에 때때로 유용할 수 있고, 런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티).
당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라. 당신은 <literal>hibernate.cfg.xml</literal> Reflection은 문제가 발생할 시에 때때로 유용할 수 있고,
당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라.
당신은 <literal>hibernate.cfg.xml</literal>
속에 이 프로퍼티를 설정할수 없다. 속에 이 프로퍼티를 설정할수 없다.
<para> <para>
<emphasis role="strong">예.</emphasis> <emphasis role="strong">예.</emphasis>

View File

@ -6,7 +6,7 @@
그리고 Hibernate의 확장 기능의 구현을 허용해준다. 그리고 Hibernate의 확장 기능의 구현을 허용해준다.
</para> </para>
<sect1 id="objectstate-interceptors" revision="2"> <sect1 id="objectstate-interceptors" revision="3">
<title>인터셉터들</title> <title>인터셉터들</title>
<para> <para>
@ -106,7 +106,14 @@ public class AuditInterceptor extends EmptyInterceptor {
}]]></programlisting> }]]></programlisting>
<para> <para>
세션이 생성될 때 인터셉터가 지정될 것이다. 인터셉터들은 다음 두 개의 특징들로 나타난다: <literal>Session</literal>-영역화 그리고
<literal>SessionFactory</literal>-영역화.
</para>
<para>
<literal>Session</literal>-영역의 인터셉터는 세션이 하나의 <literal>Interceptor</literal>를 수용하는
오버로드된 SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때
지정된다.
</para> </para>
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting> <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
@ -116,23 +123,34 @@ public class AuditInterceptor extends EmptyInterceptor {
이 경우에, 인터셉터는 threadsafe이어야 한다. 이 경우에, 인터셉터는 threadsafe이어야 한다.
</para> </para>
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
<para>
<literal>SessionFactory</literal>-영역의 인터셉터는 <literal>SessionFactory</literal>을 빌드하기에 앞서
<literal>Configuration</literal> 객체에 등록된다. 이 경우에, 공급되는 인터셉터는 그 <literal>SessionFactory</literal>로부터
열려진 모든 세션들에 적용될 것이다; 하나의 세션이 사용할 인터셉터를 명시적으로 지정하여 열리지 않는 한 이것은 참이다.
<literal>SessionFactory</literal>-영역의 인터셉터들은 세션-지정적인 상태를 저장하지 않도록 주의하여 쓰레드-안전해야 한다.
왜냐하면 다중 세션들은 (잠정적으로) 이 인터셉터를 동시적으로 사용할 것이기 때문이다.
</para>
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting> <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
</sect1> </sect1>
<sect1 id="objectstate-events" revision="3"> <sect1 id="objectstate-events" revision="4">
<title>이벤트 시스템</title> <title>이벤트 시스템</title>
<para> <para>
만일 당신이 당신의 영속 계층에서 특별한 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>이벤트</emphasis> 만일 당신이 당신의 영속 계층에서 특 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>event</emphasis>
아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다. 아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
</para> </para>
<para> <para>
본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 당신은 <literal>LoadEvent</literal>, 본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다.
당신은 <literal>LoadEvent</literal>,
<literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는 <literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는
<literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때, <literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때,
Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입에 대한 구성된 이벤트 리스너에게 전달한다. Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입 구성된 이벤트 리스너에게 전달한다.
박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을 박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을
구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal><literal>LoadEventListener</literal> 인터페이스의 구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal><literal>LoadEventListener</literal> 인터페이스의
등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal> 등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal>
@ -146,10 +164,10 @@ public class AuditInterceptor extends EmptyInterceptor {
<para> <para>
맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate 맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate
out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고자 그리고/또는 확장하고자 원하는 이벤트들에 대해 out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고/하거나 확장하고자 원하는 이벤트들에 대해
적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로 적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로
등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다). 등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다).
다음은 맞춤형 load 이벤트 리스너에 대한 예제이다: 다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
</para> </para>
<programlisting><![CDATA[public class MyLoadListener implements LoadEventListener { <programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
@ -185,13 +203,13 @@ LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting> cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
<para> <para>
선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 <literal>&lt;listener/&gt;</literal> 선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 개의 <literal>&lt;listener/&gt;</literal>
요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을 요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을
공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다. 공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
</para> </para>
<para> <para>
컨피그레이션 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을 구성 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을
구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을 구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을
더 쉽게 해준다. 더 쉽게 해준다.
</para> </para>

View File

@ -538,7 +538,7 @@ alter table line_items
</class> </class>
]]></programlisting> ]]></programlisting>
</sect2> </sect2>
<sect2 id="example-mappings-content-discrimination"> <sect2 id="example-mappings-content-discrimination">
<title>내용 기반 판별</title> <title>내용 기반 판별</title>
<programlisting><![CDATA[<class name="Person" <programlisting><![CDATA[<class name="Person"

View File

@ -63,6 +63,7 @@
</subclass> </subclass>
</hibernate-mapping>]]></programlisting> </hibernate-mapping>]]></programlisting>
<sect2 id="inheritance-tableperclass" > <sect2 id="inheritance-tableperclass" >
<title>Table per class hierarchy</title> <title>Table per class hierarchy</title>

View File

@ -576,11 +576,24 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
만료되도록 구성되어 있을지라도) 또 다른 어플리케이션에 의해 영속 저장소에 대해 행해진 변경들을 결코 알지 못한다. 만료되도록 구성되어 있을지라도) 또 다른 어플리케이션에 의해 영속 저장소에 대해 행해진 변경들을 결코 알지 못한다.
</para> </para>
<para> <para revision="1">
디폴트로, Hibernate는 JVM-레벨의 캐싱에 EHCache를 사용한다. (JCS 지원은 이제 진부하게 되었고 Hibernate의 장래 버전에서 디폴트로, Hibernate는 JVM-레벨의 캐싱에 EHCache를 사용한다. (JCS 지원은 이제 진부하게 되었고 Hibernate의 장래 버전에서
제거될 것이다.) 당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여 제거될 것이다.) 당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여
<literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 다른 구현을 선택할 수도 <literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 다른 구현을 선택할 수도
있다. 있다.
You have the option to tell Hibernate which caching implementation to use by
specifying the name of a class that implements <literal>org.hibernate.cache.CacheProvider</literal>
using the property <literal>hibernate.cache.provider_class</literal>. Hibernate
comes bundled with a number of built-in integrations with open-source cache providers
(listed below); additionally, you could implement your own and plug it in as
outlined above. Note that versions prior to 3.2 defaulted to use EhCache as the
default cache provider; that is no longer the case as of 3.2.
당신은 <literal>hibernate.cache.provider_class</literal> 프로퍼티를 사용하여
<literal>org.hibernate.cache.CacheProvider</literal>를 구현하는 클래스의 이름을 지정함으로써 어느 캐싱 구현을
사용할 것인지를 Hibernate에게 알려주는 옵션을 갖는다. Hibernate는 (아래에 열거된) 오픈-소스 프로바이더들을 가진
많은 빌드되어 있는 통합들을 번들로 갖고 있다; 추가적으로 당신은 위에서 언급했듯이 그것에 당신 자신의 것을 구현할 수 있고 그것에
플러그 시킬 수 있다. 3.2 이번 버전들은 디플트 캐시 프로바이더로서 EhCache를 사용하도록 디포릍로 내장되어 있음을 노트하라;
버전 3.2의 경우에 그것은 더이상 디폴트 내장이 아니다.
</para> </para>
<table frame="topbot" id="cacheproviders" revision="1"> <table frame="topbot" id="cacheproviders" revision="1">

View File

@ -104,6 +104,7 @@ public class Cat {
준수할 네 개의 주요 규칙들이 다음에 있다: 준수할 네 개의 주요 규칙들이 다음에 있다:
</para> </para>
<sect2 id="persistent-classes-pojo-constructor" revision="1"> <sect2 id="persistent-classes-pojo-constructor" revision="1">
<title>아규먼트 없는 생성자를 구현하라 </title> <title>아규먼트 없는 생성자를 구현하라 </title>
@ -228,7 +229,8 @@ public class DomesticCat extends Cat {
<title><literal>equals()</literal><literal>hashCode()</literal> 구현하기</title> <title><literal>equals()</literal><literal>hashCode()</literal> 구현하기</title>
<para> <para>
만일 당신이 만일 당신이 다음의 경우라면, 당신은 <literal>equals()</literal><literal>hashCode()</literal>
메소드들을 오버라이드 시켜야 한다.
</para> </para>
<itemizedlist spacing="compact"> <itemizedlist spacing="compact">
<listitem> <listitem>
@ -244,10 +246,7 @@ public class DomesticCat extends Cat {
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para>
경우에 당신은 <literal>equals()</literal><literal>hashCode()</literal> 메소드들을 오버라이드 시켜야 한다.
</para>
<para> <para>
Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다. Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다.
따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게 따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게
@ -432,7 +431,7 @@ dynamicSession.close()
</sect1> </sect1>
<sect1 id="persistent-classes-tuplizers" revision="0"> <sect1 id="persistent-classes-tuplizers" revision="1">
<title>Tuplizer들</title> <title>Tuplizer들</title>
<para> <para>
@ -442,8 +441,8 @@ dynamicSession.close()
그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다. 그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다.
예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된 예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된
프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다. 프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다.
<literal>org.hibernate.tuple.EntityTuplizer</literal> 인터페이스와 <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 인터페이스와
<literal>org.hibernate.tuple.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의 <literal>org.hibernate.tuple.component.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의
Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할 Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할
책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다. 책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다.
</para> </para>
@ -476,7 +475,7 @@ dynamicSession.close()
public class CustomMapTuplizerImpl public class CustomMapTuplizerImpl
extends org.hibernate.tuple.DynamicMapEntityTuplizer { extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
// override the buildInstantiator() method to plug in our custom map... // override the buildInstantiator() method to plug in our custom map...
protected final Instantiator buildInstantiator( protected final Instantiator buildInstantiator(
org.hibernate.mapping.PersistentClass mappingInfo) { org.hibernate.mapping.PersistentClass mappingInfo) {

View File

@ -364,7 +364,6 @@ session.createCriteria(Cat.class, "cat")
</sect1> </sect1>
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인 <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인
사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. --> 사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. -->

View File

@ -1,5 +1,5 @@
<chapter id="queryhql"> <chapter id="queryhql">
<title>HQL: Hibernate Query Language</title> <title>HQL: 하이버네이트 질의 언어(Hibernate Query Language)</title>
<para> <para>
Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라; Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라;
@ -126,7 +126,7 @@
<programlisting><![CDATA[from Cat as cat <programlisting><![CDATA[from Cat as cat
left join cat.kittens as kitten left join cat.kittens as kitten
with kitten.bodyWeight > 10.0]]></programlisting> with kitten.bodyWeight > 10.0]]></programlisting>
<para> <para>
게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는 게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는
것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을 것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을
@ -147,7 +147,7 @@
inner join fetch cat.mate inner join fetch cat.mate
left join fetch cat.kittens child left join fetch cat.kittens child
left join fetch child.kittens]]></programlisting> left join fetch child.kittens]]></programlisting>
<para> <para>
(비록 <literal>scroll()</literal>이 사용될 수 있을지라도) <literal>fetch</literal> 구조체는 (비록 <literal>scroll()</literal>이 사용될 수 있을지라도) <literal>fetch</literal> 구조체는
<literal>iterate()</literal>를 사용하여 호출되는 질의들 내에 사용될 수 없음을 노트하라. 이들 오퍼레이션들이 결과 행들에 <literal>iterate()</literal>를 사용하여 호출되는 질의들 내에 사용될 수 없음을 노트하라. 이들 오퍼레이션들이 결과 행들에
@ -167,9 +167,9 @@
<programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting> <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
<programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting> <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
</sect1> </sect1>
<sect1 id="queryhql-joins-forms"> <sect1 id="queryhql-joins-forms">
<title>join 구문의 형식들</title> <title>join 구문의 형식들</title>
@ -564,6 +564,13 @@ where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting
numeric 값들이나 temporal 값들을 가독성 있는 문자열로 변환시키는 <literal>str()</literal> numeric 값들이나 temporal 값들을 가독성 있는 문자열로 변환시키는 <literal>str()</literal>
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>cast(... as ...)</literal>, 여기서 두번 째 아규먼트는 Hibernate 타입의 이름이고,
ANSI <literal>cast()</literal><literal>extract()</literal>가 기반 데이터베이스에 의해
지원될 경우에는 <literal>extract(... from ...)</literal>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수 조인된 인덱싱된 콜렉션의 alias들에 적용되는, HQL <literal>index()</literal> 함수
@ -576,29 +583,10 @@ where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting
함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>. 함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>cast(... as ...)</literal>, 여기서 두번 째 아규먼트는 Hibernate 타입의 이름이고,
ANSI <literal>cast()</literal><literal>extract()</literal>가 기본 데이터베이스에 의해 지원될 경우에는
<literal>extract(... from ...)</literal>
</para>
</listitem>
<listitem>
<para>
조인된 인덱싱된 콜렉션의 alias들을 적용하는 HQL <literal>index()</literal> 함수
</para>
</listitem>
<listitem>
<para>
콜렉션 값 경로 표현식들을 취하는 HQL 함수들: <literal>some, all, exists, any, in</literal>을 사용하여
양이 한정될 수 있는 특별한 <literal>elements()</literal><literal>indices</literal> 함수들과 함께
<literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal> 함수들.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>,
<literal>sin()</literal>과 같이 임의의 데이터베이스-지원 SQL 스칼라 함수 <literal>sin()</literal>과 같이 임의의 데이터베이스 지원 SQL 스칼라 함수
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -867,6 +855,10 @@ from Cat as cat]]></programlisting>
<para> <para>
select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다: select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다:
</para> </para>
<para>
select 목록 내에 하나 이상의 표현식을 가진 서브질의들의 경우, 당신은 튜플(tuple) 구조를 사용할 수 있다:
</para>
<programlisting><![CDATA[from Cat as cat <programlisting><![CDATA[from Cat as cat
where not ( cat.name, cat.color ) in ( where not ( cat.name, cat.color ) in (

View File

@ -1,216 +1,366 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<chapter id="querysql" revision="2"> <chapter id="querysql" revision="2">
<title>Native SQL</title> <title>Native SQL</title>
<para> <para>당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다.
당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 당신이 오라클의 질의 힌트들 또는 당신이 오라클의 질의 힌트들 또는 <literal>CONNECT</literal> 키워드와 같은
<literal>CONNECT</literal> 키워드와 같은 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다. 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다.
그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 이전 경로를 제공한다. 그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한
</para> 이전 경로를 제공한다.</para>
<para> <para>Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해
Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을 지정하는 것을 당신에게 허용해준다.</para>
지정하는 것을 당신에게 허용해준다.
</para>
<sect1 id="querysql-creating" revision="3"> <sect1 id="querysql-creating" revision="4">
<title><literal>SQLQuery</literal> 사용하기</title> <title><literal>SQLQuery</literal> 사용하기</title>
<para> <para>native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해
native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 제어되며, 그것은 제어되며, 그것은 <literal>Session.createSQLQuery()</literal>을 호출하여
<literal>Session.createSQLQuery()</literal>을 호출하여 획득된다. 극히 간단한 경우들에서 , 획득된다. 다음은 이 API를 질의에 사용하는 방법을 설명한다.</para>
우리는 다음 형식을 사용할 수 있다:
</para>
<programlisting><![CDATA[List cats = sess.createSQLQuery("select * from cats") <sect2>
.addEntity(Cat.class) <title>스칼라 질의들</title>
.list();]]></programlisting>
<para>이 질의는 다음을 지정했다:</para>
<itemizedlist> <para>가장 기본적인 SQL 질의는 스칼라들(값들)의 목록을 얻는
것이다.</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
]]></programlisting>
<para>이것들은 둘다 CATS 테이블 내에 있는 각각의 컬럼에 대한 스칼라 값들을 가진 Object
배열들의 List를 반환할 것이다. Hibernate는 반환되는 스칼라 값들의 실제 순서와 타입들을
도출하는데 ResultSetMetadata를 사용할 것이다.</para>
<para><literal>ResultSetMetadata</literal> 사용의 오버헤드를 피하거나
간단하게는 반환되는 것을 보다 명시적이게끔 하기 위해 우리는
<literal>addScalar()</literal>를 사용할 수 있다.</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
.addScalar("NAME", Hibernate.STRING)
.addScalar("BIRTHDATE", Hibernate.DATE)
]]></programlisting>
<para>이 질의는 다음을 지정했다:</para>
<itemizedlist>
<listitem> <listitem>
<para> <para>SQL 질의 문자열</para>
SQL 질의 문자열
</para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>반환할 컬럼들과 타입들</para>
그 질의에 의해 반환되는 엔티티
</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para> <para>이것은 여전히 Object 배열들을 반환할 것이지만, 이제 그것은
여기서, 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일한 것으로 가정된다. 이것은 조인 다중 테이블들을 가진 <literal>ResultSetMetdata</literal>를 사용하지 않을 것이고 대신에
SQL 질의들에 대해 문제가 될 수 있다. 왜냐하면 동일한 컬럼 이름들이 하나 이상의 테이블 들 내에 나타날 수도 있기 때문이다. 기반 결과셋으로부터 ID, NAME 그리고 BIRTHDATE 컬럼을 각각 Long, String
다음 형식은 컬럼 이름 중복에 대해 취약하지 않다: 그리고 Short 타입으로 반환할 것이다. 심지어 그 질의가 <literal>*</literal>
</para> 사용하고 세 개의 열거된 컬럼들 보다 더 많은 것을 반환할 수 있을지라도, 이것은
또한 오직 이들 세 개의 컬럼들 만이 반환될 것임을 의미한다.</para>
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat") <para>스칼라들 중 몇몇 또는 전부에 대한 타입 정보를 남겨두는 것이 가능하다.</para>
.addEntity("cat", Cat.class)
.list();]]></programlisting> <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS")
.addScalar("ID", Hibernate.LONG)
.addScalar("NAME")
.addScalar("BIRTHDATE")
]]></programlisting>
<para>이것은 본질적으로 앞의 것과 동일한 질의이지만, 이제
<literal>ResultSetMetaData</literal>는 ID의 타입이 명시적으로 지정되어 있으므로
NAME과 BIRTHDATE의 타입을 결정하는데 사용된다.</para>
<para>java.sql.Types returned from ResultSetMetaData이 Hibernate
타입들로 매핑되는 방법은 Dialect에 의해 제어된다. 만일 특정 타입이 매핑되지 않거나
예상되는 타입으로 귀결되지 않을 경우에 Dialect 내에 있는
<literal>registerHibernateType</literal>에 대한 호출들을 통해 그것을
맞춤화 시키는 것이 가능하다.</para>
</sect2>
<sect2>
<title>Entity 질의들</title>
<para>위의 질의들은 스칼라 값들을 반환하는 것, 결과셋들로부터 "원래의" 값들을
기본적으로 반환하는 것에 대한 전부였다. 다음은 <literal>addEntity()</literal>
통해 native sql 질의로부터 엔티티 객체들을 얻는 방법을 보여준다.</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class);
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);
]]></programlisting>
<para>이 질의는 다음을 지정했다:</para> <para>이 질의는 다음을 지정했다:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>SQL 질의 문자열</para>
Hibernate가 컬럼 alias들을 도입하기 위한, placeholder를 가진, SQL 질의 문자열
</para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>그 질의에 의해 반환되는 엔티티</para>
그 질의에 의해 반환된 엔티티와 그것의 SQL 테이블 alias
</para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para>
<literal>addEntity()</literal> 메소드는 SQL 테이블 alias를 반환된 엔티티 클래스와 연관지우고,
질의 결과 셋의 형태를 결정한다.
</para>
<para>
<literal>addJoin()</literal> 메소드는 다른 엔티티들과 콜렉션들에 대한 연관들을 로드시키는데 사용될 수 있다.
</para>
<programlisting><![CDATA[List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.addEntity("cat", Cat.class)
.addJoin("kitten", "cat.kittens")
.list();]]></programlisting>
<para>
native SQL 질의는 간단한 스칼라 값을 반환하거나 스칼라들과 엔티티들의 조합을 반환할 수도 있다.
</para>
<programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat") <para>Cat이 컬럼 ID, NAME 그리고 BIRTHDATE로서 매핑된다고 가정하면,
.addScalar("maxWeight", Hibernate.DOUBLE); 위의 질의들은 둘다 각각의 요소가 하나의 Cat 엔티티인 하나의 List를 반환할 것이다.</para>
.uniqueResult();]]></programlisting>
<para>당신은 당신의 hbm 파일들 내에 결과셋 매핑 정보를 대안저긍로 설명활 수 있고 당신의 질의들을 위해 그것들을
사용할 수 있다.</para>
<programlisting><![CDATA[List cats = sess.createSQLQuery( <para>만일 그 엔티티가 또 다른 엔티티에 대해 <literal>many-to-one</literal>
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" 매핑되어 있다면 또한 native 질의를 실행할 때 이것을 반환하는 것이 필수적고, 그 밖의 경우
) 데이터베이스 지정적인 "컬럼이 발견되지 않았습니다" 오류가 일어날 것이다. 추가적인
.setResultSetMapping("catAndKitten") 컬럼은 * 표기를 사용할 자동적으로 반환될 것이지만, 우리는 다음 <literal>Dog</literal>
.list();]]></programlisting> 대한 <literal>many-to-one</literal> 예제에서처럼 명시적인 것을 더 선호한다:</para>
</sect1> <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
]]></programlisting>
<sect1 id="querysql-aliasreferences"> <para>이것은 cat.getDog()이 고유하게 기능하는 것을 허용한다.</para>
<title>Alias 참조와 프로퍼티 참조</title> </sect2>
<para> <sect2>
위에서 사용된 <literal>{cat.*}</literal> 표기는 "모든 프로퍼티"에 대한 약어이다. 다른 방법으로, 당신은 명시적으로 컬럼들을 <title>연관들과 콜렉션들을 처리하기</title>
리스트할 수 있지만, 심지어 이 경우 조차도 우리는 Hibernate로 하여금 각각의 프로퍼티에 대해 SQL 컬럼 alias들을 끼워넣도록 해야 한다.
컬럼 alias에 대한 placeholder는 테이블 alias 수식어가 붙은 프로퍼티 이름이다. 다음 예제에서, 우리는 매핑 메타데이터에 선언된 <para>프락시를 초기화 시킴에 있어 가능한 특별한 라운드트립을 피하기 위해서
것에 대해 다른 테이블 (<literal>cat_log</literal>)로부터 <literal>Cat</literal>들을 검색한다. 우리는 심지어 우리가 <literal>Dog</literal>에서 eagerly join시키는 것이 간으하다. 이것은
좋아할 경우 where 절 속에 프로퍼티 alias들을 사용할 수도 있음을 주목하라. <literal>addJoin()</literal> 메소드를 통해 행해지는데, 그것은
</para> 연관이나 콜렉션 내에서 조인시키는 것을 당신에게 허용해준다.</para>
<para>
The <literal>{}</literal>-syntax is <emphasis>not</emphasis> required for named queries. <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
See <xref linkend="querysql-namedqueries"/> .addEntity("cat", Cat.class)
</para> .addJoin("cat.dog");
]]></programlisting>
<programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
"cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " + <para>이 예제에서 반환되는 <literal>Cat</literal>들은 데이터베이스에
"cat.weight*10 as {cat.weight}, cat.name as {cat.name} " + 대한 임의의 특별한 라운드크립 없이 전체적으로 초기화된 그것들의 <literal>dog</literal>
"from cat_log cat where {cat.mate} = :catId" 프로퍼티를 갖는다. 우리가 join의 대상 프로퍼티 경로를 지정하는 것을 가능하도록 하기 위해
하나의 alias 이름("cat")을 추가했음을 주지하라. 대신에 예를 들어 <literal>Cat</literal>
<literal>Dog</literal>에 대해 one-to-many를 가질 경우, 콜렉션들에 대해 동일한 eager joining을
행하는 것이 가능하다.</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
.addEntity("cat", Cat.class)
.addJoin("cat.dogs");
]]></programlisting>
<p>이 단계에서 우리는 Hibernate에서 native 질의들을 사용가능하도록 만들기 위해
sql 질의들을 강화시키지는 것을 시작하지 않고서도 native 질의들로서 가능한 것의 한계에
도달하고 있다; 문제점들은 동일한 타입의 여러 엔티티들을 반환할 때 또는 디폴트 alias/column
이름들이 충분하지 않을 때 발생하기 시작한다.</p>
</sect2>
<sect2>
<title>여러 개의 엔티티들을 반환하기</title>
<para>지금까지 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일하다고 가정되어 있다.
동일한 컬럼이 하나 이상의 테이블 내에서 나타날 수 있기 때문에, 이것은 여러 개의 테이블들을 조인시키는
SQL 질의들에 대해 문제가 될 수 있다.</para>
<para>컬럼 alias 주입은 다음 질의(아마 실패할 것이다)에서 필요하다:</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
]]></programlisting>
<para>이 질의의 목적은 단위 행 당 두 개의 Cat 인스턴스들, 하나의 cat 그리고 그것의 mother를
반환하는 것이다. 왜냐하면 그것들이 동일한 컬럼 이름들로 매핑되어 있기 때문에 이것은 실패할 것이고
데이베이스 상에서 반환된 컬럼 alias들은 아마 매핑들 내에 지정된 컬럼들("ID" 와 "NAME")과 같지 않은
"c.ID", "c.NAME" 등의 형식일 것이다.</para>
<para>다음 형식은 컬럼 이름 중복 취약점을 갖지 않는다:</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
.addEntity("cat", Cat.class)
.addEntity("mother", Cat.class)
]]></programlisting>
<para>이 질의는 다음을 지정했다:</para>
<itemizedlist>
<listitem>
<para>컬럼 alias들을 주입하기 위한 Hibernate용 placeholder들을 가진 SQL 질의 문자열</para>
</listitem>
<listitem>
<para>그 질의에 의해 반환되는 엔티티들</para>
</listitem>
</itemizedlist>
<para>위에 사용된 {cat.*} 과 {mother.*} 표기는 "모든 프로퍼티들"에 대한 생략이다.
다른 방법으로 당신은 컬럼들을 명시적으로 열거할 수도 있지만, 이 경우에 우리는 Hibernate로 하여금
SQL 컬럼 alias들을 각각의 컬럼에 주입시키도록 강제한다. 컬럼 alias를 위한 placeholder는 단지
그 테이블 alias에 의해 수식된 프로퍼티 이름이다. 다음 예제에서, 우리는 다른 테이블(cat_log)로부터
매핑 메타데이터 내에 선언된 것으로의 Cat들과 그것들의 mother들을 검색한다. 우리는 우리가 좋다면
심지어 where 절 내에 프로퍼티 alias를 사용할 수도 있음을 주지하라.</para>
<programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as {c.name}, " +
"BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
"FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
List loggedCats = sess.createSQLQuery(sql) List loggedCats = sess.createSQLQuery(sql)
.addEntity("cat", Cat.class) .addEntity("cat", Cat.class)
.setLong("catId", catId) .addEntity("mother", Cat.class).list()
.list();]]></programlisting> ]]></programlisting>
<para> <sect3 id="querysql-aliasreferences" revision="2">
<emphasis>노트:</emphasis> 만일 당신이 각각의 프로퍼티를 명시적으로 리스트할 경우, 당신은 그 클래스와 <title>alias 참조와 프로퍼티 참조</title>
<emphasis>그것의 서브클래스들</emphasis>의 모든 프로퍼티들을 포함해야 한다!
</para>
<para>
다음 테이블은 alias injection을 사용하는 다른 가능성들을 보여준다. 노트 : 결과 내에서 alias 이름들이 예제들이며, 각각의 alias는
사용될 시에 하나의 유일한 그리고 가능한 다른 이름을 가질 것이다.
</para>
<table frame="topbot" id="aliasinjection-summary"> <para>대부분의 경우에 위의 alias 주입이 필요하지만, composite 프로퍼티들, 상속 판별자들
<title>Alias injection 이름들</title> (inheritance discriminators), 콜렉션 등과 같은 보다 복잡한 매핑들과 관련된 질의들의 경우에는
고유한 alias들을 주입시키는 것을 Hibernate에게 허용하는데 사용될 몇몇 특별한 alias들이 존재한다.</para>
<para>다음 테이블은 alias 주입을 사용하는 다른 가능성들을 보여준다. 노트: 결과 내에 있는 alias 이름들이
예제이며, 각각의 alias는 사용될 때 하나의 유일한 이름과 아마 다른 이름을 가질 것이다.</para>
<tgroup cols="4"> <table frame="topbot" id="aliasinjection-summary">
<colspec colwidth="1*"/> <title>alias 주입 이름들</title>
<colspec colwidth="1*"/>
<colspec colwidth="2.5*"/>
<thead>
<row>
<entry>설명</entry>
<entry>구문</entry>
<entry>예제</entry>
</row>
</thead>
<tbody>
<row>
<entry>간단한 프로퍼티</entry>
<entry><literal>{[aliasname].[propertyname]</literal></entry>
<entry><literal>A_NAME as {item.name}</literal></entry>
</row>
<row>
<entry>composite 프로퍼티</entry>
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
</row>
<row>
<entry>엔티티의 판별자(Discriminator)</entry>
<entry><literal>{[aliasname].class}</literal></entry>
<entry><literal>DISC as {item.class}</literal></entry>
</row>
<row>
<entry>엔티티의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{item.*}</literal></entry>
</row>
<row>
<entry>콜렉션 키</entry>
<entry><literal>{[aliasname].key}</literal></entry>
<entry><literal>ORGID as {coll.key}</literal></entry>
</row>
<row>
<entry>콜렉션의 id</entry>
<entry><literal>{[aliasname].id}</literal></entry>
<entry><literal>EMPID as {coll.id}</literal></entry>
</row>
<row>
<entry>콜렉션의 요소</entry>
<entry><literal>{[aliasname].element}</literal></entry>
<entry><literal>XID as {coll.element}</literal></entry>
<entry></entry>
</row>
<row>
<entry>콜렉션 내에 있는 요소의 프로퍼티</entry>
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
<entry><literal>NAME as {coll.element.name}</literal></entry>
</row>
<row>
<entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].element.*}</literal></entry>
<entry><literal>{coll.element.*}</literal></entry>
</row>
<row>
<entry>콜렉션의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{coll.*}</literal></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1> <tgroup cols="3">
<colspec colwidth="1*" />
<colspec colwidth="1*" />
<colspec colwidth="2.5*" />
<thead>
<row>
<entry>설명</entry>
<entry>구문</entry>
<entry>예제</entry>
</row>
</thead>
<tbody>
<row>
<entry>간단한 프로퍼티</entry>
<entry><literal>{[aliasname].[propertyname]</literal></entry>
<entry><literal>A_NAME as {item.name}</literal></entry>
</row>
<row>
<entry>composite 프로퍼티</entry>
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
</row>
<row>
<entry>엔티티의 판별자(Discriminator)</entry>
<entry><literal>{[aliasname].class}</literal></entry>
<entry><literal>DISC as {item.class}</literal></entry>
</row>
<row>
<entry>엔티티의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{item.*}</literal></entry>
</row>
<row>
<entry>콜렉션 키</entry>
<entry><literal>{[aliasname].key}</literal></entry>
<entry><literal>ORGID as {coll.key}</literal></entry>
</row>
<row>
<entry>콜렉션의 id</entry>
<entry><literal>{[aliasname].id}</literal></entry>
<entry><literal>EMPID as {coll.id}</literal></entry>
</row>
<row>
<entry>콜렉션의 요소</entry>
<entry><literal>{[aliasname].element}</literal></entry>
<entry><literal>XID as {coll.element}</literal></entry>
<entry></entry>
</row>
<row>
<entry>콜렉션 내에 있는 요소의 프로퍼티</entry>
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
<entry><literal>NAME as {coll.element.name}</literal></entry>
</row>
<row>
<entry>콜렉션 내에 있는 요소의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].element.*}</literal></entry>
<entry><literal>{coll.element.*}</literal></entry>
</row>
<row>
<entry>콜렉션의 모든 프로퍼티들</entry>
<entry><literal>{[aliasname].*}</literal></entry>
<entry><literal>{coll.*}</literal></entry>
</row>
</tbody>
</tgroup>
</table>
</sect3>
</sect2>
<sect2>
<title>non-managed 엔티티들을 반환하기</title>
<para>native sql 질의에 ResultTransformer를 적용하는 것이 가능하다. 예를 들어
non-managed 엔티티들을 반환하기 위해 ResultTransformer를 허용하는 것.</para>
<programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS")
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
<para>이 질의는 다음을 지정했다:</para>
<itemizedlist>
<listitem>
<para>SQL 질의 문자열</para>
</listitem>
<listitem>
<para>결과 변환자(transformer)</para>
</listitem>
</itemizedlist>
<para>
위의 질의는 초기화되어 있고 NAME과 BIRTHNAME의 값들을 <literal>CatDTO</literal>
대응하는 프로퍼티들과 필드들 속으로 주입시킨 <literal>CatDTO</literal>의 리스트를 반환할 것이다.
</para>
</sect2>
<sect2>
<title>상속 처리하기</title>
<para>상속의 부분으로서 매핑되는 엔티티들을 질의하는 native sql 질의들은 baseclass의
모든 프로퍼티들을 포함해야 하고 그 모든 것이 서브클래스화 되어야 한다.</para>
</sect2>
<sect2>
<title>파라미터들</title>
<para>Native sql 질의들은 위치 파라미터들 뿐만 아니라 명명된 파라미터들을 지원한다:</para>
<programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class);
List pusList = query.setString(0, "Pus%").list();
query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class);
List pusList = query.setString("name", "Pus%").list(); ]]></programlisting>
</sect2>
</sect1>
<sect1 id="querysql-namedqueries" revision="3"> <sect1 id="querysql-namedqueries" revision="3">
<title>명명된 SQL 질의들</title> <title>명명된 SQL 질의들</title>
@ -219,7 +369,7 @@ List loggedCats = sess.createSQLQuery(sql)
<literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>. <literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>.
</para> </para>
<programlisting><![CDATA[<sql-query name="persons"> <programlisting><![CDATA[<sql-query name="persons">
<return alias="person" class="eg.Person"/> <return alias="person" class="eg.Person"/>
SELECT person.NAME AS {person.name}, SELECT person.NAME AS {person.name},
person.AGE AS {person.age}, person.AGE AS {person.age},
@ -228,16 +378,17 @@ List loggedCats = sess.createSQLQuery(sql)
WHERE person.NAME LIKE :namePattern WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<programlisting><![CDATA[List people = sess.getNamedQuery("persons") <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
.setString("namePattern", namePattern) .setString("namePattern", namePattern)
.setMaxResults(50) .setMaxResults(50)
.list();]]></programlisting> .list();]]></programlisting>
<para>
The <literal>&lt;return-join&gt;</literal> 요소와 <literal>&lt;load-collection&gt;</literal> <para><literal>&lt;return-join&gt;</literal> 요소와
요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을 정의하는데 사용된다. <literal>&lt;load-collection&gt;</literal>
</para> 요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을
정의하는데 사용된다.</para>
<programlisting><![CDATA[<sql-query name="personsWith"> <programlisting><![CDATA[<sql-query name="personsWith">
<return alias="person" class="eg.Person"/> <return alias="person" class="eg.Person"/>
<return-join alias="address" property="person.mailingAddress"/> <return-join alias="address" property="person.mailingAddress"/>
SELECT person.NAME AS {person.name}, SELECT person.NAME AS {person.name},
@ -253,12 +404,11 @@ List loggedCats = sess.createSQLQuery(sql)
WHERE person.NAME LIKE :namePattern WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para> <para>명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은
명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은 <literal>&lt;return-scalar&gt;</literal> 요소를 사용하여 <literal>&lt;return-scalar&gt;</literal> 요소를 사용하여
컬럼 alias와 Hibernate 타입을 선언해야 한다: 컬럼 alias와 Hibernate 타입을 선언해야 한다:</para>
</para>
<programlisting><![CDATA[<sql-query name="mySqlQuery"> <programlisting><![CDATA[<sql-query name="mySqlQuery">
<return-scalar column="name" type="string"/> <return-scalar column="name" type="string"/>
<return-scalar column="age" type="long"/> <return-scalar column="age" type="long"/>
SELECT p.NAME AS name, SELECT p.NAME AS name,
@ -288,16 +438,23 @@ List loggedCats = sess.createSQLQuery(sql)
WHERE person.NAME LIKE :namePattern WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<sect2 id="propertyresults"> <para>다른방법으로 당신은 당신의 hbm 파일들 내에 직접 자바 코드로 된 결과셋 매핑 정보를 사용할 수 있다.</para>
<title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
<programlisting><![CDATA[List cats = sess.createSQLQuery(
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
)
.setResultSetMapping("catAndKitten")
.list();]]></programlisting>
<sect2 id="propertyresults">
<title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
<para>Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해
<literal>{}</literal>-구문을 사용하는 것 대신에,
<literal>&lt;return-property&gt;</literal>로서 당신은 사용할
컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로 알려줄 수 있다.</para>
<para> <programlisting><![CDATA[<sql-query name="mySqlQuery">
Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해 <literal>{}</literal>-구문을 사용하는 것 대신에,
<literal>&lt;return-property&gt;</literal>로서 당신은 사용할 컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로
알려줄 수 있다.
</para>
<programlisting><![CDATA[<sql-query name="mySqlQuery">
<return alias="person" class="eg.Person"> <return alias="person" class="eg.Person">
<return-property name="name" column="myName"/> <return-property name="name" column="myName"/>
<return-property name="age" column="myAge"/> <return-property name="age" column="myAge"/>
@ -310,12 +467,11 @@ List loggedCats = sess.createSQLQuery(sql)
</sql-query> </sql-query>
]]></programlisting> ]]></programlisting>
<para> <para><literal>&lt;return-property&gt;</literal>는 또한 다중 컬럼들에 대해 동작한다.
<literal>&lt;return-property&gt;</literal>는 또한 다중 컬럼들에 대해 동작한다. 이것은 다중-컬럼 프로퍼티들에 이것은 다중-컬럼 프로퍼티들에 대한 fine grained 제어를 허용할 수 없는
대한 fine grained 제어를 허용할 수 없는 <literal>{}</literal>-구문을 가진 제약을 해결해준다. <literal>{}</literal>-구문을 가진 제약을 해결해준다.</para>
</para>
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
<return alias="emp" class="Employment"> <return alias="emp" class="Employment">
<return-property name="salary"> <return-property name="salary">
<return-column name="VALUE"/> <return-column name="VALUE"/>
@ -330,28 +486,22 @@ List loggedCats = sess.createSQLQuery(sql)
WHERE EMPLOYER = :id AND ENDDATE IS NULL WHERE EMPLOYER = :id AND ENDDATE IS NULL
ORDER BY STARTDATE ASC ORDER BY STARTDATE ASC
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para>
이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal>&lt;return-property&gt;</literal>
사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.
</para>
<para> <para>이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal>&lt;return-property&gt;</literal>
만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데 사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.</para>
<literal>&lt;return-discriminator&gt;</literal>를 사용해야 한다.
</para> <para>만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데
</sect2> <literal>&lt;return-discriminator&gt;</literal>를 사용해야 한다.</para>
</sect2>
<sect2 id="sp_query" revision="1"> <sect2 id="sp_query" revision="1">
<title>질의를 위한 내장 프로시저 사용하기</title> <title>질의를 위한 내장 프로시저 사용하기</title>
<para> <para>Hibernate 3은 내장 프로시저들과 함수들을 통한 질의 지원을 도입한다. 대부분의 다음 문서는 양자 모두에 동일하게 적용된다.
Hibernate 3은 내장 프로시저들과 함수들을 통한 질의 지원을 도입한다. 대부분의 다음 문서는 양자 모두에 동일하게 적용된다. 내장 프로시저/함수는 Hibernate와 동작하는 것이 가능하도록 첫 번째 out-파라미터로서 한 개의 결과셋을 반환해야 한다.
내장 프로시저/함수는 Hibernate와 동작하는 것이 가능하도록 첫 번째 out-파라미터로서 한 개의 결과셋을 반환해야 한다. Oracle9 이상의 버전에서 그런 내장 프로시저에 대한 예제는 다음과 같다:</para>
Oracle9 이상의 버전에서 그런 내장 프로시저에 대한 예제는 다음과 같다:
</para> <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR RETURN SYS_REFCURSOR
AS AS
st_cursor SYS_REFCURSOR; st_cursor SYS_REFCURSOR;
@ -363,12 +513,11 @@ BEGIN
FROM EMPLOYMENT; FROM EMPLOYMENT;
RETURN st_cursor; RETURN st_cursor;
END;]]></programlisting> END;]]></programlisting>
<para> <para>Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해
Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해 그것을 매핑할 필요가 있다. 그것을 매핑할 필요가 있다.</para>
</para>
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
<return alias="emp" class="Employment"> <return alias="emp" class="Employment">
<return-property name="employee" column="EMPLOYEE"/> <return-property name="employee" column="EMPLOYEE"/>
<return-property name="employer" column="EMPLOYER"/> <return-property name="employer" column="EMPLOYER"/>
@ -383,78 +532,61 @@ BEGIN
</return> </return>
{ ? = call selectAllEmployments() } { ? = call selectAllEmployments() }
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para>
내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal>&lt;return-join&gt;</literal>
<literal>&lt;load-collection&gt;</literal>은 지원되지 않는다.
</para>
<sect3 id="querysql-limits-storedprocedures" revision="1">
<title>내장 프로시저들을 사용하는 규칙들/제약들</title>
<para>
Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들/함수들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을
따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우,
당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장
프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.
</para>
<para> <para>내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal>&lt;return-join&gt;</literal>
내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다. <literal>&lt;load-collection&gt;</literal>은 지원되지 않는다.</para>
</para>
<para>권장되는 호출 형식은 표준 SQL92이다: <literal>{ ? = call <sect3 id="querysql-limits-storedprocedures" revision="1">
<title>내장 프로시저들을 사용하는 규칙들/제약들</title>
<para>Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들/함수들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을
따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우,
당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장
프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.</para>
<para>내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다.</para>
<para>권장되는 호출 형식은 표준 SQL92이다: <literal>{ ? = call
functionName(&lt;parameters&gt;) }</literal> 또는 <literal>{ ? = call functionName(&lt;parameters&gt;) }</literal> 또는 <literal>{ ? = call
procedureName(&lt;parameters&gt;}</literal>. Native 호출 구문은 지원되지 않는다.</para> procedureName(&lt;parameters&gt;}</literal>. Native 호출 구문은 지원되지 않는다.</para>
<para> <para>Oracle의 경우 다음 규칙들이 적용된다:</para>
Oracle의 경우 다음 규칙들이 적용된다:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>하나의 함수는 하나의 결과 셋을 반환해야 한다. 프로시저의 첫 번째 파라미터는 하나의 결과 셋을 반환하는
하나의 <literal>OUT</literal>이어야 한다. 이것은 Oracle 9 또는 10에서 하나의 <literal>SYS_REFCURSOR</literal>
사용하여 행해진다. Oracle에서 당신이 <literal>REF CURSOR</literal> 타입을 정의할 필요가 있다면, Oracle 보고서를 보라.
</para>
</listitem>
</itemizedlist>
<para>
Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로,
Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은
폐기될 것이다.
</para>
</listitem>
<listitem>
<para>
만일 당신이 당신의 프로시저 내에 <literal>SET NOCOUNT ON</literal>을 이용 가능하게 할 수 있다면 그것은 아마
보다 효율적이게 될 것이지만 이것은 필요 조건이 아니다.
</para>
</listitem>
</itemizedlist>
</sect3>
</sect2>
</sect1> <itemizedlist spacing="compact">
<listitem>
<para>하나의 함수는 하나의 결과 셋을 반환해야 한다. 프로시저의 첫 번째 파라미터는 하나의 결과 셋을 반환하는
하나의 <literal>OUT</literal>이어야 한다. 이것은 Oracle 9 또는 10에서 하나의
<literal>SYS_REFCURSOR</literal>를 사용하여 행해진다. Oracle에서 당신은
<literal>REF CURSOR</literal> 타입을 정의할 필요가 있는데, Oracle 보고서를 보라.</para>
</listitem>
</itemizedlist>
<sect1 id="querysql-cud"> <para>Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:</para>
<title>create, update 그리고 delete를 위한 맞춤형 SQL</title>
<para> <itemizedlist spacing="compact">
Hibernate3는 create, update, delete 오퍼레이션들을 위한 맞춤형 문장들을 사용할 수 있다. Hibernate에서 클래스와 콜렉션 <listitem>
영속자들은 구성 시에 생성된 문자열들의 집합(insertsql, deletesql, updatesql 등)을 이미 포함하고 있다. <para>프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로,
<literal>&lt;sql-insert&gt;</literal>, <literal>&lt;sql-delete&gt;</literal>, Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은
<literal>&lt;sql-update&gt;</literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다: 폐기될 것이다.</para>
</para> </listitem>
<listitem>
<para>만일 당신이 당신의 프로시저 내에 <literal>SET NOCOUNT ON</literal>을 이용 가능하게 할 수 있다면 그것은 아마
보다 효율적이게 될 것이지만 이것은 필요 조건이 아니다.</para>
</listitem>
</itemizedlist>
</sect3>
</sect2>
</sect1>
<programlisting><![CDATA[<class name="Person"> <sect1 id="querysql-cud">
<title>create, update 그리고 delete를 위한 맞춤형 SQL</title>
<para>Hibernate3는 create, update, delete 오퍼레이션들을 위한 맞춤형 문장들을 사용할 수 있다. Hibernate에서 클래스와 콜렉션
영속자들은 구성 시에 생성된 문자열들의 집합(insertsql, deletesql, updatesql 등)을 이미 포함하고 있다.
<literal>&lt;sql-insert&gt;</literal>, <literal>&lt;sql-delete&gt;</literal>,
<literal>&lt;sql-update&gt;</literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다:</para>
<programlisting><![CDATA[<class name="Person">
<id name="id"> <id name="id">
<generator class="increment"/> <generator class="increment"/>
</id> </id>
@ -464,14 +596,10 @@ BEGIN
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete> <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스
SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스 지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.</para>
지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.
</para>
<para> <para>만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:</para>
만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:
</para>
<programlisting><![CDATA[<class name="Person"> <programlisting><![CDATA[<class name="Person">
<id name="id"> <id name="id">
@ -483,24 +611,19 @@ BEGIN
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update> <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로,
위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로, 위치 파라미터들의 순서는 현재 절대적으로 중요하다. 위치 파라미터들의 순서는 현재 절대적으로 중요하다.</para>
</para>
<para>
당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수
있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다.
(예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에
두라.)
</para>
<para> <para>당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수
Hibernate가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘 있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다.
행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자 (예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에
출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다: 두라.)</para>
</para>
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2) <para>Hibernate가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘
행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자
출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다:</para>
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
RETURN NUMBER IS RETURN NUMBER IS
BEGIN BEGIN
@ -513,18 +636,14 @@ BEGIN
return SQL%ROWCOUNT; return SQL%ROWCOUNT;
END updatePerson;]]></programlisting> END updatePerson;]]></programlisting>
</sect1>
<sect1 id="querysql-load">
</sect1> <title>로딩을 위한 맞춤형 SQL</title>
<sect1 id="querysql-load"> <para>당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:</para>
<title>로딩을 위한 맞춤형 SQL</title>
<para> <programlisting><![CDATA[<sql-query name="person">
당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:
</para>
<programlisting><![CDATA[<sql-query name="person">
<return alias="pers" class="Person" lock-mode="upgrade"/> <return alias="pers" class="Person" lock-mode="upgrade"/>
SELECT NAME AS {pers.name}, ID AS {pers.id} SELECT NAME AS {pers.name}, ID AS {pers.id}
FROM PERSON FROM PERSON
@ -532,11 +651,9 @@ END updatePerson;]]></programlisting>
FOR UPDATE FOR UPDATE
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para> <para>이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:</para>
이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:
</para>
<programlisting><![CDATA[<class name="Person"> <programlisting><![CDATA[<class name="Person">
<id name="id"> <id name="id">
<generator class="increment"/> <generator class="increment"/>
</id> </id>
@ -544,20 +661,16 @@ END updatePerson;]]></programlisting>
<loader query-ref="person"/> <loader query-ref="person"/>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>이것은 심지어 내장 프로시저들에 동작한다.</para>
이것은 심지어 내장 프로시저들에 동작한다.
</para>
<para> <para>당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:</para>
당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:
</para>
<programlisting><![CDATA[<set name="employments" inverse="true"> <programlisting><![CDATA[<set name="employments" inverse="true">
<key/> <key/>
<one-to-many class="Employment"/> <one-to-many class="Employment"/>
<loader query-ref="employments"/> <loader query-ref="employments"/>
</set>]]></programlisting> </set>]]></programlisting>
<programlisting><![CDATA[<sql-query name="employments"> <programlisting><![CDATA[<sql-query name="employments">
<load-collection alias="emp" role="Person.employments"/> <load-collection alias="emp" role="Person.employments"/>
SELECT {emp.*} SELECT {emp.*}
@ -566,9 +679,7 @@ END updatePerson;]]></programlisting>
ORDER BY STARTDATE ASC, EMPLOYEE ASC ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
<para> <para>당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:</para>
당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:
</para>
<programlisting><![CDATA[<sql-query name="person"> <programlisting><![CDATA[<sql-query name="person">
<return alias="pers" class="Person"/> <return alias="pers" class="Person"/>
@ -579,7 +690,5 @@ END updatePerson;]]></programlisting>
ON pers.ID = emp.PERSON_ID ON pers.ID = emp.PERSON_ID
WHERE ID=? WHERE ID=?
</sql-query>]]></programlisting> </sql-query>]]></programlisting>
</sect1>
</sect1>
</chapter> </chapter>

View File

@ -413,7 +413,7 @@ cats.close()]]></programlisting>
</sect3> </sect3>
<sect3 id="objectstate-querying-executing-named"> <sect3 id="objectstate-querying-executing-named" revision="1">
<title>명명된 질의들을 구체화 시키기</title> <title>명명된 질의들을 구체화 시키기</title>
<para> <para>
@ -421,7 +421,7 @@ cats.close()]]></programlisting>
포함할 경우에 <literal>CDATA</literal> 섹션을 사용하는 것을 기억하라)) 포함할 경우에 <literal>CDATA</literal> 섹션을 사용하는 것을 기억하라))
</para> </para>
<programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[ <programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
from eg.DomesticCat as cat from eg.DomesticCat as cat
where cat.name = ? where cat.name = ?
and cat.weight > ? and cat.weight > ?
@ -431,7 +431,7 @@ cats.close()]]></programlisting>
파라미터 바인딩과 실행은 프로그램 상으로 행해진다: 파라미터 바인딩과 실행은 프로그램 상으로 행해진다:
</para> </para>
<programlisting><![CDATA[Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight"); <programlisting><![CDATA[Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name); q.setString(0, name);
q.setInt(1, minWeight); q.setInt(1, minWeight);
List cats = q.list();]]></programlisting> List cats = q.list();]]></programlisting>
@ -440,6 +440,13 @@ List cats = q.list();]]></programlisting>
실제 프로그램 코드는 사용되는 질의 언어에 독립적이고, 당신은 또한 메타데이터로 native SQL 질의들을 정의할 수도 있거나 실제 프로그램 코드는 사용되는 질의 언어에 독립적이고, 당신은 또한 메타데이터로 native SQL 질의들을 정의할 수도 있거나
그것들을 매핑 파일들 속에 기존 질의들을 위치지움으로써 기존 질의들을 Hibernate로 이전시킬 수도 있음을 노트하라. 그것들을 매핑 파일들 속에 기존 질의들을 위치지움으로써 기존 질의들을 Hibernate로 이전시킬 수도 있음을 노트하라.
</para> </para>
<para>
또한 <literal>&lt;hibernate-mapping&gt;</literal> 요소 내에서 하나의 질의 선언은 그 질의에 대한
전역 유일 이름을 필요로 하고, 반면에 <literal>&lt;class&gt;</literal> 요소 내에서의 질의 선언은
클래스 이름으로 수직된이름을 첨가하여 자동적으로 유일하게 만들어진다.
예를 들어 <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
</para>
</sect3> </sect3>

View File

@ -317,10 +317,7 @@
않다. 않다.
</para> </para>
<para> <para>
However, it is often desirable to keep your persistence layer portable between non-managed
resource-local environments, and systems that can rely on JTA but use BMT instead of CMT.
In both cases you'd use programmatic transaction demaracation.
하지만, CMT 대신 BMT를 사용하는 JTA에 의존할 수 있는 시스템들, 그리고 관리되지 않는 resource-local 환경들 사이에서 하지만, CMT 대신 BMT를 사용하는 JTA에 의존할 수 있는 시스템들, 그리고 관리되지 않는 resource-local 환경들 사이에서
당신의 영속 계층에 이식성을 유지시키는 것이 자주 희망된다. 두 경우들에서 당신은 프로그램 상의 트랜잭션 경계설정을 사용할 것이다. 당신의 영속 계층에 이식성을 유지시키는 것이 자주 희망된다. 두 경우들에서 당신은 프로그램 상의 트랜잭션 경계설정을 사용할 것이다.
Hibernate는 당신의 배치 환경의 고유한 트랜잭션 시스템 속으로 변환되는 <literal>Transaction</literal>이라 명명되는 Hibernate는 당신의 배치 환경의 고유한 트랜잭션 시스템 속으로 변환되는 <literal>Transaction</literal>이라 명명되는
@ -488,7 +485,7 @@ catch (RuntimeException e) {
tx.rollback(); tx.rollback();
throw e; // or display error message throw e; // or display error message
}]]></programlisting> }]]></programlisting>
<para> <para>
CMT의 경우, 트랜잭션 관할[경계 설정]은 프로그램 상이 아닌, session bean 배치 디스크립터들 속에서 행해진다. CMT의 경우, 트랜잭션 관할[경계 설정]은 프로그램 상이 아닌, session bean 배치 디스크립터들 속에서 행해진다.
그러므로 코드는 다음으로 감소된다: 그러므로 코드는 다음으로 감소된다:
@ -621,7 +618,7 @@ try {
sess.getTransaction().commit() sess.getTransaction().commit()
} }
catch (RuntimeException e) { catch (RuntimeException e) {
sess.getTransaction().rollback(); sess.getTransaction().rollback();
throw e; // or display error message throw e; // or display error message
} }
finally { finally {
@ -716,7 +713,6 @@ foo.setProperty("bar");
session.flush(); // Only for last transaction in conversation session.flush(); // Only for last transaction in conversation
t.commit(); // Also return JDBC connection t.commit(); // Also return JDBC connection
session.close(); // Only for last transaction in conversation]]></programlisting> session.close(); // Only for last transaction in conversation]]></programlisting>
<para> <para>
<literal>foo</literal> 객체는 그것이 로드되었던 <literal>Session</literal>이 어느 것인지를 여전히 알고 있다. <literal>foo</literal> 객체는 그것이 로드되었던 <literal>Session</literal>이 어느 것인지를 여전히 알고 있다.
이전 세션 상에서 하나의 새로운 데이터베이스 트랜잭션을 시작하는 것은 하나의 새로운 커넥션을 획득하고 그 세션을 소비한다. 이전 세션 상에서 하나의 새로운 데이터베이스 트랜잭션을 시작하는 것은 하나의 새로운 커넥션을 획득하고 그 세션을 소비한다.

View File

@ -1,18 +1,23 @@
<chapter id="tutorial"> <chapter id="tutorial">
<title>Hibernate 개요</title> <title>Hibernate 개요</title>
<sect1 id="tutorial-intro"> <sect1 id="tutorial-intro" revision="1">
<title>머리말</title> <title>머리말</title>
<para> <para>
이 장은 Hibernate 초심자를 위한 개론적인 튜토리얼이다. 우리는 메모리-내 데이터베이스를 이 장은 Hibernate 초심자를 위한 개론적인 튜토리얼이다. 우리는 메모리-내 데이터베이스를
사용하는 간단한 명령 라인 어플리케이션으로 시작하고 단계들을 이해하도록 쉽게 그것을 개발한다. 사용하는 간단한 명령 라인 어플리케이션으로 시작하고 단계들을 이해하도록 쉽게 그것을 개발한다.
</para> </para>
<para> <para>
이 튜토리얼은 Hibernate 신규 사용자들을 의도하고 있지만 Java와 SQL 지식을 필요로 한다. 이 튜토리얼은 Hibernate 신규 사용자들을 의도하고 있지만 Java와 SQL 지식을 필요로 한다.
그것은 Michael Gloegl이 작성한 튜토리얼에 기초한다. 그것은 Michael Gloegl이 작성한 튜토리얼에 기초하며, 우리가 명명하는 제 3의 라이브러리들은
JDK 1.4와 5.0 버전용이다. 당신은 JDK1.3에 대해 다른 라이브러리들을 필요로 할 수도 있다.
</para>
<para>
튜토리얼용 소스는 <literal>doc/reference/tutorial/</literal> 디렉토리 내에 있는
배포본 내에 포함되어 있다.
</para> </para>
</sect1> </sect1>
@ -62,14 +67,16 @@
다음으로 우리는 우리가 데이터베이스 속에 저장시키고자 원하는 이벤트를 표현하는 한 개의 클래스를 생성시킨다. 다음으로 우리는 우리가 데이터베이스 속에 저장시키고자 원하는 이벤트를 표현하는 한 개의 클래스를 생성시킨다.
</para> </para>
<sect2 id="tutorial-firstapp-firstclass"> <sect2 id="tutorial-firstapp-firstclass" revision="1">
<title>첫 번째 클래스</title> <title>첫 번째 클래스</title>
<para> <para>
우리의 첫 번째 영속 클래스는 몇몇 프로퍼티들을 가진 간단한 자바빈즈 클래스이다: 우리의 첫 번째 영속 클래스는 몇몇 프로퍼티들을 가진 간단한 자바빈즈 클래스이다:
</para> </para>
<programlisting><![CDATA[import java.util.Date; <programlisting><![CDATA[package events;
import java.util.Date;
public class Event { public class Event {
private Long id; private Long id;
@ -77,7 +84,7 @@ public class Event {
private String title; private String title;
private Date date; private Date date;
Event() {} public Event() {}
public Long getId() { public Long getId() {
return id; return id;
@ -107,18 +114,19 @@ public class Event {
<para> <para>
당신은 이 클래스가 프로퍼티 getter와 setter 메소드들에 대한 표준 자바빈즈 명명법들 뿐만 아니라 필드들에 대한 당신은 이 클래스가 프로퍼티 getter와 setter 메소드들에 대한 표준 자바빈즈 명명법들 뿐만 아니라 필드들에 대한
private 가시성을 사용하고 있음을 알 수 있다. 이것은 권장되는 설계이지만, 필수적이지는 않다. Hibernate는 private 가시성을 사용하고 있음을 알 수 있다. 이것은 권장되는 설계이지만, 필수적이지는 않다. Hibernate는
또한 필드들에 직접 접근할 수 있으며, accessor 메소드들의 이점은 강건한 리팩토링이다. 또한 필드들에 직접 접근할 수 있으며, accessor 메소드들의 이점은 강건한 리팩토링이다. 아규먼트 없는 생성자는
reflection을 통해 이 클래스의 객체를 초기화 시킬 필요가 있다.
</para> </para>
<para> <para>
<literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 만일 우리가 Hibernate의 <literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 모든 영속 엔티티 클래스들
전체 특징을 사용하고자 원할 경우 모든 영속 엔티티 클래스들(보다 덜 중요한 종속 클래스들 또한 존재한다)은 그런 (보다 덜 중요한 종속 클래스들도 존재한다)은 우리가 Hibernate의 전체 특징 집합을 사용하고자 원할 경우에
식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해 그런 식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해
객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제이라기 보다는 하나의 특징으로 간주할 것이다. 하지만 객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제약점이라기 보다는 하나의 특징으로 간주할 것이다. 하지만
우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때, 우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때,
Hibernate는 단지 식별자 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들 Hibernate는 단지 식별자들을 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들
뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려 뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려
있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다. 있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다.
</para> </para>
<para> <para>
@ -128,7 +136,7 @@ public class Event {
</para> </para>
<para> <para>
이 Java 스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제 이 Java 스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제
그 디렉토리는 다음과 같을 것이다: 그 디렉토리는 다음과 같을 것이다:
</para> </para>
@ -136,7 +144,8 @@ public class Event {
+lib +lib
<Hibernate and third-party libraries> <Hibernate and third-party libraries>
+src +src
Event.java]]></programlisting> +events
Event.java]]></programlisting>
<para> <para>
다음 단계에서, 우리는 Hiberante에게 이 영속 클래스에 대해 알려 준다. 다음 단계에서, 우리는 Hiberante에게 이 영속 클래스에 대해 알려 준다.
@ -144,8 +153,8 @@ public class Event {
</sect2> </sect2>
<sect2 id="tutorial-firstapp-mapping"> <sect2 id="tutorial-firstapp-mapping" revision="1">
<title>매핑 파일</title> <title>The mapping file</title>
<para> <para>
Hibernate는 영속 크래스들에 대한 객체들을 로드시키고 저장시키는 방법을 알 필요가 있다. Hibernate는 영속 크래스들에 대한 객체들을 로드시키고 저장시키는 방법을 알 필요가 있다.
@ -189,7 +198,7 @@ public class Event {
<programlisting><![CDATA[<hibernate-mapping> <programlisting><![CDATA[<hibernate-mapping>
<class name="Event" table="EVENTS"> <class name="events.Event" table="EVENTS">
</class> </class>
@ -204,9 +213,9 @@ public class Event {
<programlisting><![CDATA[<hibernate-mapping> <programlisting><![CDATA[<hibernate-mapping>
<class name="Event" table="EVENTS"> <class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID"> <id name="id" column="EVENT_ID">
<generator class="increment"/> <generator class="native"/>
</id> </id>
</class> </class>
@ -230,9 +239,9 @@ public class Event {
<programlisting><![CDATA[ <programlisting><![CDATA[
<hibernate-mapping> <hibernate-mapping>
<class name="Event" table="EVENTS"> <class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID"> <id name="id" column="EVENT_ID">
<generator class="increment"/> <generator class="native"/>
</id> </id>
<property name="date" type="timestamp" column="EVENT_DATE"/> <property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/> <property name="title"/>
@ -242,7 +251,9 @@ public class Event {
<para> <para>
<literal>id</literal> 요소의 경우처럼, <literal>property</literal> 요소의 <literal>name</literal> <literal>id</literal> 요소의 경우처럼, <literal>property</literal> 요소의 <literal>name</literal>
속성은 사용할 getter 및 setter 메소드들이 어느 것인지를 Hibernate에게 알려준다. 속성은 사용할 getter 및 setter 메소드들이 어느 것인지를 Hibernate에게 알려준다. 따라서 이 경우에 Hibernate는
<literal>getDate()/setDate()</literal> 뿐만 아니라 <literal>getTitle()/setTitle()</literal>
찾게 될 것이다.
</para> </para>
<para> <para>
@ -262,8 +273,9 @@ public class Event {
그 자체를 결정하려고 시도할 것이다. 몇몇 경우들에서 (Java 클래스에 대한 Reflection을 사용하는) 이 자동적인 검출은 그 자체를 결정하려고 시도할 것이다. 몇몇 경우들에서 (Java 클래스에 대한 Reflection을 사용하는) 이 자동적인 검출은
당신이 예상하거나 필요로 하는 디폴트를 갖지 않을 수도 있다. 이것은 <literal>date</literal> 프로퍼티를 가진 당신이 예상하거나 필요로 하는 디폴트를 갖지 않을 수도 있다. 이것은 <literal>date</literal> 프로퍼티를 가진
경우이다. Hibernate는 그 프로퍼티가 SQL <literal>date</literal> 컬럼, <literal>timestamp</literal> 경우이다. Hibernate는 그 프로퍼티가 SQL <literal>date</literal> 컬럼, <literal>timestamp</literal>
컬럼 또는 <literal>time</literal> 컬럼 중 어느 것으로 매핑되어야 하는지를 알 수가 없다. 우리는 <literal>timestamp</literal> 컬럼 또는 <literal>time</literal> 컬럼 중 어느 것으로 매핑되어야 하는지를 알 수가 없다. 우리는
가진 프로퍼티를 매핑함으로써 전체 날짜와 시간 정보를 보존하고 싶다고 선언한다. <literal>timestamp</literal> 컨버터를 가진 프로퍼티를 매핑함으로써 전체 날짜와 시간 정보를 보존하고 싶다고
선언한다.
</para> </para>
<para> <para>
@ -277,8 +289,9 @@ public class Event {
+lib +lib
<Hibernate and third-party libraries> <Hibernate and third-party libraries>
+src +src
Event.java +events
Event.hbm.xml]]></programlisting> Event.java
Event.hbm.xml]]></programlisting>
<para> <para>
우리는 Hibernate의 메인 구성을 계속 행한다. 우리는 Hibernate의 메인 구성을 계속 행한다.
@ -299,7 +312,7 @@ public class Event {
<para> <para>
개발 디렉토리의 루트에 <literal>data</literal>로 명명된 디렉토리를 생성시켜라 - 이 디렉토리는 개발 디렉토리의 루트에 <literal>data</literal>로 명명된 디렉토리를 생성시켜라 - 이 디렉토리는
HSQL DB가 그것의 데이터 파일들을 저장하게 될 장소이다. 이제 이 데이터 디렉토리에서 HSQL DB가 그것의 데이터 파일들을 저장하게 될 장소이다. 이제 이 데이터 디렉토리에서
<literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal>를 실행시켜서 <literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal>를 실행시켜서
데이터베이스를 시작시켜라. 당신은 그것이 시작되고 이것은 우리의 어플리케이션이 나중에 연결하게 될 장소인, 데이터베이스를 시작시켜라. 당신은 그것이 시작되고 이것은 우리의 어플리케이션이 나중에 연결하게 될 장소인,
하나의 TCP/IP 소켓에 바인드 되는 것을 볼 수 있다. 만일 이 튜토리얼 동안에 당신이 새 데이터베이스로 하나의 TCP/IP 소켓에 바인드 되는 것을 볼 수 있다. 만일 이 튜토리얼 동안에 당신이 새 데이터베이스로
시작하고자 원할 경우, HSQL DB를 셧다운시키고(왼도우에서 <literal>CTRL + C</literal>를 눌러라), 시작하고자 원할 경우, HSQL DB를 셧다운시키고(왼도우에서 <literal>CTRL + C</literal>를 눌러라),
@ -332,26 +345,29 @@ public class Event {
<!-- Database connection settings --> <!-- Database connection settings -->
<property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="connection.url">jdbc:hsqldb:data/tutorial</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property>
<property name="connection.username">sa</property> <property name="connection.username">sa</property>
<property name="connection.password"></property> <property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) --> <!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property> <property name="connection.pool_size">1</property>
<!-- For a HSQL 1.8 in-memory database, this is required -->
<property name="connection.shutdown">true</property>
<!-- SQL dialect --> <!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property> <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout --> <!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property> <property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup --> <!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property> <property name="hbm2ddl.auto">create</property>
<mapping resource="Event.hbm.xml"/> <mapping resource="events/Event.hbm.xml"/>
</session-factory> </session-factory>
@ -382,7 +398,7 @@ public class Event {
</sect2> </sect2>
<sect2 id="tutorial-firstapp-ant"> <sect2 id="tutorial-firstapp-ant" revision="1">
<title>Ant로 빌드하기</title> <title>Ant로 빌드하기</title>
<para> <para>
@ -393,16 +409,6 @@ public class Event {
명명되고 개발 디렉토리 속에 직접 위치될 것이다. 명명되고 개발 디렉토리 속에 직접 위치될 것이다.
</para> </para>
<note>
<title>Ant 설치</title>
<para>
디폴트로 Ant 배포본은 (FAQ에 설명되었듯이) 깨어져 있으며, 예를 들어, 만일 당신이 당신의 빌드 파일 내부에서
JUnit를 사용하고자 원할 경우 당신에 의해 정정되어야 한다. JUnit 태스크 작업을 행하기 위해(우리는 이
튜토리얼에서 그것을 필요로 하지 않을 것이다), junit.jar를 <literal>ANT_HOME/lib</literal>에 복사하거나
<literal>ANT_HOME/lib/ant-junit.jar</literal> 플러그인 스텁을 제거하라.
</para>
</note>
<para> <para>
기본 빌드 파일은 다음과 같다: 기본 빌드 파일은 다음과 같다:
</para> </para>
@ -460,7 +466,7 @@ Total time: 1 second ]]></programlisting>
</sect2> </sect2>
<sect2 id="tutorial-firstapp-helpers" revision="1"> <sect2 id="tutorial-firstapp-helpers" revision="3">
<title>시작과 helper들</title> <title>시작과 helper들</title>
<para> <para>
@ -478,12 +484,14 @@ Total time: 1 second ]]></programlisting>
유용하며, 우리는 현재의 작업 단위를 현재의 쓰레드와 연관지워 유지한다. 구현을 살펴보자: 유용하며, 우리는 현재의 작업 단위를 현재의 쓰레드와 연관지워 유지한다. 구현을 살펴보자:
</para> </para>
<programlisting><![CDATA[import org.hibernate.*; <programlisting><![CDATA[package util;
import org.hibernate.*;
import org.hibernate.cfg.*; import org.hibernate.cfg.*;
public class HibernateUtil { public class HibernateUtil {
public static final SessionFactory sessionFactory; private static final SessionFactory sessionFactory;
static { static {
try { try {
@ -496,25 +504,10 @@ public class HibernateUtil {
} }
} }
public static final ThreadLocal session = new ThreadLocal(); public static SessionFactory getSessionFactory() {
return sessionFactory;
public static Session getCurrentSession() throws HibernateException {
Session s = (Session) session.get();
// Open a new Session, if this thread has none yet
if (s == null) {
s = sessionFactory.openSession();
// Store it in the ThreadLocal variable
session.set(s);
}
return s;
} }
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
if (s != null)
s.close();
session.set(null);
}
}]]></programlisting> }]]></programlisting>
<para> <para>
@ -545,9 +538,11 @@ public class HibernateUtil {
+lib +lib
<Hibernate and third-party libraries> <Hibernate and third-party libraries>
+src +src
Event.java +events
Event.hbm.xml Event.java
HibernateUtil.java Event.hbm.xml
+util
HibernateUtil.java
hibernate.cfg.xml hibernate.cfg.xml
+data +data
build.xml]]></programlisting> build.xml]]></programlisting>
@ -567,7 +562,7 @@ build.xml]]></programlisting>
</sect2> </sect2>
<sect2 id="tutorial-firstapp-workingpersistence" revision="2"> <sect2 id="tutorial-firstapp-workingpersistence" revision="4">
<title>객체 로딩과 객체 저장</title> <title>객체 로딩과 객체 저장</title>
<para> <para>
@ -575,11 +570,13 @@ build.xml]]></programlisting>
메소드를 가진 한 개의 <literal>EventManager</literal> 클래스를 작성한다: 메소드를 가진 한 개의 <literal>EventManager</literal> 클래스를 작성한다:
</para> </para>
<programlisting><![CDATA[import org.hibernate.Transaction; <programlisting><![CDATA[package events;
import org.hibernate.Session; import org.hibernate.Session;
import java.util.Date; import java.util.Date;
import util.HibernateUtil;
public class EventManager { public class EventManager {
public static void main(String[] args) { public static void main(String[] args) {
@ -589,28 +586,24 @@ public class EventManager {
mgr.createAndStoreEvent("My Event", new Date()); mgr.createAndStoreEvent("My Event", new Date());
} }
HibernateUtil.sessionFactory.close(); HibernateUtil.getSessionFactory().close();
} }
}]]></programlisting> private void createAndStoreEvent(String title, Date theDate) {
<para> Session session = HibernateUtil.getSessionFactory().getCurrentSession();
우리는 명령 라인으로부터 몇몇 아규먼트들을 읽어들이고, 만일 첫 번째 아규먼트가 "store"이면, 우리는
새로운 Event를 생성시키고 저장시킨다:
</para>
<programlisting><![CDATA[private void createAndStoreEvent(String title, Date theDate) { session.beginTransaction();
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
Event theEvent = new Event(); Event theEvent = new Event();
theEvent.setTitle(title); theEvent.setTitle(title);
theEvent.setDate(theDate); theEvent.setDate(theDate);
session.save(theEvent); session.save(theEvent);
session.getTransaction().commit();
}
tx.commit();
HibernateUtil.closeSession();
}]]></programlisting> }]]></programlisting>
<para> <para>
@ -621,22 +614,31 @@ public class EventManager {
</para> </para>
<para> <para>
<literal>Session</literal>은 한 개의 작업 단위이다. 당신은 우리가 추가적인 API, <literal>Transaction</literal>dmf <literal>Session</literal>은 한 개의 작업 단위이다. 지금부터 우리는 단숨함을 유지할 것이고
갖고 있음에 놀랐을 수도 있다. 이것은 작업 단위가 한 개의 데이터베이스 트랜잭션보다 "더 긴" 경우일 수 있음을 의미한다 Hibernate <literal>Session</literal>과 데이터베이스 트랜잭션 사이의 일-대-일 과립형(granularity)을 가정할 것이다.
-웹 어플리케이션 속에서 여러 개의 Http 요청/응답 주기들(예를 들면 마법사 대화상자)에 걸치는 작업 단위를 상상하라. 실제 기반 트랜잭션 시스템으로부터 우리의 소스를 은폐시키기 위해(이 경우 통상의 JDBC이지만, 그것은 또한 JTA에도 실행된다)
지금 우리는 그것들을 간단하게 유지할 것이고 <literal>Session</literal> <literal>Transaction</literal> 우리는 Hibernate <literal>Session</literal> 상에서 이용 가능한 <literal>Transaction</literal> API를
이에 한 개의 one-to-one 입상을 가정할 것이다. 용한다.
</para> </para>
<para> <para>
<literal>Transaction.begin()</literal><literal>commit()</literal>은 무엇을 행하는가? <literal>sessionFactory.getCurrentSession()</literal>은 무엇을 행하는가? 먼저
잘못되는 경우들에서 <literal>rollback()</literal>은 어디에 있는가? Hibernate 당신은 당신이 (<literal>HibernateUtil</literal> 덕분에 쉽게) <literal>SessionFactory</literal>
<literal>Transaction</literal> API는 실제 옵션이지만, 우리는 편의와 이식성을 위해 그것을 사용한다. 당신이 소유하고 있다면, 원하는 만큼 어디서든 여러번 그것을 호출할 수 있다.
(예를 들어 <literal>session.connection.commit()</literal>을 호출함으로써)만일 당신 자신이 <literal>getCurrentSession()</literal> 메소드는 항상 "현재의" 작업 단위를 반환한다. 우리가
데이터베이스 트랜잭션을 처리했다면, 당신은 이 직접적인 관리되지 않는 JDBC로 특별한 배치 환경에 그 코드를 <literal>hibernate.cfg.xml</literal> 내에서 이 매커니즘에 대한 구성 옵션을 "thread"로 전환시켰음을 기억하는가?
바인드시켰다. 당신의 Hibernate 구성 속에서 <literal>Transaction</literal>을 위한 팩토리를 설정함으로써, 그러므로 현재 작업 단위의 영역은 우리의 어플리케이션을 실행시키는 현재의 Java 쓰레드이다. 하지만 이것은
당신은 당신의 영속 계층을 어디에서나 배치할 수 있다. 트랜잭션 처리와 관할에 대한 추가 정보는 전부가 진실은 아니다. 그것이 처음으로 필요로 되고, <literal>getCurrentSession()</literal>을 첫번째로
<xref linkend="transactions"/>를 살펴보라. 우리는 또한 이 예제에서 오류 핸들링과 롤백을 생략했다. 호출할 때 <literal>Session</literal>이 시작된다. 그때 현째의 쓰레드에 대해 Hibernate에 의해 바인드 된다.
트랜잭션이 종료될 때 커밋 되거나 롤백되고, Hibernate는 또한 쓰레드로부터 <literal>Session</literal>
바인드 해제시키고 당신을 위해 그것을 닫는다. 만일 당신이 <literal>getCurrentSession()</literal>을 다시
호출한다면, 당신은 새로운 <literal>Session</literal>을 얻고 새로운 작업단위를 시작할 수 있다. 이
<emphasis>thread-bound</emphasis> 프로그래밍 모형은 Hibernate를 사용하는 가장 대중적인 방법이다.
</para>
<para>
트랜잭션 핸들링과 경계구분에 대한 추가 정보는 <xref linkend="transactions"/>을 살펴보라.
우리는 또한 앞의 예제에서 임의의 오류 처리와 롤백을 생략했다.
</para> </para>
<para> <para>
@ -644,7 +646,7 @@ public class EventManager {
</para> </para>
<programlisting><![CDATA[<target name="run" depends="compile"> <programlisting><![CDATA[<target name="run" depends="compile">
<java classname="EventManager" classpathref="libraries"> <java fork="true" classname="events.EventManager" classpathref="libraries">
<classpath path="${targetdir}"/> <classpath path="${targetdir}"/>
<arg value="${action}"/> <arg value="${action}"/>
</java> </java>
@ -691,13 +693,14 @@ else if (args[0].equals("list")) {
</para> </para>
<programlisting><![CDATA[private List listEvents() { <programlisting><![CDATA[private List listEvents() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction(); Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List result = session.createQuery("from Event").list(); List result = session.createQuery("from Event").list();
tx.commit(); session.getTransaction().commit();
session.close();
return result; return result;
}]]></programlisting> }]]></programlisting>
@ -722,9 +725,9 @@ else if (args[0].equals("list")) {
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 프로퍼티를 주석처리함으로써 hbm2ddl을 이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 프로퍼티를 주석처리함으로써 hbm2ddl을
사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서 그것을 사용 가능하게 내버려두어도 되지만, 또 다른 사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서 그것을 사용 가능하게 내버려두어도 되지만, 또 다른
hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>드롭</emphasis>시킬 것이다 - <literal>create</literal> hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>drop</emphasis>시킬 것이다 - <literal>create</literal>
구성 설정은 실제로 "스키마로부터 모든 테이블들을 드롭시키고 나서, SessionFactory가 빌드될 때 모든 테이블들을 구성 설정은 실제로 "스키마로부터 모든 테이블들을 드롭시키고 나서, SessionFactory가 빌드될 때 모든 테이블들을
다시 생성시키는 것"으로 변환된다. 다시 생성시키는 것"으로 변환된다.
</para> </para>
@ -755,35 +758,38 @@ else if (args[0].equals("list")) {
우리는 우리의 어플리케이션에 사람들을 추가하고 그들이 참여하는 이벤트들의 목록을 저장할 것이다. 우리는 우리의 어플리케이션에 사람들을 추가하고 그들이 참여하는 이벤트들의 목록을 저장할 것이다.
</para> </para>
<sect2 id="tutorial-associations-mappinguser"> <sect2 id="tutorial-associations-mappinguser" revision="1">
<title>Person 클래스 매핑하기</title> <title>Person 클래스 매핑하기</title>
<para> <para>
클래스의 첫 번째 장면은 간단하다: 클래스의 첫 번째 장면은 간단하다:
</para> </para>
<programlisting><![CDATA[public class Person { <programlisting><![CDATA[package events;
public class Person {
private Long id; private Long id;
private int age; private int age;
private String firstname; private String firstname;
private String lastname; private String lastname;
Person() {} public Person() {}
// Accessor methods for all properties, private setter for 'id' // Accessor methods for all properties, private setter for 'id'
}]]></programlisting> }]]></programlisting>
<para> <para>
<literal>Person.hbm.xml</literal>로 명명된 새로운 매핑 파일을 생성시켜라: <literal>Person.hbm.xml</literal>로 명명되는 새로운 매핑 파일을 생성시켜라
(맨위에 DTD 참조를 잊지말라):
</para> </para>
<programlisting><![CDATA[<hibernate-mapping> <programlisting><![CDATA[<hibernate-mapping>
<class name="Person" table="PERSON"> <class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID"> <id name="id" column="PERSON_ID">
<generator class="increment"/> <generator class="native"/>
</id> </id>
<property name="age"/> <property name="age"/>
<property name="firstname"/> <property name="firstname"/>
@ -796,9 +802,8 @@ else if (args[0].equals("list")) {
마지막으로 새로운 매핑을 Hibernate의 구성에 추가하라: 마지막으로 새로운 매핑을 Hibernate의 구성에 추가하라:
</para> </para>
<programlisting><![CDATA[ <mapping resource="Event.hbm.xml"/> <programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
<mapping resource="Person.hbm.xml"/> <mapping resource="events/Person.hbm.xml"/>]]></programlisting>
]]></programlisting>
<para> <para>
이제 우리는 이들 두 개의 엔티티들 사이에 한 개의 연관을 생성시킬 것이다. 명백하게, 개인들은 이벤트들에 이제 우리는 이들 두 개의 엔티티들 사이에 한 개의 연관을 생성시킬 것이다. 명백하게, 개인들은 이벤트들에
@ -845,29 +850,6 @@ else if (args[0].equals("list")) {
사용한다: 사용한다:
</para> </para>
<programlisting><![CDATA[public class Person {
private Set events = new HashSet();
public Set getEvents() {
return events;
}
public void setEvents(Set events) {
this.events = events;
}
}]]></programlisting>
<para>
이 연관을 매핑시키기 전에, 다른 측에 대해 생각해보자. 명료하게 우리는 이것을 단방향으로 유지시킬 수 있다. 또는
만일 우리가 양방향으로 네비게이트하는 것을 가능하도록 하고자 원할 경우에, 우리는 <literal>Event</literal> 상의
또 다른 콜렉션을 생성시킬 수 있다. 예를 들면.<literal>anEvent.getParticipants()</literal>. 이것은
기능적인 관점에서 필수적이지 않다. 당신은 특정 이벤트에 대한 참여자들을 검색하기 위해 하나의 명시적인 질의를 항상
실행시킬 수 있다. 이것은 당신에게 설계상의 선택으로 남겨두지만, 이 논의에서 명료해지는 것은 그 연관의 다중성이다:
양 측들이 "many" 값을 가질 경우, 우리는 이것을 <emphasis>many-to-many</emphasis> 연관이라 명명한다. 그러므로,
우리는 Hibernate의 many-to-many 매핑을 사용한다:
</para>
<programlisting><![CDATA[<class name="events.Person" table="PERSON"> <programlisting><![CDATA[<class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID"> <id name="id" column="PERSON_ID">
<generator class="native"/> <generator class="native"/>
@ -882,6 +864,7 @@ else if (args[0].equals("list")) {
</set> </set>
</class>]]></programlisting> </class>]]></programlisting>
<para> <para>
Hibernate는 모든 종류의 콜렉션 매핑들, 가장 공통적인 <literal>&lt;set&gt;</literal>을 지원한다. many-to-many Hibernate는 모든 종류의 콜렉션 매핑들, 가장 공통적인 <literal>&lt;set&gt;</literal>을 지원한다. many-to-many
연관 (또는 <emphasis>n:m</emphasis> 엔티티 관계)의 경우, 한 개의 연관 테이블이 필요하다. 이 테이블 내에 있는 각각의 연관 (또는 <emphasis>n:m</emphasis> 엔티티 관계)의 경우, 한 개의 연관 테이블이 필요하다. 이 테이블 내에 있는 각각의
@ -912,7 +895,7 @@ else if (args[0].equals("list")) {
</sect2> </sect2>
<sect2 id="tutorial-associations-working" revision="1"> <sect2 id="tutorial-associations-working" revision="2">
<title>연관들에 작업하기</title> <title>연관들에 작업하기</title>
<para> <para>
@ -920,16 +903,16 @@ else if (args[0].equals("list")) {
</para> </para>
<programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) { <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction(); Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId); Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId); Event anEvent = (Event) session.load(Event.class, eventId);
aPerson.getEvents().add(anEvent); aPerson.getEvents().add(anEvent);
tx.commit(); session.getTransaction().commit();
HibernateUtil.closeSession();
}]]></programlisting> }]]></programlisting>
<para> <para>
@ -940,7 +923,9 @@ else if (args[0].equals("list")) {
프로퍼티를 변경함으로써 그것을 시도할 수 있다. 그것들이 <emphasis>영속(persistent)</emphasis> 상태에 있는 동안, 즉 특정 Hibernate 프로퍼티를 변경함으로써 그것을 시도할 수 있다. 그것들이 <emphasis>영속(persistent)</emphasis> 상태에 있는 동안, 즉 특정 Hibernate
<literal>Session</literal>에 바인드되어 있는 동안(예를 들면. 그것들은 작업 단위 속에 방금 로드되었거나 저장되었다), <literal>Session</literal>에 바인드되어 있는 동안(예를 들면. 그것들은 작업 단위 속에 방금 로드되었거나 저장되었다),
Hibernate는 임의의 변경들을 모니터링하고 쓰기 이면의 형태로 SQL을 실행시킨다. 메모리 상태를 데이터베이스와 동기화 시키는 Hibernate는 임의의 변경들을 모니터링하고 쓰기 이면의 형태로 SQL을 실행시킨다. 메모리 상태를 데이터베이스와 동기화 시키는
과정은 대개 오직 작업 단위의 끝에서이고, <emphasis>flushing</emphasis>이라 명명된다. 과정은 대개 오직 작업 단위의 끝에서이고, <emphasis>flushing</emphasis>이라 명명된다. 우리의 코드에서, 작업 단위는
<literal>CurrentSessionContext</literal> 클래스에 대한 <literal>thread</literal> 구성 옵션에 의해 정의된
대로 - 데이터베이스 트랜잭션의 커밋(또는 롤백)으로 끝이난다.
</para> </para>
<para> <para>
@ -949,41 +934,54 @@ else if (args[0].equals("list")) {
<emphasis>detached</emphasis>라고 부른다). (매우 사실적이지 않은) 코드 내에서 이것은 다음과 같을 수 있다: <emphasis>detached</emphasis>라고 부른다). (매우 사실적이지 않은) 코드 내에서 이것은 다음과 같을 수 있다:
</para> </para>
<programlisting><![CDATA[ private void addPersonToEvent(Long personId, Long eventId) { <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getCurrentSession(); Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction(); session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId); Person aPerson = (Person) session
Event anEvent = (Event) session.load(Event.class, eventId); .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId)
.uniqueResult(); // Eager fetch the collection so we can use it detached
tx.commit(); Event anEvent = (Event) session.load(Event.class, eventId);
HibernateUtil.closeSession();
aPerson.getEvents().add(anEvent); // aPerson is detached session.getTransaction().commit();
Session session2 = HibernateUtil.getCurrentSession(); // End of first unit of work
Transaction tx2 = session.beginTransaction();
session2.update(aPerson); // Reattachment of aPerson aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
tx2.commit(); // Begin second unit of work
HibernateUtil.closeSession();
} Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
]]></programlisting> session2.beginTransaction();
session2.update(aPerson); // Reattachment of aPerson
session2.getTransaction().commit();
}]]></programlisting>
<para> <para>
<literal>update</literal>에 대한 호출은 한 개의 detached 객체를 영속화 시키고, 당신은 그것이 새로운 작업 단위에 <literal>update</literal>에 대한 호출은 한 개의 detached 객체를 다시 영속화 시키고, 당신은 그것이 새로운 작업 단위에
바인드된다고 말할 수 있고, 따라서 detached 동안에 당신이 그것에 대해 행한 임의의 변경들이 데이터베이스에 저장될 수 있다. 바인드된다고 말할 수 있고, 따라서 detached 동안에 당신이 그것에 대해 행한 임의의 변경들이 데이터베이스에 저장될 수 있다.
이것은 당신이 그 엔티티 객체의 콜렉션에 대해 행했던 임의의 변경들(추가/삭제)를 포함한다.
</para> </para>
<para> <para>
물론, 이것은 우리의 현재 상황에서 많이 사용되지 않지만, 그것은 당신이 당신 자신의 어플리케이션 속으로 설계할 수 있는 중요한 물론, 우리의 현재 상황에서 이것은 많이 사용되지 않지만, 그것은 당신이 당신 자신의 어플리케이션 로 설계할 수 있는 중요한
개념이다. 지금 한 개의 새로운 액션을 <literal>EventManager</literal>의 main 메소드에 추가하고 명령 라인에서 그것을 개념이다. 지금 <literal>EventManager</literal>의 main 메소드에 한 개의 새로운 액션을 추가하고 명령 라인에서 그것을
호출하여 이 연습을 완료하라. 만일 당신이 한명의 개인과 한 개의 이벤트에 대한 식별자들을 필요로 할 경우 - <literal>save()</literal> 호출하여 이 연습을 완료하라. 만일 당신이 한명의 개인과 한 개의 이벤트에 대한 식별자들을 필요로 할 경우 - <literal>save()</literal>
메소드가 그것을 반환시킨다. 메소드가 그것을 반환시킨다(당신은 그 식별자를 반환시키는 앞의 메소드들 중 몇몇을 변경시켜야 할 것이다):
</para> </para>
<programlisting><![CDATA[else if (args[0].equals("addpersontoevent")) {
Long eventId = mgr.createAndStoreEvent("My Event", new Date());
Long personId = mgr.createAndStorePerson("Foo", "Bar");
mgr.addPersonToEvent(personId, eventId);
System.out.println("Added person " + personId + " to event " + eventId);
}]]></programlisting>
<para> <para>
이것은 두 개의 동등하게 중요한 클래스들, 두 개의 엔티티들 사이에서 한 개의 연관에 관한 예제였다. 앞서 언급했듯이, 전형적인 모형 내에는 이것은 두 개의 동등하게 중요한 클래스들, 두 개의 엔티티들 사이에서 한 개의 연관에 관한 예제였다. 앞서 언급했듯이, 전형적인 모형 내에는
다른 클래스들과 타이들이 존재하는데, 대개 "덜 중요하다". 당신은 이미 <literal>int</literal> 또는 <literal>String</literal> 다른 클래스들과 타이들이 존재하는데, 대개 "덜 중요하다". 당신은 이미 <literal>int</literal> 또는 <literal>String</literal>
@ -1065,9 +1063,29 @@ public void setEmailAddresses(Set emailAddresses) {
그것은 Java에서 동일한 코드이다. 그것은 Java에서 동일한 코드이다.
</para> </para>
<programlisting><![CDATA[private void addEmailToPerson(Long personId, String emailAddress) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId);
// The getEmailAddresses() might trigger a lazy load of the collection
aPerson.getEmailAddresses().add(emailAddress);
session.getTransaction().commit();
}]]></programlisting>
<para>
지금 우리는 콜렉션을 초기화 시키는데 <emphasis>fetch</emphasis> 질의를 사용하지 않았다.
그러므로 콜렉션의 getter 메소드에 대한 호출은 콜렉션을 초기화 시키기 위해 추가적인 select를 트리거 시킬
것이어서, 우리는 그것에 요소를 추가시킬 수 있다. SQL 로그를 관찰하고 이것을 eager fetch로 최적화 시키려고
시도하라.
</para>
</sect2> </sect2>
<sect2 id="tutorial-associations-bidirectional"> <sect2 id="tutorial-associations-bidirectional" revision="1">
<title>Bi-directional associations</title> <title>Bi-directional associations</title>
<para> <para>
@ -1097,7 +1115,7 @@ public void setParticipants(Set participants) {
<programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true"> <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
<key column="EVENT_ID"/> <key column="EVENT_ID"/>
<many-to-many column="PERSON_ID" class="Person"/> <many-to-many column="PERSON_ID" class="events.Person"/>
</set>]]></programlisting> </set>]]></programlisting>
<para> <para>
@ -1183,7 +1201,7 @@ public void removeFromEvent(Event event) {
그것은 새로운 이벤트들을 입력하기 위한 HTML form을 제공한다. 그것은 새로운 이벤트들을 입력하기 위한 HTML form을 제공한다.
</para> </para>
<sect2 id="tutorial-webapp-servlet"> <sect2 id="tutorial-webapp-servlet" revision="1">
<title>기본 서블릿 작성하기</title> <title>기본 서블릿 작성하기</title>
<para> <para>
@ -1198,17 +1216,9 @@ public void removeFromEvent(Event event) {
public class EventManagerServlet extends HttpServlet { public class EventManagerServlet extends HttpServlet {
private final SimpleDateFormat dateFormatter =
new SimpleDateFormat("dd.MM.yyyy");
// Servlet code // Servlet code
}]]></programlisting> }]]></programlisting>
<para>
<literal>dateFormatter</literal>는 나중에 문자열들로부터 그리고 문자열로 <literal>Date</literal> 객체들을
변환하는데 나중에 사용하게 될 도구이다. 서블릿의 멤버로서 오직 한 개의 formatter를 갖는 것이 도리에 맞다.
</para>
<para> <para>
서블릿은 HTTP <literal>GET</literal> 요청들 만을 처리하므로, 우리가 구현하는 메소드는 <literal>doGet()</literal>이다: 서블릿은 HTTP <literal>GET</literal> 요청들 만을 처리하므로, 우리가 구현하는 메소드는 <literal>doGet()</literal>이다:
</para> </para>
@ -1217,6 +1227,8 @@ public class EventManagerServlet extends HttpServlet {
HttpServletResponse response) HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
try { try {
// Begin unit of work // Begin unit of work
HibernateUtil.getSessionFactory() HibernateUtil.getSessionFactory()
@ -1259,7 +1271,7 @@ public class EventManagerServlet extends HttpServlet {
</sect2> </sect2>
<sect2 id="tutorial-webapp-processing"> <sect2 id="tutorial-webapp-processing" revision="1">
<title>프로세싱과 렌더링</title> <title>프로세싱과 렌더링</title>
<para> <para>
@ -1286,7 +1298,7 @@ if ( "store".equals(request.getParameter("action")) ) {
// Print page // Print page
printEventForm(out); printEventForm(out);
listEvents(out); listEvents(out, dateFormatter);
// Write HTML footer // Write HTML footer
out.println("</body></html>"); out.println("</body></html>");
@ -1315,7 +1327,8 @@ out.close();]]></programlisting>
쓰레드에 결합된 Hibernate <literal>Session</literal>을 사용한다: 쓰레드에 결합된 Hibernate <literal>Session</literal>을 사용한다:
</para> </para>
<programlisting><![CDATA[private void listEvents(PrintWriter out) { <programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
List result = HibernateUtil.getSessionFactory() List result = HibernateUtil.getSessionFactory()
.getCurrentSession().createCriteria(Event.class).list(); .getCurrentSession().createCriteria(Event.class).list();
if (result.size() > 0) { if (result.size() > 0) {

View File

@ -43,10 +43,10 @@
<fo:block> <fo:block>
<fo:external-graphic src="file:images/hibernate_logo_a.png"/> <fo:external-graphic src="file:images/hibernate_logo_a.png"/>
</fo:block> </fo:block>
<fo:block font-family="가을체" font-size="24pt" padding-before="10mm"> <fo:block font-family="Bangwool" font-size="18pt" padding-before="10mm">
<xsl:value-of select="bookinfo/subtitle"/> <xsl:value-of select="bookinfo/subtitle"/>
</fo:block> </fo:block>
<fo:block font-family="가을체" font-size="14pt" padding="10mm"> <fo:block font-family="Bangwool" font-size="12pt" padding="10mm">
버전: 버전:
<xsl:value-of select="bookinfo/releaseinfo"/> <xsl:value-of select="bookinfo/releaseinfo"/>
</fo:block> </fo:block>
@ -92,7 +92,7 @@
<xsl:variable name="Version"> <xsl:variable name="Version">
<xsl:choose> <xsl:choose>
<xsl:when test="//releaseinfo"> <xsl:when test="//releaseinfo">
<xsl:text>하이버네이트 </xsl:text> <xsl:text>하이버네이트</xsl:text>
<xsl:value-of select="//releaseinfo"/> <xsl:value-of select="//releaseinfo"/>
</xsl:when> </xsl:when>
<xsl:otherwise> <xsl:otherwise>
@ -256,10 +256,10 @@
################################################### --> ################################################### -->
<!-- Default Font size --> <!-- Default Font size -->
<xsl:param name="body.font.master">11</xsl:param> <xsl:param name="body.font.master">10</xsl:param>
<!-- Line height in body text --> <!-- Line height in body text -->
<xsl:param name="line-height">1.4</xsl:param> <xsl:param name="line-height">1.6</xsl:param>
<!-- Monospaced fonts are smaller than regular text --> <!-- Monospaced fonts are smaller than regular text -->
<xsl:attribute-set name="monospace.properties"> <xsl:attribute-set name="monospace.properties">
@ -311,7 +311,6 @@
<l:template name="sect4" text="the section called %t"/> <l:template name="sect4" text="the section called %t"/>
<l:template name="sect5" text="the section called %t"/> <l:template name="sect5" text="the section called %t"/>
</l:context> </l:context>
</l:l10n> </l:l10n>
</l:i18n> </l:i18n>
@ -516,9 +515,9 @@
<!-- Korean related Settings --> <!-- Korean related Settings -->
<xsl:param name="hyphenate">false</xsl:param> <xsl:param name="hyphenate">false</xsl:param>
<xsl:param name="body.font.family">Gulim</xsl:param> <xsl:param name="body.font.family">Hankc</xsl:param>
<!-- xsl:param name="monospace.font.family">가을체</xsl:param--> <!-- xsl:param name="monospace.font.family">Bangwool</xsl:param-->
<xsl:param name="title.font.family">가을체</xsl:param> <xsl:param name="title.font.family">Bangwool</xsl:param>
<xsl:param name="saxon.character.representation" select="native"/> <xsl:param name="saxon.character.representation" select="native"/>
<xsl:param name="callout.unicode" select="1"/> <xsl:param name="callout.unicode" select="1"/>
<xsl:param name="callout.unicode.start.character" select="10102"/> <xsl:param name="callout.unicode.start.character" select="10102"/>