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:
parent
cff47ee5ba
commit
1873cef798
|
@ -9,28 +9,56 @@
|
|||
Blog : http://blog.naver.com/jdkim528/
|
||||
|
||||
[Down/Config/Build]
|
||||
cvs 클라이언트를 갖고 있다면,
|
||||
1)연결 유형 : pserve/extssh 중 하나를 선택합니다
|
||||
2)사용자이름 : anonymous
|
||||
3)호스트 : cvs.sourceforge.net
|
||||
4)포트 : 기본값
|
||||
5)저장소경로 : /cvsroot/hibernate
|
||||
6)모듈 : Hibernate3/doc/reference
|
||||
위와 같이 연결 정보를 입력 하신 후 REFERENCE 전체를 내려받으셔도 되지만,
|
||||
한글 번역본만 필요하시다면 다음과 같이 하셔도 됩니다.
|
||||
[가]. 공통 모듈 받기
|
||||
위에서 6)모듈을 Hibernate3/doc/reference/support로 지정하시고
|
||||
로컬 컴퓨터의 디렉토리 [로컬 경로]/reference/ 하에 받습니다
|
||||
[나]. 한글본 모듈 받기
|
||||
위에서 6)모듈을 Hibernate3/doc/reference/ko로 지정하고
|
||||
로컬 컴퓨터의 디렉토리 [로컬 경로]/reference/ 하에 받습니다.
|
||||
[다]. 빌드 파일 받기
|
||||
그런 다음 /doc/reference/build.xml 파일을 내려 받은 다음
|
||||
* 기존의 CVS에서 SVN으로 바뀌면서 신규 사용자들을 위한 길잡이를 작성할 필요가
|
||||
생겼네요...
|
||||
|
||||
필자는 개인적으로 TortoiseSVN과 Subclipse를 사용하고 있으나 Subclpse를 중심으로
|
||||
설명할까 합니다.(선호하는 svn 클라이언트가 있다면 해당 클라이언트의 설정에
|
||||
따라 설정한 후에 사용하셔도 될 것입니다.)
|
||||
|
||||
[Subclipse 설치]
|
||||
|
||||
Subclipse를 설치하는 방법은 http://subclipse.tigris.org/install.html 을 참조하여
|
||||
eclipse의 도움말>소프트웨어갱신>찾기 및 설치 메뉴를 통해 쉽게 설치할 수 있습니다.
|
||||
|
||||
[Subclipse Checkout]
|
||||
0) Subclipse 설치가 끝났으면 이클립스를 재시작하십시오.
|
||||
1) 이클립스의 Perspective 열기에서 SVN Repository exploring을 열어 저장소를 등록하여 사용하거나
|
||||
이클립스의 패키지 탐색기에서 마우스 오른쪽 팝업 메뉴에서 "프로젝트"를 생성시킵니다.
|
||||
여기서는 "프로젝트" 생성 방법을 설명합니다.
|
||||
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로 빌드하시면 됩니다.
|
||||
빌드 시간은 2분 가량 소요됩니다.
|
||||
[마]. 문서 보기
|
||||
[나]. 문서 보기
|
||||
디렉토리 [로컬 경로]/reference/build/ko/ 디렉토리에 빌드된 문서를 보시기 바랍니다.
|
||||
그럼 하이버네이트와 함께 즐거운 시간을 보내세요.
|
||||
|
||||
|
|
|
@ -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>
|
||||
-->
|
||||
<font metrics-file="Gulim.xml" kerning="yes" embed-file="gulim.ttc">
|
||||
<font-triplet name="Gulim" style="normal" weight="normal"/>
|
||||
<font-triplet name="Gulim" style="normal" weight="bold"/>
|
||||
<font-triplet name="Gulim" style="italic" weight="normal"/>
|
||||
<font-triplet name="Gulim" style="italic" weight="bold"/>
|
||||
<font metrics-file="Hankc.xml" kerning="yes" embed-file="Hankc.ttf">
|
||||
<font-triplet name="Hankc" style="normal" weight="normal"/>
|
||||
<font-triplet name="Hankc" style="normal" weight="bold"/>
|
||||
<font-triplet name="Hankc" style="italic" weight="normal"/>
|
||||
<font-triplet name="Hankc" style="italic" weight="bold"/>
|
||||
</font>
|
||||
<font metrics-file="Gaeul.xml" kerning="yes" embed-file="Gaeul.ttf">
|
||||
<font-triplet name="가을체" style="normal" weight="normal"/>
|
||||
<font-triplet name="가을체" style="normal" weight="bold"/>
|
||||
<font-triplet name="가을체" style="italic" weight="normal"/>
|
||||
<font-triplet name="가을체" style="italic" weight="bold"/>
|
||||
<font metrics-file="Bangwool.xml" kerning="yes" embed-file="Bangwool.ttf">
|
||||
<font-triplet name="Bangwool" style="normal" weight="normal"/>
|
||||
<font-triplet name="Bangwool" style="normal" weight="bold"/>
|
||||
<font-triplet name="Bangwool" style="italic" weight="normal"/>
|
||||
<font-triplet name="Bangwool" style="italic" weight="bold"/>
|
||||
</font>
|
||||
</fonts>
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<bookinfo lang="ko">
|
||||
<title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title>
|
||||
<subtitle>하이버네이트 참조 문서</subtitle>
|
||||
<releaseinfo lang="ko">3.1</releaseinfo>
|
||||
<releaseinfo lang="ko">3.2 cr3</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<toc lang="ko" />
|
||||
|
|
|
@ -78,19 +78,19 @@
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Persistent objects and collections</term>
|
||||
<term>영속 객체들과 콜렉션들</term>
|
||||
<listitem>
|
||||
<para>
|
||||
persistent 상태와 비지니스 기능을 포함하는 수명이 짧고, 단일 쓰레드인 객체들. 이것들은 통상의 JavaBeans/POJO들일
|
||||
수 있고, 오직 그것들에 대한 오직 특별한 것은 그것들이 현재 (정확하게 한 개의) <literal>Session</literal>과 연관되어
|
||||
있다는 점이다. <literal>Session</literal>이 닫히자마자, 그것들은 분리될(detached 상태가 될) 것이고 어플리케이션
|
||||
레이어에서 사용하는 것이 자유로와진다(예를 들면. 프리젠테이션으로의 데이터 전송 객체들로서 직접적으로 그리고 프리젠테이션으로부터
|
||||
데이터 전송 객체들로서 직접으로).
|
||||
레이어에서 사용하는 것이 자유로와진다(예를 들면. 직접적으로 프리젠테이션 계층으로
|
||||
데이터 전송 객체들로서 그리고 직접적으로 프리젠테이션 계층으로부터 데이터 전송 객체들로서).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Transient and detached objects and collections</term>
|
||||
<term>전이(Transient, 필자 주-과도) 객체들과 콜렉션들</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session</literal>과 현재 연관되어 있지 않은 영속 클래스들의 인스턴스들. 그것들은 어플리케이션에 의해 초기화
|
||||
|
@ -236,7 +236,7 @@
|
|||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-current-session" revision="1">
|
||||
<sect1 id="architecture-current-session" revision="2">
|
||||
<title>컨텍스트 상의 세션들</title>
|
||||
<para>
|
||||
Hibernate를 사용하는 대부분의 어플리케이션들은 어떤 양식의 "컨텍스트상의(contextual)" 세션들을 필요로 한다. 여기서
|
||||
|
@ -264,7 +264,7 @@
|
|||
<para>
|
||||
그것의 계약에 대한 상세한 논의는 <literal>org.hibernate.context.CurrentSessionContext</literal> 인터페이스에
|
||||
관한 javadocs를 보라. 그것은 하나의 메소드, <literal>currentSession()</literal>를 정의하며, 그 구현은
|
||||
현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 구 개의 구현들을 부수적으로
|
||||
현재의 컨텍스트 상의 세션을 추적할 책임이 있다. 비공식적으로, Hibernate는 이 인터페이스에 대한 세 개의 구현들을 부수적으로
|
||||
포함하고 있다.
|
||||
</para>
|
||||
|
||||
|
@ -284,7 +284,7 @@
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는
|
||||
처음의 두 구현들은 <emphasis>session-per-request</emphasis>로 알려지고 사용되고 있는
|
||||
"하나의 세션 - 하나의 데이터베이스 트랜잭션" 프로그래밍 모형을 제공한다. 하나의 Hibernate 세션의 시작과 끝은
|
||||
데이터베이스 트랜잭션의 존속 기간에 의해 정의된다. 만일 (예를 들면 순수 J2SE에서 또는 JTA/UserTransaction/BMT의 경우에)
|
||||
당신이 프로그램 상의 트랜잭션 경계구분을 사용할 경우, 당신은 당신의 코드로부터 기본 트랜잭션 시스템을 은폐시키는데
|
||||
|
|
|
@ -48,8 +48,7 @@
|
|||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null )
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -79,8 +78,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -135,8 +133,7 @@ create table Address ( personId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key,
|
||||
personId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key, personId bigint not null )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -177,8 +174,7 @@ create table Address ( addressId bigint not null primary key,
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId not null,
|
||||
addressId bigint not null primary key )
|
||||
create table PersonAddress ( personId not null, addressId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -211,8 +207,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key,
|
||||
addressId bigint not null )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -247,8 +242,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -279,9 +273,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null,
|
||||
addressId bigint not null,
|
||||
primary key (personId, addressId) )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -319,8 +311,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null )
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -386,8 +377,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
property-ref="address"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -459,8 +449,7 @@ create table Address ( personId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null,
|
||||
addressId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -505,8 +494,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
@ -543,9 +531,7 @@ create table Address ( addressId bigint not null primary key )
|
|||
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null,
|
||||
addressId bigint not null,
|
||||
primary key (personId, addressId) )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
|
||||
|
||||
|
||||
<sect2 id="mapping-declaration-doctype" revision="2">
|
||||
<sect2 id="mapping-declaration-doctype" revision="3">
|
||||
<title>Doctype</title>
|
||||
|
||||
<para>
|
||||
|
@ -102,6 +102,56 @@
|
|||
당신이 인터넷 연결을 사용하는 DTD에 대한 룩업들을 겪게 될 경우, 당신의 classpath의 컨텐츠에 대해 당신의 DTD 선언을
|
||||
체크하라.
|
||||
</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 id="mapping-declaration-mapping" revision="3">
|
||||
|
@ -692,6 +742,17 @@
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><literal>sequence-identity</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
실제 값 생성을 위해 데이터베이스 시퀀스를 활용하지만, 생성된 식별자 값을 insert 문장 실행의 부분으로서
|
||||
실제로 반환시키기 위해 이것을 JDBC3 getGeneratedKeys와 결합시킨 특화된 시퀀스 생성 방도. 이 방도는
|
||||
JDK 1.4에 대상화된 Oracle 10g 드라이버들 상에서만 지원되는 거승로 알려져 있다. 이들 insert 문장들에
|
||||
대한 주석들은 Oracle 드라이버들 내에 있는 버그 때문에 사용불가능하게 되어 있음을 노트하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
@ -1082,7 +1143,7 @@
|
|||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-declaration-timestamp" revision="3" >
|
||||
<sect2 id="mapping-declaration-timestamp" revision="4" >
|
||||
<title>timestamp (옵션)</title>
|
||||
|
||||
<para>
|
||||
|
@ -1090,7 +1151,7 @@
|
|||
버전화에 대한 대체물로서 고안되었다. Timestamp은 고유하게 optimistic 잠금에 대한 다소 안전한 구현이다. 하지만 때때로
|
||||
어플리케이션은 다른 방법들로 timestamp들을 사용할 수도 있다.
|
||||
</para>
|
||||
|
||||
|
||||
<programlistingco>
|
||||
<areaspec>
|
||||
<area id="timestamp1" coords="2 70"/>
|
||||
|
@ -1123,7 +1184,7 @@
|
|||
가진 자바빈즈 스타일의 프로퍼티 이름.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="timestamp3">
|
||||
<callout arearefs="timestamp3">
|
||||
<para>
|
||||
<literal>access</literal> (옵션 - 디폴트는 <literal>property</literal>):
|
||||
Hibernate가 프로퍼티 값에 접근하는데 사용할 방도.
|
||||
|
@ -1140,18 +1201,18 @@
|
|||
<callout arearefs="timestamp5">
|
||||
<para>
|
||||
<literal>source</literal> (옵션 - 디폴트는 <literal>vm</literal>):
|
||||
Hibernate는 어느 장소로부터 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가?
|
||||
Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야 하기 때문에 데이터베이스 기반의
|
||||
timestamp들은 오버헤드를 초래하지만, 클러스터링된 환경들의 용도로 더 안전할 것이다. 또한 모든
|
||||
Hibernate는 어디서 timestamp 값을 검색할 것인가? 데이터베이스로부터인가 현재의 JVM으로부터인가?
|
||||
데이터베이스 기반의 timestamp들은 Hibernate가 "다음 값"을 결정하기 위해 데이터베이스에 접속해야
|
||||
하기 때문에 오버헤드를 초래하지만, 클러스터링된 환경들에서의 용도로 보다 더 안전할 것이다. 또한 모든
|
||||
<literal>Dialect</literal>들이 데이터베이스의 현재의 timestamp에 대한 검색을 지원하는 것으로 알려져
|
||||
있는 반면에, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용에 대해 안전하지 않을
|
||||
있지 않지만, 다른 <literal>Dialect</literal>들은 정밀도 결핍 때문에 잠금에 있어 사용이 안전하지 않을
|
||||
수 있음을 노트하라(예를 들면 오라클 8).
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="timestamp6">
|
||||
<para>
|
||||
<literal>generated</literal> (옵션 - 디폴트는 <literal>never</literal>):
|
||||
이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 산출되는지를 지정한다.
|
||||
이 timestamp 프로퍼티 값이 데이터베이스에 의해 실제로 생성됨을 지정한다.
|
||||
<xref linkend="mapping-generated">산출되는 프로퍼티들</xref>에 대한 논의들 보라.
|
||||
</para>
|
||||
</callout>
|
||||
|
@ -2202,7 +2263,8 @@
|
|||
<title>join</title>
|
||||
|
||||
<para>
|
||||
<literal><join></literal> 요소를 사용하면, 한 개의 클래스의 프로퍼티들을 몇 개의 테이블들로 매핑시키는 것이
|
||||
<literal><join></literal> 테이블들 사이에 1대일 관계가 존재할 때,
|
||||
요소를 사용하여 하나의 클래스에 속한 프로퍼티들을 몇 개의 테이블들로 매핑시키는 것이
|
||||
가능하다.
|
||||
</para>
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ session.close();]]></programlisting>
|
|||
|
||||
<para>
|
||||
당신은 또한 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>
|
||||
|
||||
<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
|
||||
|
@ -94,7 +92,6 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="batch-statelesssession">
|
||||
<title>StatelessSession 인터페이스</title>
|
||||
|
@ -140,7 +137,7 @@ session.close();]]></programlisting>
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-direct" revision="2">
|
||||
<sect1 id="batch-direct" revision="3">
|
||||
<title>DML-스타일 연산들</title>
|
||||
|
||||
<para>
|
||||
|
@ -151,9 +148,9 @@ session.close();]]></programlisting>
|
|||
(<xref linkend="queryhql">HQL</xref>)를 통해 실행되는 대량 SQL-스타일의 DML 문장 실행을 위한 메소드들을 제공한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들의 유사-구문은 다음과 같다:
|
||||
<literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지 :
|
||||
<para>
|
||||
<literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들에 대한 유사 구문은 다음과 같다:
|
||||
<literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. 노트할 몇 가지:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
|
@ -201,10 +198,34 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<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>
|
||||
HQL <literal>DELETE</literal>를 실행하려면, 같은 메소드 <literal>Query.executeUpdate()</literal>를
|
||||
사용하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
|
|||
schema="schema_name"
|
||||
lazy="true|extra|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"
|
||||
order-by="column_name asc|desc"
|
||||
where="arbitrary sql where condition"
|
||||
|
|
|
@ -184,8 +184,7 @@
|
|||
<property name="purchaseDate"/>
|
||||
<property name="price"/>
|
||||
<property name="quantity"/>
|
||||
<many-to-one name="item" class="eg.Item"/>
|
||||
<!-- class attribute is optional -->
|
||||
<many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
|
|
@ -653,8 +653,15 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
선택할 것이다.
|
||||
<para>
|
||||
<emphasis role="strong">eg.</emphasis>
|
||||
<literal>on_close</literal> (디폴트) | <literal>after_transaction</literal> |
|
||||
<literal>after_statement</literal> | <literal>auto</literal>
|
||||
<literal>auto</literal> (디폴트) | <literal>on_close</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>
|
||||
</entry>
|
||||
</row>
|
||||
|
@ -864,7 +871,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</tgroup>
|
||||
</table>
|
||||
|
||||
<table frame="topbot" id="configuration-misc-properties" revision="9">
|
||||
<table frame="topbot" id="configuration-misc-properties" revision="10">
|
||||
<title>여러가지 프로퍼티들</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colname="c1" colwidth="1*"/>
|
||||
|
@ -882,12 +889,12 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</entry>
|
||||
<entry>
|
||||
"현재" <literal>Session</literal>의 영역화를 위한 하나의 (맞춤) 방도를
|
||||
공급한다. 빌드되어 있는 방도들에 대한 추가 정보는
|
||||
제공한다. 빌드되어 있는 방도들에 대한 추가 정보는
|
||||
<xref linkend="architecture-current-session"/>를 보라.
|
||||
<para>
|
||||
<emphasis role="strong">예.</emphasis>
|
||||
<literal>jta</literal> | <literal>thread</literal> |
|
||||
<literal>custom.Class</literal>
|
||||
<literal>jta</literal> | <literal>thread</literal> |
|
||||
<literal>managed</literal> | <literal>custom.Class</literal>
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
@ -899,7 +906,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
Chooses the HQL 파서 구현을 선택한다.
|
||||
<para>
|
||||
<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>
|
||||
</para>
|
||||
</entry>
|
||||
|
@ -909,7 +916,8 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.query.substitutions</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑(예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다).
|
||||
Hibernate 질의들 내의 토큰들로부터 SQL 토큰들로의 매핑
|
||||
(예를 들어 토큰들은 함수 이름 또는 리터럴 이름일 수 있다).
|
||||
<para>
|
||||
<emphasis role="strong">예.</emphasis>
|
||||
<literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
|
||||
|
@ -921,8 +929,10 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.hbm2ddl.auto</literal>
|
||||
</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>
|
||||
<emphasis role="strong">예.</emphasis>
|
||||
<literal>validate</literal> | <literal>update</literal> |
|
||||
|
@ -935,8 +945,10 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.cglib.use_reflection_optimizer</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티). Reflection은 문제가 발생할 시에 때때로 유용할 수 있고,
|
||||
당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라. 당신은 <literal>hibernate.cfg.xml</literal>
|
||||
런타임 reflection 대신에 CGLIB의 사용을 가능하도록 만든다(시스템 레벨 프로퍼티).
|
||||
Reflection은 문제가 발생할 시에 때때로 유용할 수 있고,
|
||||
당신이 optimizer를 사용하지 않을 경우조차도 Hibernate는 항상 필요로 함을 유의하라.
|
||||
당신은 <literal>hibernate.cfg.xml</literal>
|
||||
속에 이 프로퍼티를 설정할수 없다.
|
||||
<para>
|
||||
<emphasis role="strong">예.</emphasis>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
그리고 Hibernate의 확장 기능의 구현을 허용해준다.
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-interceptors" revision="2">
|
||||
<sect1 id="objectstate-interceptors" revision="3">
|
||||
<title>인터셉터들</title>
|
||||
|
||||
<para>
|
||||
|
@ -106,7 +106,14 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
세션이 생성될 때 인터셉터가 지정될 것이다.
|
||||
인터셉터들은 다음 두 개의 특징들로 나타난다: <literal>Session</literal>-영역화 그리고
|
||||
<literal>SessionFactory</literal>-영역화.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal>-영역의 인터셉터는 세션이 하나의 <literal>Interceptor</literal>를 수용하는
|
||||
오버로드된 SessionFactory.openSession() 메소드들 중 하나를 사용하여 열릴 때
|
||||
지정된다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
||||
|
@ -116,23 +123,34 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
이 경우에, 인터셉터는 threadsafe이어야 한다.
|
||||
</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>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-events" revision="3">
|
||||
<sect1 id="objectstate-events" revision="4">
|
||||
<title>이벤트 시스템</title>
|
||||
|
||||
<para>
|
||||
만일 당신이 당신의 영속 계층에서 특별한 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>이벤트</emphasis>
|
||||
만일 당신이 당신의 영속 계층에서 특정 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>event</emphasis>
|
||||
아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 당신은 <literal>LoadEvent</literal>,
|
||||
본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다.
|
||||
당신은 <literal>LoadEvent</literal>,
|
||||
<literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는
|
||||
<literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때,
|
||||
Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입에 대한 구성된 이벤트 리스너에게 전달한다.
|
||||
Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입의 구성된 이벤트 리스너에게 전달한다.
|
||||
박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을
|
||||
구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의
|
||||
등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal>
|
||||
|
@ -146,10 +164,10 @@ public class AuditInterceptor extends EmptyInterceptor {
|
|||
|
||||
<para>
|
||||
맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate
|
||||
out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고자 그리고/또는 확장하고자 원하는 이벤트들에 대해
|
||||
out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고/하거나 확장하고자 원하는 이벤트들에 대해
|
||||
적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로
|
||||
등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다).
|
||||
다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
|
||||
다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
|
||||
|
@ -185,13 +203,13 @@ LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener
|
|||
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
|
||||
|
||||
<para>
|
||||
선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 <literal><listener/></literal>
|
||||
선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 개의 <literal><listener/></literal>
|
||||
요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을
|
||||
공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
컨피그레이션 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을
|
||||
구성 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을
|
||||
구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을
|
||||
더 쉽게 해준다.
|
||||
</para>
|
||||
|
|
|
@ -538,7 +538,7 @@ alter table line_items
|
|||
</class>
|
||||
]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="example-mappings-content-discrimination">
|
||||
<title>내용 기반 판별</title>
|
||||
<programlisting><![CDATA[<class name="Person"
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
</subclass>
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
|
||||
<sect2 id="inheritance-tableperclass" >
|
||||
<title>Table per class hierarchy</title>
|
||||
|
||||
|
|
|
@ -576,11 +576,24 @@ Cat fritz = (Cat) iter.next();]]></programlisting>
|
|||
만료되도록 구성되어 있을지라도) 또 다른 어플리케이션에 의해 영속 저장소에 대해 행해진 변경들을 결코 알지 못한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<para revision="1">
|
||||
디폴트로, Hibernate는 JVM-레벨의 캐싱에 EHCache를 사용한다. (JCS 지원은 이제 진부하게 되었고 Hibernate의 장래 버전에서
|
||||
제거될 것이다.) 당신은 <literal>hibernate.cache.provider_class</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>
|
||||
|
||||
<table frame="topbot" id="cacheproviders" revision="1">
|
||||
|
|
|
@ -104,6 +104,7 @@ public class Cat {
|
|||
준수할 네 개의 주요 규칙들이 다음에 있다:
|
||||
</para>
|
||||
|
||||
|
||||
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
||||
<title>아규먼트 없는 생성자를 구현하라 </title>
|
||||
|
||||
|
@ -228,7 +229,8 @@ public class DomesticCat extends Cat {
|
|||
<title><literal>equals()</literal>와 <literal>hashCode()</literal> 구현하기</title>
|
||||
|
||||
<para>
|
||||
만일 당신이
|
||||
만일 당신이 다음의 경우라면, 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal>
|
||||
메소드들을 오버라이드 시켜야 한다.
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
|
@ -244,10 +246,7 @@ public class DomesticCat extends Cat {
|
|||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
경우에 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal> 메소드들을 오버라이드 시켜야 한다.
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다.
|
||||
따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게
|
||||
|
@ -432,7 +431,7 @@ dynamicSession.close()
|
|||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-tuplizers" revision="0">
|
||||
<sect1 id="persistent-classes-tuplizers" revision="1">
|
||||
<title>Tuplizer들</title>
|
||||
|
||||
<para>
|
||||
|
@ -442,8 +441,8 @@ dynamicSession.close()
|
|||
그런 데이터 구조로부터 값들을 추출시키는 방법 그리고 그런 데이터구조 속으로 값들을 삽입시키는 방법을 알고 있는 것이다.
|
||||
예를 들어, POJO 엔티티 모드의 경우, 대응하는 tuplizer는 그것의 생성자를 통해 POJO를 생성시키는 방법, 그리고 정의된
|
||||
프로퍼티 접근자들을 사용하여 POJO 프로퍼티들에 접근하는 방법을 안다.
|
||||
<literal>org.hibernate.tuple.EntityTuplizer</literal> 인터페이스와
|
||||
<literal>org.hibernate.tuple.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의
|
||||
<literal>org.hibernate.tuple.entity.EntityTuplizer</literal> 인터페이스와
|
||||
<literal>org.hibernate.tuple.component.ComponentTuplizer</literal> 인터페이스에 의해 표현되는 두 가지 고급 유형의
|
||||
Tuplizer들이 존재한다. <literal>EntityTuplizer</literal>들은 엔티티들에 관해서는 위에 언급된 계약들을 매핑할
|
||||
책임이 있는 반면에, <literal>ComponentTuplizer</literal>들은 컴포넌트들에 대해서도 동일한 것을 행한다.
|
||||
</para>
|
||||
|
@ -476,7 +475,7 @@ dynamicSession.close()
|
|||
|
||||
|
||||
public class CustomMapTuplizerImpl
|
||||
extends org.hibernate.tuple.DynamicMapEntityTuplizer {
|
||||
extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
|
||||
// override the buildInstantiator() method to plug in our custom map...
|
||||
protected final Instantiator buildInstantiator(
|
||||
org.hibernate.mapping.PersistentClass mappingInfo) {
|
||||
|
|
|
@ -364,7 +364,6 @@ session.createCriteria(Cat.class, "cat")
|
|||
|
||||
</sect1>
|
||||
|
||||
|
||||
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인
|
||||
사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. -->
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<chapter id="queryhql">
|
||||
<title>HQL: Hibernate Query Language</title>
|
||||
<title>HQL: 하이버네이트 질의 언어(Hibernate Query Language)</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 (아주 의도적으로) SQL과 매우 흡사하게 보이는 극히 강력한 질의 언어를 구비하고 있다. 그러나 그 구문에 의해 우롱당하지 말라;
|
||||
|
@ -126,7 +126,7 @@
|
|||
<programlisting><![CDATA[from Cat as cat
|
||||
left join cat.kittens as kitten
|
||||
with kitten.bodyWeight > 10.0]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
게다가, "fetch" join은 값들을 가진 콜렉션들이나 연관관계들이 한 개의 select를 사용하여, 그것들의 부모 객체들에 따라 초기화 되는
|
||||
것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관관계들과 콜렉션들에 대한 매핑 파일의 outer join과 lazy 선언들을
|
||||
|
@ -147,7 +147,7 @@
|
|||
inner join fetch cat.mate
|
||||
left join fetch cat.kittens child
|
||||
left join fetch child.kittens]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
(비록 <literal>scroll()</literal>이 사용될 수 있을지라도) <literal>fetch</literal> 구조체는
|
||||
<literal>iterate()</literal>를 사용하여 호출되는 질의들 내에 사용될 수 없음을 노트하라. 이들 오퍼레이션들이 결과 행들에
|
||||
|
@ -167,9 +167,9 @@
|
|||
|
||||
<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>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="queryhql-joins-forms">
|
||||
<title>join 구문의 형식들</title>
|
||||
|
||||
|
@ -564,6 +564,13 @@ where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting
|
|||
numeric 값들이나 temporal 값들을 가독성 있는 문자열로 변환시키는 <literal>str()</literal>
|
||||
</para>
|
||||
</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> 함수
|
||||
|
@ -576,29 +583,10 @@ where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting
|
|||
함수들과 함께 <literal>size(), minelement(), maxelement(), minindex(), maxindex()</literal>.
|
||||
</para>
|
||||
</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>
|
||||
<para>
|
||||
<literal>sign()</literal>, <literal>trunc()</literal>, <literal>rtrim()</literal>,
|
||||
<literal>sin()</literal>과 같이 임의의 데이터베이스-지원 SQL 스칼라 함수
|
||||
<literal>sin()</literal>과 같이 임의의 데이터베이스 지원 SQL 스칼라 함수
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@ -867,6 +855,10 @@ from Cat as cat]]></programlisting>
|
|||
<para>
|
||||
select 리스트 내에 있는 하나 이상의 표현식을 가진 서브질의들의 경우에 당신은 tuple 생성자를 사용할 수 있다:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
select 목록 내에 하나 이상의 표현식을 가진 서브질의들의 경우, 당신은 튜플(tuple) 구조를 사용할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[from Cat as cat
|
||||
where not ( cat.name, cat.color ) in (
|
||||
|
|
|
@ -1,216 +1,366 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="querysql" revision="2">
|
||||
<title>Native SQL</title>
|
||||
<title>Native SQL</title>
|
||||
|
||||
<para>
|
||||
당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 당신이 오라클의 질의 힌트들 또는
|
||||
<literal>CONNECT</literal> 키워드와 같은 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다.
|
||||
그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 이전 경로를 제공한다.
|
||||
</para>
|
||||
<para>당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다.
|
||||
당신이 오라클의 질의 힌트들 또는 <literal>CONNECT</literal> 키워드와 같은
|
||||
데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다.
|
||||
그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한
|
||||
이전 경로를 제공한다.</para>
|
||||
|
||||
<para>
|
||||
Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을
|
||||
지정하는 것을 당신에게 허용해준다.
|
||||
</para>
|
||||
<para>Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해
|
||||
(내장 프로시저들을 포함하여) 손으로 작성된 SQL을 지정하는 것을 당신에게 허용해준다.</para>
|
||||
|
||||
<sect1 id="querysql-creating" revision="3">
|
||||
<title><literal>SQLQuery</literal> 사용하기</title>
|
||||
<sect1 id="querysql-creating" revision="4">
|
||||
<title><literal>SQLQuery</literal> 사용하기</title>
|
||||
|
||||
<para>
|
||||
native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해 제어되며, 그것은
|
||||
<literal>Session.createSQLQuery()</literal>을 호출하여 획득된다. 극히 간단한 경우들에서 ,
|
||||
우리는 다음 형식을 사용할 수 있다:
|
||||
</para>
|
||||
<para>native SQL 질의들의 실행은 <literal>SQLQuery</literal> 인터페이스를 통해
|
||||
제어되며, 그것은 <literal>Session.createSQLQuery()</literal>을 호출하여
|
||||
획득된다. 다음은 이 API를 질의에 사용하는 방법을 설명한다.</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery("select * from cats")
|
||||
.addEntity(Cat.class)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>이 질의는 다음을 지정했다:</para>
|
||||
<sect2>
|
||||
<title>스칼라 질의들</title>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
SQL 질의 문자열
|
||||
</para>
|
||||
<para>SQL 질의 문자열</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
그 질의에 의해 반환되는 엔티티
|
||||
</para>
|
||||
<para>반환할 컬럼들과 타입들</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
여기서, 결과 셋 컬럼 이름들은 매핑 문서 내에 지정된 컬럼 이름들과 동일한 것으로 가정된다. 이것은 조인 다중 테이블들을 가진
|
||||
SQL 질의들에 대해 문제가 될 수 있다. 왜냐하면 동일한 컬럼 이름들이 하나 이상의 테이블 들 내에 나타날 수도 있기 때문이다.
|
||||
다음 형식은 컬럼 이름 중복에 대해 취약하지 않다:
|
||||
</para>
|
||||
<para>이것은 여전히 Object 배열들을 반환할 것이지만, 이제 그것은
|
||||
<literal>ResultSetMetdata</literal>를 사용하지 않을 것이고 대신에
|
||||
기반 결과셋으로부터 ID, NAME 그리고 BIRTHDATE 컬럼을 각각 Long, String
|
||||
그리고 Short 타입으로 반환할 것이다. 심지어 그 질의가 <literal>*</literal>를
|
||||
사용하고 세 개의 열거된 컬럼들 보다 더 많은 것을 반환할 수 있을지라도, 이것은
|
||||
또한 오직 이들 세 개의 컬럼들 만이 반환될 것임을 의미한다.</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
|
||||
.addEntity("cat", Cat.class)
|
||||
.list();]]></programlisting>
|
||||
<para>스칼라들 중 몇몇 또는 전부에 대한 타입 정보를 남겨두는 것이 가능하다.</para>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate가 컬럼 alias들을 도입하기 위한, placeholder를 가진, SQL 질의 문자열
|
||||
</para>
|
||||
<para>SQL 질의 문자열</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
그 질의에 의해 반환된 엔티티와 그것의 SQL 테이블 alias
|
||||
</para>
|
||||
<para>그 질의에 의해 반환되는 엔티티</para>
|
||||
</listitem>
|
||||
</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>
|
||||
</itemizedlist>
|
||||
|
||||
<programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
|
||||
.addScalar("maxWeight", Hibernate.DOUBLE);
|
||||
.uniqueResult();]]></programlisting>
|
||||
|
||||
<para>당신은 당신의 hbm 파일들 내에 결과셋 매핑 정보를 대안저긍로 설명활 수 있고 당신의 질의들을 위해 그것들을
|
||||
사용할 수 있다.</para>
|
||||
<para>Cat이 컬럼 ID, NAME 그리고 BIRTHDATE로서 매핑된다고 가정하면,
|
||||
위의 질의들은 둘다 각각의 요소가 하나의 Cat 엔티티인 하나의 List를 반환할 것이다.</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
||||
)
|
||||
.setResultSetMapping("catAndKitten")
|
||||
.list();]]></programlisting>
|
||||
<para>만일 그 엔티티가 또 다른 엔티티에 대해 <literal>many-to-one</literal>로
|
||||
매핑되어 있다면 또한 native 질의를 실행할 때 이것을 반환하는 것이 필수적고, 그 밖의 경우
|
||||
데이터베이스 지정적인 "컬럼이 발견되지 않았습니다" 오류가 일어날 것이다. 추가적인
|
||||
컬럼은 * 표기를 사용할 자동적으로 반환될 것이지만, 우리는 다음 <literal>Dog</literal>에
|
||||
대한 <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">
|
||||
<title>Alias 참조와 프로퍼티 참조</title>
|
||||
<para>이것은 cat.getDog()이 고유하게 기능하는 것을 허용한다.</para>
|
||||
</sect2>
|
||||
|
||||
<para>
|
||||
위에서 사용된 <literal>{cat.*}</literal> 표기는 "모든 프로퍼티"에 대한 약어이다. 다른 방법으로, 당신은 명시적으로 컬럼들을
|
||||
리스트할 수 있지만, 심지어 이 경우 조차도 우리는 Hibernate로 하여금 각각의 프로퍼티에 대해 SQL 컬럼 alias들을 끼워넣도록 해야 한다.
|
||||
컬럼 alias에 대한 placeholder는 테이블 alias 수식어가 붙은 프로퍼티 이름이다. 다음 예제에서, 우리는 매핑 메타데이터에 선언된
|
||||
것에 대해 다른 테이블 (<literal>cat_log</literal>)로부터 <literal>Cat</literal>들을 검색한다. 우리는 심지어 우리가
|
||||
좋아할 경우 where 절 속에 프로퍼티 alias들을 사용할 수도 있음을 주목하라.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>{}</literal>-syntax is <emphasis>not</emphasis> required for named queries.
|
||||
See <xref linkend="querysql-namedqueries"/>
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
|
||||
"cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
|
||||
"cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
|
||||
"from cat_log cat where {cat.mate} = :catId"
|
||||
<sect2>
|
||||
<title>연관들과 콜렉션들을 처리하기</title>
|
||||
|
||||
<para>프락시를 초기화 시킴에 있어 가능한 특별한 라운드트립을 피하기 위해서
|
||||
<literal>Dog</literal>에서 eagerly join시키는 것이 간으하다. 이것은
|
||||
<literal>addJoin()</literal> 메소드를 통해 행해지는데, 그것은
|
||||
연관이나 콜렉션 내에서 조인시키는 것을 당신에게 허용해준다.</para>
|
||||
|
||||
<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")
|
||||
.addEntity("cat", Cat.class)
|
||||
.addJoin("cat.dog");
|
||||
]]></programlisting>
|
||||
|
||||
<para>이 예제에서 반환되는 <literal>Cat</literal>들은 데이터베이스에
|
||||
대한 임의의 특별한 라운드크립 없이 전체적으로 초기화된 그것들의 <literal>dog</literal>
|
||||
프로퍼티를 갖는다. 우리가 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)
|
||||
.addEntity("cat", Cat.class)
|
||||
.setLong("catId", catId)
|
||||
.list();]]></programlisting>
|
||||
.addEntity("cat", Cat.class)
|
||||
.addEntity("mother", Cat.class).list()
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>노트:</emphasis> 만일 당신이 각각의 프로퍼티를 명시적으로 리스트할 경우, 당신은 그 클래스와
|
||||
<emphasis>그것의 서브클래스들</emphasis>의 모든 프로퍼티들을 포함해야 한다!
|
||||
</para>
|
||||
<para>
|
||||
다음 테이블은 alias injection을 사용하는 다른 가능성들을 보여준다. 노트 : 결과 내에서 alias 이름들이 예제들이며, 각각의 alias는
|
||||
사용될 시에 하나의 유일한 그리고 가능한 다른 이름을 가질 것이다.
|
||||
</para>
|
||||
<sect3 id="querysql-aliasreferences" revision="2">
|
||||
<title>alias 참조와 프로퍼티 참조</title>
|
||||
|
||||
<table frame="topbot" id="aliasinjection-summary">
|
||||
<title>Alias injection 이름들</title>
|
||||
<para>대부분의 경우에 위의 alias 주입이 필요하지만, composite 프로퍼티들, 상속 판별자들
|
||||
(inheritance discriminators), 콜렉션 등과 같은 보다 복잡한 매핑들과 관련된 질의들의 경우에는
|
||||
고유한 alias들을 주입시키는 것을 Hibernate에게 허용하는데 사용될 몇몇 특별한 alias들이 존재한다.</para>
|
||||
|
||||
<para>다음 테이블은 alias 주입을 사용하는 다른 가능성들을 보여준다. 노트: 결과 내에 있는 alias 이름들이
|
||||
예제이며, 각각의 alias는 사용될 때 하나의 유일한 이름과 아마 다른 이름을 가질 것이다.</para>
|
||||
|
||||
<tgroup cols="4">
|
||||
<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>
|
||||
<table frame="topbot" id="aliasinjection-summary">
|
||||
<title>alias 주입 이름들</title>
|
||||
|
||||
</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">
|
||||
<title>명명된 SQL 질의들</title>
|
||||
|
||||
|
@ -219,7 +369,7 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
<literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="persons">
|
||||
<programlisting><![CDATA[<sql-query name="persons">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
SELECT person.NAME AS {person.name},
|
||||
person.AGE AS {person.age},
|
||||
|
@ -228,16 +378,17 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
||||
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
||||
.setString("namePattern", namePattern)
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
<para>
|
||||
The <literal><return-join></literal> 요소와 <literal><load-collection></literal>
|
||||
요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을 정의하는데 사용된다.
|
||||
</para>
|
||||
|
||||
<para><literal><return-join></literal> 요소와
|
||||
<literal><load-collection></literal>
|
||||
요소는 연관들을 조인시키고 콜렉션들을 각각 초기화 시키는 질의들을
|
||||
정의하는데 사용된다.</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="personsWith">
|
||||
<programlisting><![CDATA[<sql-query name="personsWith">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
<return-join alias="address" property="person.mailingAddress"/>
|
||||
SELECT person.NAME AS {person.name},
|
||||
|
@ -253,12 +404,11 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은 <literal><return-scalar></literal> 요소를 사용하여
|
||||
컬럼 alias와 Hibernate 타입을 선언해야 한다:
|
||||
</para>
|
||||
<para>명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은
|
||||
<literal><return-scalar></literal> 요소를 사용하여
|
||||
컬럼 alias와 Hibernate 타입을 선언해야 한다:</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return-scalar column="name" type="string"/>
|
||||
<return-scalar column="age" type="long"/>
|
||||
SELECT p.NAME AS name,
|
||||
|
@ -288,16 +438,23 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<sect2 id="propertyresults">
|
||||
<title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
|
||||
<para>다른방법으로 당신은 당신의 hbm 파일들 내에 직접 자바 코드로 된 결과셋 매핑 정보를 사용할 수 있다.</para>
|
||||
|
||||
<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><return-property></literal>로서 당신은 사용할
|
||||
컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로 알려줄 수 있다.</para>
|
||||
|
||||
<para>
|
||||
Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해 <literal>{}</literal>-구문을 사용하는 것 대신에,
|
||||
<literal><return-property></literal>로서 당신은 사용할 컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로
|
||||
알려줄 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return alias="person" class="eg.Person">
|
||||
<return-property name="name" column="myName"/>
|
||||
<return-property name="age" column="myAge"/>
|
||||
|
@ -310,12 +467,11 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
</sql-query>
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal><return-property></literal>는 또한 다중 컬럼들에 대해 동작한다. 이것은 다중-컬럼 프로퍼티들에
|
||||
대한 fine grained 제어를 허용할 수 없는 <literal>{}</literal>-구문을 가진 제약을 해결해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
|
||||
<para><literal><return-property></literal>는 또한 다중 컬럼들에 대해 동작한다.
|
||||
이것은 다중-컬럼 프로퍼티들에 대한 fine grained 제어를 허용할 수 없는
|
||||
<literal>{}</literal>-구문을 가진 제약을 해결해준다.</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
|
||||
<return alias="emp" class="Employment">
|
||||
<return-property name="salary">
|
||||
<return-column name="VALUE"/>
|
||||
|
@ -330,28 +486,22 @@ List loggedCats = sess.createSQLQuery(sql)
|
|||
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
||||
ORDER BY STARTDATE ASC
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal><return-property></literal>를
|
||||
사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데
|
||||
<literal><return-discriminator></literal>를 사용해야 한다.
|
||||
</para>
|
||||
</sect2>
|
||||
<para>이 예제에서 우리는 끼워넣기(injection)를 위해 <literal>{}</literal>-구문과 함께 <literal><return-property></literal>를
|
||||
사용했음을 주목하라. 사용자들이 컬럼과 프로퍼티들을 참조하고자 원하는 방법을 선택하는 것을 사용자들에게 허용해줌으로써.</para>
|
||||
|
||||
<para>만일 당신의 매핑이 한 개의 판별자(discriminator )를 가질 경우 당신은 판별자 컬럼을 지정하는데
|
||||
<literal><return-discriminator></literal>를 사용해야 한다.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="sp_query" revision="1">
|
||||
<title>질의를 위한 내장 프로시저 사용하기</title>
|
||||
|
||||
<para>
|
||||
Hibernate 3은 내장 프로시저들과 함수들을 통한 질의 지원을 도입한다. 대부분의 다음 문서는 양자 모두에 동일하게 적용된다.
|
||||
내장 프로시저/함수는 Hibernate와 동작하는 것이 가능하도록 첫 번째 out-파라미터로서 한 개의 결과셋을 반환해야 한다.
|
||||
Oracle9 이상의 버전에서 그런 내장 프로시저에 대한 예제는 다음과 같다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||
<sect2 id="sp_query" revision="1">
|
||||
<title>질의를 위한 내장 프로시저 사용하기</title>
|
||||
|
||||
<para>Hibernate 3은 내장 프로시저들과 함수들을 통한 질의 지원을 도입한다. 대부분의 다음 문서는 양자 모두에 동일하게 적용된다.
|
||||
내장 프로시저/함수는 Hibernate와 동작하는 것이 가능하도록 첫 번째 out-파라미터로서 한 개의 결과셋을 반환해야 한다.
|
||||
Oracle9 이상의 버전에서 그런 내장 프로시저에 대한 예제는 다음과 같다:</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||
RETURN SYS_REFCURSOR
|
||||
AS
|
||||
st_cursor SYS_REFCURSOR;
|
||||
|
@ -363,12 +513,11 @@ BEGIN
|
|||
FROM EMPLOYMENT;
|
||||
RETURN st_cursor;
|
||||
END;]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해 그것을 매핑할 필요가 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
|
||||
|
||||
<para>Hibernate에서 이 질의를 사용하기 위해 당신은 하나의 명명된 질의(a named query)를 통해
|
||||
그것을 매핑할 필요가 있다.</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
|
||||
<return alias="emp" class="Employment">
|
||||
<return-property name="employee" column="EMPLOYEE"/>
|
||||
<return-property name="employer" column="EMPLOYER"/>
|
||||
|
@ -383,78 +532,61 @@ BEGIN
|
|||
</return>
|
||||
{ ? = call selectAllEmployments() }
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal><return-join></literal>과
|
||||
<literal><load-collection></literal>은 지원되지 않는다.
|
||||
</para>
|
||||
|
||||
<sect3 id="querysql-limits-storedprocedures" revision="1">
|
||||
<title>내장 프로시저들을 사용하는 규칙들/제약들</title>
|
||||
|
||||
<para>
|
||||
Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들/함수들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을
|
||||
따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우,
|
||||
당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장
|
||||
프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다.
|
||||
</para>
|
||||
<para>내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal><return-join></literal>과
|
||||
<literal><load-collection></literal>은 지원되지 않는다.</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(<parameters>) }</literal> 또는 <literal>{ ? = call
|
||||
procedureName(<parameters>}</literal>. Native 호출 구문은 지원되지 않는다.</para>
|
||||
|
||||
<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>
|
||||
<para>Oracle의 경우 다음 규칙들이 적용된다:</para>
|
||||
|
||||
</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">
|
||||
<title>create, update 그리고 delete를 위한 맞춤형 SQL</title>
|
||||
<para>Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:</para>
|
||||
|
||||
<para>
|
||||
Hibernate3는 create, update, delete 오퍼레이션들을 위한 맞춤형 문장들을 사용할 수 있다. Hibernate에서 클래스와 콜렉션
|
||||
영속자들은 구성 시에 생성된 문자열들의 집합(insertsql, deletesql, updatesql 등)을 이미 포함하고 있다.
|
||||
<literal><sql-insert></literal>, <literal><sql-delete></literal>,
|
||||
<literal><sql-update></literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로,
|
||||
Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은
|
||||
폐기될 것이다.</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><sql-insert></literal>, <literal><sql-delete></literal>,
|
||||
<literal><sql-update></literal> 매핑 태그들은 이들 문자열들을 오버라이드 시킨다:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
|
@ -464,14 +596,10 @@ BEGIN
|
|||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스
|
||||
지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.
|
||||
</para>
|
||||
<para>SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스
|
||||
지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.</para>
|
||||
|
||||
<para>
|
||||
만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:
|
||||
</para>
|
||||
<para>만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
|
@ -483,24 +611,19 @@ BEGIN
|
|||
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로, 위치 파라미터들의 순서는 현재 절대적으로 중요하다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수
|
||||
있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다.
|
||||
(예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에
|
||||
두라.)
|
||||
</para>
|
||||
<para>위치 파라미터들은 Hibernate가 그것들을 기대하는 것과 같은 순서가 되어야 하므로,
|
||||
위치 파라미터들의 순서는 현재 절대적으로 중요하다.</para>
|
||||
|
||||
<para>
|
||||
Hibernate가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘
|
||||
행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자
|
||||
출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다:
|
||||
</para>
|
||||
<para>당신은 <literal>org.hiberate.persister.entity</literal> 레벨로 디버그 로깅을 사용 가능하게 함으로써 예상된 순서를 볼 수
|
||||
있다. 이 레벨을 이용 가능하게 하면 Hibernate는 엔티티들을 생성시키고, 업데이트하고, 삭제하는데 사용되는 정적인 SQL을 출력할 것이다.
|
||||
(예상되는 결과를 보려면, Hibernate 생성된 정적인 sql을 오버라이드 시키게 매핑 파일들 속에 당신의 맞춤형 SQL을 포함시키지 않도록 염두에
|
||||
두라.)</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
|
||||
BEGIN
|
||||
|
||||
|
@ -513,18 +636,14 @@ BEGIN
|
|||
return SQL%ROWCOUNT;
|
||||
|
||||
END updatePerson;]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
|
||||
</sect1>
|
||||
<sect1 id="querysql-load">
|
||||
<title>로딩을 위한 맞춤형 SQL</title>
|
||||
|
||||
<sect1 id="querysql-load">
|
||||
<title>로딩을 위한 맞춤형 SQL</title>
|
||||
<para>당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:</para>
|
||||
|
||||
<para>
|
||||
당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
||||
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
||||
FROM PERSON
|
||||
|
@ -532,11 +651,9 @@ END updatePerson;]]></programlisting>
|
|||
FOR UPDATE
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:
|
||||
</para>
|
||||
<para>이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
|
@ -544,20 +661,16 @@ END updatePerson;]]></programlisting>
|
|||
<loader query-ref="person"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이것은 심지어 내장 프로시저들에 동작한다.
|
||||
</para>
|
||||
<para>이것은 심지어 내장 프로시저들에 동작한다.</para>
|
||||
|
||||
<para>
|
||||
당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:
|
||||
</para>
|
||||
<para>당신은 콜렉션 로딩을 위한 한 개의 질의를 정의할 수도 있다:</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="employments" inverse="true">
|
||||
<key/>
|
||||
<one-to-many class="Employment"/>
|
||||
<loader query-ref="employments"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="employments">
|
||||
<load-collection alias="emp" role="Person.employments"/>
|
||||
SELECT {emp.*}
|
||||
|
@ -566,9 +679,7 @@ END updatePerson;]]></programlisting>
|
|||
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:
|
||||
</para>
|
||||
<para>당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person"/>
|
||||
|
@ -579,7 +690,5 @@ END updatePerson;]]></programlisting>
|
|||
ON pers.ID = emp.PERSON_ID
|
||||
WHERE ID=?
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</sect1>
|
||||
</chapter>
|
|
@ -413,7 +413,7 @@ cats.close()]]></programlisting>
|
|||
|
||||
</sect3>
|
||||
|
||||
<sect3 id="objectstate-querying-executing-named">
|
||||
<sect3 id="objectstate-querying-executing-named" revision="1">
|
||||
<title>명명된 질의들을 구체화 시키기</title>
|
||||
|
||||
<para>
|
||||
|
@ -421,7 +421,7 @@ cats.close()]]></programlisting>
|
|||
포함할 경우에 <literal>CDATA</literal> 섹션을 사용하는 것을 기억하라))
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
|
||||
<programlisting><![CDATA[<query name="ByNameAndMaximumWeight"><![CDATA[
|
||||
from eg.DomesticCat as cat
|
||||
where cat.name = ?
|
||||
and cat.weight > ?
|
||||
|
@ -431,7 +431,7 @@ cats.close()]]></programlisting>
|
|||
파라미터 바인딩과 실행은 프로그램 상으로 행해진다:
|
||||
</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.setInt(1, minWeight);
|
||||
List cats = q.list();]]></programlisting>
|
||||
|
@ -440,6 +440,13 @@ List cats = q.list();]]></programlisting>
|
|||
실제 프로그램 코드는 사용되는 질의 언어에 독립적이고, 당신은 또한 메타데이터로 native SQL 질의들을 정의할 수도 있거나
|
||||
그것들을 매핑 파일들 속에 기존 질의들을 위치지움으로써 기존 질의들을 Hibernate로 이전시킬 수도 있음을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
또한 <literal><hibernate-mapping></literal> 요소 내에서 하나의 질의 선언은 그 질의에 대한
|
||||
전역 유일 이름을 필요로 하고, 반면에 <literal><class></literal> 요소 내에서의 질의 선언은
|
||||
클래스 이름으로 수직된이름을 첨가하여 자동적으로 유일하게 만들어진다.
|
||||
예를 들어 <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
|
||||
</para>
|
||||
|
||||
</sect3>
|
||||
|
||||
|
|
|
@ -317,10 +317,7 @@
|
|||
않다.
|
||||
</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.
|
||||
<para>
|
||||
하지만, CMT 대신 BMT를 사용하는 JTA에 의존할 수 있는 시스템들, 그리고 관리되지 않는 resource-local 환경들 사이에서
|
||||
당신의 영속 계층에 이식성을 유지시키는 것이 자주 희망된다. 두 경우들에서 당신은 프로그램 상의 트랜잭션 경계설정을 사용할 것이다.
|
||||
Hibernate는 당신의 배치 환경의 고유한 트랜잭션 시스템 속으로 변환되는 <literal>Transaction</literal>이라 명명되는
|
||||
|
@ -488,7 +485,7 @@ catch (RuntimeException e) {
|
|||
tx.rollback();
|
||||
throw e; // or display error message
|
||||
}]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
CMT의 경우, 트랜잭션 관할[경계 설정]은 프로그램 상이 아닌, session bean 배치 디스크립터들 속에서 행해진다.
|
||||
그러므로 코드는 다음으로 감소된다:
|
||||
|
@ -621,7 +618,7 @@ try {
|
|||
sess.getTransaction().commit()
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
sess.getTransaction().rollback();
|
||||
sess.getTransaction().rollback();
|
||||
throw e; // or display error message
|
||||
}
|
||||
finally {
|
||||
|
@ -716,7 +713,6 @@ foo.setProperty("bar");
|
|||
session.flush(); // Only for last transaction in conversation
|
||||
t.commit(); // Also return JDBC connection
|
||||
session.close(); // Only for last transaction in conversation]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>foo</literal> 객체는 그것이 로드되었던 <literal>Session</literal>이 어느 것인지를 여전히 알고 있다.
|
||||
이전 세션 상에서 하나의 새로운 데이터베이스 트랜잭션을 시작하는 것은 하나의 새로운 커넥션을 획득하고 그 세션을 소비한다.
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
<chapter id="tutorial">
|
||||
<title>Hibernate 개요</title>
|
||||
|
||||
<sect1 id="tutorial-intro">
|
||||
<sect1 id="tutorial-intro" revision="1">
|
||||
<title>머리말</title>
|
||||
|
||||
<para>
|
||||
이 장은 Hibernate 초심자를 위한 개론적인 튜토리얼이다. 우리는 메모리-내 데이터베이스를
|
||||
사용하는 간단한 명령 라인 어플리케이션으로 시작하고 단계들을 이해하도록 쉽게 그것을 개발한다.
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 튜토리얼은 Hibernate 신규 사용자들을 의도하고 있지만 Java와 SQL 지식을 필요로 한다.
|
||||
그것은 Michael Gloegl이 작성한 튜토리얼에 기초한다.
|
||||
그것은 Michael Gloegl이 작성한 튜토리얼에 기초하며, 우리가 명명하는 제 3의 라이브러리들은
|
||||
JDK 1.4와 5.0 버전용이다. 당신은 JDK1.3에 대해 다른 라이브러리들을 필요로 할 수도 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
튜토리얼용 소스는 <literal>doc/reference/tutorial/</literal> 디렉토리 내에 있는
|
||||
배포본 내에 포함되어 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -62,14 +67,16 @@
|
|||
다음으로 우리는 우리가 데이터베이스 속에 저장시키고자 원하는 이벤트를 표현하는 한 개의 클래스를 생성시킨다.
|
||||
</para>
|
||||
|
||||
<sect2 id="tutorial-firstapp-firstclass">
|
||||
<sect2 id="tutorial-firstapp-firstclass" revision="1">
|
||||
<title>첫 번째 클래스</title>
|
||||
|
||||
<para>
|
||||
우리의 첫 번째 영속 클래스는 몇몇 프로퍼티들을 가진 간단한 자바빈즈 클래스이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[import java.util.Date;
|
||||
<programlisting><![CDATA[package events;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Event {
|
||||
private Long id;
|
||||
|
@ -77,7 +84,7 @@ public class Event {
|
|||
private String title;
|
||||
private Date date;
|
||||
|
||||
Event() {}
|
||||
public Event() {}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
@ -107,18 +114,19 @@ public class Event {
|
|||
<para>
|
||||
당신은 이 클래스가 프로퍼티 getter와 setter 메소드들에 대한 표준 자바빈즈 명명법들 뿐만 아니라 필드들에 대한
|
||||
private 가시성을 사용하고 있음을 알 수 있다. 이것은 권장되는 설계이지만, 필수적이지는 않다. Hibernate는
|
||||
또한 필드들에 직접 접근할 수 있으며, accessor 메소드들의 이점은 강건한 리팩토링이다.
|
||||
또한 필드들에 직접 접근할 수 있으며, accessor 메소드들의 이점은 강건한 리팩토링이다. 아규먼트 없는 생성자는
|
||||
reflection을 통해 이 클래스의 객체를 초기화 시킬 필요가 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 만일 우리가 Hibernate의
|
||||
전체 특징을 사용하고자 원할 경우 모든 영속 엔티티 클래스들(보다 덜 중요한 종속 클래스들 또한 존재한다)은 그런
|
||||
식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해
|
||||
객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제한이라기 보다는 하나의 특징으로 간주할 것이다. 하지만
|
||||
우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때,
|
||||
Hibernate는 단지 식별자를 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들
|
||||
뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려
|
||||
있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다.
|
||||
<literal>id</literal> 프로퍼티는 특별한 이벤트를 위한 유일 식별자를 소유한다. 모든 영속 엔티티 클래스들
|
||||
(보다 덜 중요한 종속 클래스들도 존재한다)은 우리가 Hibernate의 전체 특징 집합을 사용하고자 원할 경우에
|
||||
그런 식별자 프로퍼티를 필요로 할 것이다. 사실 대부분의 어플리케이션들(특히 웹 어플리케이션들)은 식별자에 의해
|
||||
객체들을 구분지을 필요가 있어서, 당신은 이것을 어떤 제약점이라기 보다는 하나의 특징으로 간주할 것이다. 하지만
|
||||
우리는 대개 객체의 항등(identity)를 처리하지 않으므로, setter 메소드는 private이어야 한다. 객체가 저장될 때,
|
||||
Hibernate는 단지 식별자들을 할당할 것이다. 당신은 Hibernate가 public, private, protected 접근자 메소드들
|
||||
뿐만 아니라 (public, private, protected) 필드들에도 직접 접근할 수 있음을 알 수 있다. 선택은 당신에게 달려
|
||||
있으며, 당신은 당신의 어플리케이션 설계에 적합하도록 그것을 부합시킬 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -128,7 +136,7 @@ public class Event {
|
|||
</para>
|
||||
|
||||
<para>
|
||||
이 Java 노스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제
|
||||
이 Java 소스 파일을 개발 폴더 내의 <literal>src</literal>로 명명된 디렉토리 속에 있는 위치지워라. 이제
|
||||
그 디렉토리는 다음과 같을 것이다:
|
||||
</para>
|
||||
|
||||
|
@ -136,7 +144,8 @@ public class Event {
|
|||
+lib
|
||||
<Hibernate and third-party libraries>
|
||||
+src
|
||||
Event.java]]></programlisting>
|
||||
+events
|
||||
Event.java]]></programlisting>
|
||||
|
||||
<para>
|
||||
다음 단계에서, 우리는 Hiberante에게 이 영속 클래스에 대해 알려 준다.
|
||||
|
@ -144,8 +153,8 @@ public class Event {
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-firstapp-mapping">
|
||||
<title>매핑 파일</title>
|
||||
<sect2 id="tutorial-firstapp-mapping" revision="1">
|
||||
<title>The mapping file</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 영속 크래스들에 대한 객체들을 로드시키고 저장시키는 방법을 알 필요가 있다.
|
||||
|
@ -189,7 +198,7 @@ public class Event {
|
|||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Event" table="EVENTS">
|
||||
<class name="events.Event" table="EVENTS">
|
||||
|
||||
</class>
|
||||
|
||||
|
@ -204,9 +213,9 @@ public class Event {
|
|||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Event" table="EVENTS">
|
||||
<class name="events.Event" table="EVENTS">
|
||||
<id name="id" column="EVENT_ID">
|
||||
<generator class="increment"/>
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>
|
||||
|
||||
|
@ -230,9 +239,9 @@ public class Event {
|
|||
<programlisting><![CDATA[
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="Event" table="EVENTS">
|
||||
<class name="events.Event" table="EVENTS">
|
||||
<id name="id" column="EVENT_ID">
|
||||
<generator class="increment"/>
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="date" type="timestamp" column="EVENT_DATE"/>
|
||||
<property name="title"/>
|
||||
|
@ -242,7 +251,9 @@ public class Event {
|
|||
|
||||
<para>
|
||||
<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>
|
||||
|
@ -262,8 +273,9 @@ public class Event {
|
|||
그 자체를 결정하려고 시도할 것이다. 몇몇 경우들에서 (Java 클래스에 대한 Reflection을 사용하는) 이 자동적인 검출은
|
||||
당신이 예상하거나 필요로 하는 디폴트를 갖지 않을 수도 있다. 이것은 <literal>date</literal> 프로퍼티를 가진
|
||||
경우이다. Hibernate는 그 프로퍼티가 SQL <literal>date</literal> 컬럼, <literal>timestamp</literal>
|
||||
컬럼 또는 <literal>time</literal> 컬럼 중 어느 것으로 매핑되어야 하는지를 알 수가 없다. 우리는 <literal>timestamp</literal>를
|
||||
가진 프로퍼티를 매핑함으로써 전체 날짜와 시간 정보를 보존하고 싶다고 선언한다.
|
||||
컬럼 또는 <literal>time</literal> 컬럼 중 어느 것으로 매핑되어야 하는지를 알 수가 없다. 우리는
|
||||
<literal>timestamp</literal> 컨버터를 가진 프로퍼티를 매핑함으로써 전체 날짜와 시간 정보를 보존하고 싶다고
|
||||
선언한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -277,8 +289,9 @@ public class Event {
|
|||
+lib
|
||||
<Hibernate and third-party libraries>
|
||||
+src
|
||||
Event.java
|
||||
Event.hbm.xml]]></programlisting>
|
||||
+events
|
||||
Event.java
|
||||
Event.hbm.xml]]></programlisting>
|
||||
|
||||
<para>
|
||||
우리는 Hibernate의 메인 구성을 계속 행한다.
|
||||
|
@ -299,7 +312,7 @@ public class Event {
|
|||
<para>
|
||||
개발 디렉토리의 루트에 <literal>data</literal>로 명명된 디렉토리를 생성시켜라 - 이 디렉토리는
|
||||
HSQL DB가 그것의 데이터 파일들을 저장하게 될 장소이다. 이제 이 데이터 디렉토리에서
|
||||
<literal>java -classpath lib/hsqldb.jar org.hsqldb.Server</literal>를 실행시켜서
|
||||
<literal>java -classpath ../lib/hsqldb.jar org.hsqldb.Server</literal>를 실행시켜서
|
||||
데이터베이스를 시작시켜라. 당신은 그것이 시작되고 이것은 우리의 어플리케이션이 나중에 연결하게 될 장소인,
|
||||
하나의 TCP/IP 소켓에 바인드 되는 것을 볼 수 있다. 만일 이 튜토리얼 동안에 당신이 새 데이터베이스로
|
||||
시작하고자 원할 경우, HSQL DB를 셧다운시키고(왼도우에서 <literal>CTRL + C</literal>를 눌러라),
|
||||
|
@ -332,26 +345,29 @@ public class Event {
|
|||
|
||||
<!-- Database connection settings -->
|
||||
<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.password"></property>
|
||||
|
||||
<!-- JDBC connection pool (use the built-in) -->
|
||||
<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 -->
|
||||
<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 -->
|
||||
<property name="show_sql">true</property>
|
||||
|
||||
<!-- Drop and re-create the database schema on startup -->
|
||||
<property name="hbm2ddl.auto">create</property>
|
||||
|
||||
<mapping resource="Event.hbm.xml"/>
|
||||
<mapping resource="events/Event.hbm.xml"/>
|
||||
|
||||
</session-factory>
|
||||
|
||||
|
@ -382,7 +398,7 @@ public class Event {
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-firstapp-ant">
|
||||
<sect2 id="tutorial-firstapp-ant" revision="1">
|
||||
<title>Ant로 빌드하기</title>
|
||||
|
||||
<para>
|
||||
|
@ -393,16 +409,6 @@ public class Event {
|
|||
명명되고 개발 디렉토리 속에 직접 위치될 것이다.
|
||||
</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>
|
||||
|
@ -460,7 +466,7 @@ Total time: 1 second ]]></programlisting>
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-firstapp-helpers" revision="1">
|
||||
<sect2 id="tutorial-firstapp-helpers" revision="3">
|
||||
<title>시작과 helper들</title>
|
||||
|
||||
<para>
|
||||
|
@ -478,12 +484,14 @@ Total time: 1 second ]]></programlisting>
|
|||
유용하며, 우리는 현재의 작업 단위를 현재의 쓰레드와 연관지워 유지한다. 구현을 살펴보자:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[import org.hibernate.*;
|
||||
<programlisting><![CDATA[package util;
|
||||
|
||||
import org.hibernate.*;
|
||||
import org.hibernate.cfg.*;
|
||||
|
||||
public class HibernateUtil {
|
||||
|
||||
public static final SessionFactory sessionFactory;
|
||||
private static final SessionFactory sessionFactory;
|
||||
|
||||
static {
|
||||
try {
|
||||
|
@ -496,25 +504,10 @@ public class HibernateUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static final ThreadLocal session = new ThreadLocal();
|
||||
|
||||
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 SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
public static void closeSession() throws HibernateException {
|
||||
Session s = (Session) session.get();
|
||||
if (s != null)
|
||||
s.close();
|
||||
session.set(null);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -545,9 +538,11 @@ public class HibernateUtil {
|
|||
+lib
|
||||
<Hibernate and third-party libraries>
|
||||
+src
|
||||
Event.java
|
||||
Event.hbm.xml
|
||||
HibernateUtil.java
|
||||
+events
|
||||
Event.java
|
||||
Event.hbm.xml
|
||||
+util
|
||||
HibernateUtil.java
|
||||
hibernate.cfg.xml
|
||||
+data
|
||||
build.xml]]></programlisting>
|
||||
|
@ -567,7 +562,7 @@ build.xml]]></programlisting>
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-firstapp-workingpersistence" revision="2">
|
||||
<sect2 id="tutorial-firstapp-workingpersistence" revision="4">
|
||||
<title>객체 로딩과 객체 저장</title>
|
||||
|
||||
<para>
|
||||
|
@ -575,11 +570,13 @@ build.xml]]></programlisting>
|
|||
메소드를 가진 한 개의 <literal>EventManager</literal> 클래스를 작성한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[import org.hibernate.Transaction;
|
||||
<programlisting><![CDATA[package events;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import util.HibernateUtil;
|
||||
|
||||
public class EventManager {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -589,28 +586,24 @@ public class EventManager {
|
|||
mgr.createAndStoreEvent("My Event", new Date());
|
||||
}
|
||||
|
||||
HibernateUtil.sessionFactory.close();
|
||||
HibernateUtil.getSessionFactory().close();
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
private void createAndStoreEvent(String title, Date theDate) {
|
||||
|
||||
<para>
|
||||
우리는 명령 라인으로부터 몇몇 아규먼트들을 읽어들이고, 만일 첫 번째 아규먼트가 "store"이면, 우리는
|
||||
새로운 Event를 생성시키고 저장시킨다:
|
||||
</para>
|
||||
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
|
||||
|
||||
<programlisting><![CDATA[private void createAndStoreEvent(String title, Date theDate) {
|
||||
Session session = HibernateUtil.getCurrentSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
session.beginTransaction();
|
||||
|
||||
Event theEvent = new Event();
|
||||
theEvent.setTitle(title);
|
||||
theEvent.setDate(theDate);
|
||||
Event theEvent = new Event();
|
||||
theEvent.setTitle(title);
|
||||
theEvent.setDate(theDate);
|
||||
|
||||
session.save(theEvent);
|
||||
session.save(theEvent);
|
||||
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
HibernateUtil.closeSession();
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -621,22 +614,31 @@ public class EventManager {
|
|||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal>은 한 개의 작업 단위이다. 당신은 우리가 추가적인 API, <literal>Transaction</literal>dmf
|
||||
갖고 있음에 놀랐을 수도 있다. 이것은 작업 단위가 한 개의 데이터베이스 트랜잭션보다 "더 긴" 경우일 수 있음을 의미한다
|
||||
-웹 어플리케이션 속에서 여러 개의 Http 요청/응답 주기들(예를 들면 마법사 대화상자)에 걸치는 작업 단위를 상상하라.
|
||||
지금 우리는 그것들을 간단하게 유지할 것이고 <literal>Session</literal>과 <literal>Transaction</literal>
|
||||
사이에 한 개의 one-to-one 입상을 가정할 것이다.
|
||||
<literal>Session</literal>은 한 개의 작업 단위이다. 지금부터 우리는 단숨함을 유지할 것이고
|
||||
Hibernate <literal>Session</literal>과 데이터베이스 트랜잭션 사이의 일-대-일 과립형(granularity)을 가정할 것이다.
|
||||
실제 기반 트랜잭션 시스템으로부터 우리의 소스를 은폐시키기 위해(이 경우 통상의 JDBC이지만, 그것은 또한 JTA에도 실행된다)
|
||||
우리는 Hibernate <literal>Session</literal> 상에서 이용 가능한 <literal>Transaction</literal> API를
|
||||
사용한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Transaction.begin()</literal>과 <literal>commit()</literal>은 무엇을 행하는가?
|
||||
잘못되는 경우들에서 <literal>rollback()</literal>은 어디에 있는가? Hibernate
|
||||
<literal>Transaction</literal> API는 실제 옵션이지만, 우리는 편의와 이식성을 위해 그것을 사용한다.
|
||||
(예를 들어 <literal>session.connection.commit()</literal>을 호출함으로써)만일 당신 자신이
|
||||
데이터베이스 트랜잭션을 처리했다면, 당신은 이 직접적인 관리되지 않는 JDBC로 특별한 배치 환경에 그 코드를
|
||||
바인드시켰다. 당신의 Hibernate 구성 속에서 <literal>Transaction</literal>을 위한 팩토리를 설정함으로써,
|
||||
당신은 당신의 영속 계층을 어디에서나 배치할 수 있다. 트랜잭션 처리와 관할에 대한 추가 정보는
|
||||
<xref linkend="transactions"/>를 살펴보라. 우리는 또한 이 예제에서 오류 핸들링과 롤백을 생략했다.
|
||||
<literal>sessionFactory.getCurrentSession()</literal>은 무엇을 행하는가? 먼저
|
||||
당신은 당신이 (<literal>HibernateUtil</literal> 덕분에 쉽게) <literal>SessionFactory</literal>을
|
||||
당신이 소유하고 있다면, 원하는 만큼 어디서든 여러번 그것을 호출할 수 있다.
|
||||
<literal>getCurrentSession()</literal> 메소드는 항상 "현재의" 작업 단위를 반환한다. 우리가
|
||||
<literal>hibernate.cfg.xml</literal> 내에서 이 매커니즘에 대한 구성 옵션을 "thread"로 전환시켰음을 기억하는가?
|
||||
그러므로 현재 작업 단위의 영역은 우리의 어플리케이션을 실행시키는 현재의 Java 쓰레드이다. 하지만 이것은
|
||||
전부가 진실은 아니다. 그것이 처음으로 필요로 되고, <literal>getCurrentSession()</literal>을 첫번째로
|
||||
호출할 때 <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>
|
||||
|
@ -644,7 +646,7 @@ public class EventManager {
|
|||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="run" depends="compile">
|
||||
<java classname="EventManager" classpathref="libraries">
|
||||
<java fork="true" classname="events.EventManager" classpathref="libraries">
|
||||
<classpath path="${targetdir}"/>
|
||||
<arg value="${action}"/>
|
||||
</java>
|
||||
|
@ -691,13 +693,14 @@ else if (args[0].equals("list")) {
|
|||
</para>
|
||||
|
||||
<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();
|
||||
|
||||
tx.commit();
|
||||
session.close();
|
||||
session.getTransaction().commit();
|
||||
|
||||
return result;
|
||||
}]]></programlisting>
|
||||
|
@ -722,9 +725,9 @@ else if (args[0].equals("list")) {
|
|||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 프로퍼티를 주석처리함으로써 hbm2ddl을
|
||||
사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서 그것을 사용 가능하게 내버려두어도 되지만, 또 다른
|
||||
hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>드롭</emphasis>시킬 것이다 - <literal>create</literal>
|
||||
이제 당신의 <literal>hibernate.cfg.xml</literal> 파일 속에서 그 프로퍼티를 주석처리함으로써 hbm2ddl을
|
||||
사용불가능하게 하라. 대개 당신은 지속되는 단위 테스팅에서는 그것을 사용 가능하게 내버려두어도 되지만, 또 다른
|
||||
hbm2ddl의 실행은 당신이 저장했던 모든 것을 <emphasis>drop</emphasis>시킬 것이다 - <literal>create</literal>
|
||||
구성 설정은 실제로 "스키마로부터 모든 테이블들을 드롭시키고 나서, SessionFactory가 빌드될 때 모든 테이블들을
|
||||
다시 생성시키는 것"으로 변환된다.
|
||||
</para>
|
||||
|
@ -755,35 +758,38 @@ else if (args[0].equals("list")) {
|
|||
우리는 우리의 어플리케이션에 사람들을 추가하고 그들이 참여하는 이벤트들의 목록을 저장할 것이다.
|
||||
</para>
|
||||
|
||||
<sect2 id="tutorial-associations-mappinguser">
|
||||
<sect2 id="tutorial-associations-mappinguser" revision="1">
|
||||
<title>Person 클래스 매핑하기</title>
|
||||
|
||||
<para>
|
||||
클래스의 첫 번째 장면은 간단하다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Person {
|
||||
<programlisting><![CDATA[package events;
|
||||
|
||||
public class Person {
|
||||
|
||||
private Long id;
|
||||
private int age;
|
||||
private String firstname;
|
||||
private String lastname;
|
||||
|
||||
Person() {}
|
||||
public Person() {}
|
||||
|
||||
// Accessor methods for all properties, private setter for 'id'
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Person.hbm.xml</literal>로 명명된 새로운 매핑 파일을 생성시켜라:
|
||||
<literal>Person.hbm.xml</literal>로 명명되는 새로운 매핑 파일을 생성시켜라
|
||||
(맨위에 DTD 참조를 잊지말라):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Person" table="PERSON">
|
||||
<class name="events.Person" table="PERSON">
|
||||
<id name="id" column="PERSON_ID">
|
||||
<generator class="increment"/>
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="age"/>
|
||||
<property name="firstname"/>
|
||||
|
@ -796,9 +802,8 @@ else if (args[0].equals("list")) {
|
|||
마지막으로 새로운 매핑을 Hibernate의 구성에 추가하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[ <mapping resource="Event.hbm.xml"/>
|
||||
<mapping resource="Person.hbm.xml"/>
|
||||
]]></programlisting>
|
||||
<programlisting><![CDATA[<mapping resource="events/Event.hbm.xml"/>
|
||||
<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이제 우리는 이들 두 개의 엔티티들 사이에 한 개의 연관을 생성시킬 것이다. 명백하게, 개인들은 이벤트들에
|
||||
|
@ -845,29 +850,6 @@ else if (args[0].equals("list")) {
|
|||
사용한다:
|
||||
</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">
|
||||
<id name="id" column="PERSON_ID">
|
||||
<generator class="native"/>
|
||||
|
@ -882,6 +864,7 @@ else if (args[0].equals("list")) {
|
|||
</set>
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate는 모든 종류의 콜렉션 매핑들, 가장 공통적인 <literal><set></literal>을 지원한다. many-to-many
|
||||
연관 (또는 <emphasis>n:m</emphasis> 엔티티 관계)의 경우, 한 개의 연관 테이블이 필요하다. 이 테이블 내에 있는 각각의
|
||||
|
@ -912,7 +895,7 @@ else if (args[0].equals("list")) {
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-associations-working" revision="1">
|
||||
<sect2 id="tutorial-associations-working" revision="2">
|
||||
<title>연관들에 작업하기</title>
|
||||
|
||||
<para>
|
||||
|
@ -920,16 +903,16 @@ else if (args[0].equals("list")) {
|
|||
</para>
|
||||
|
||||
<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);
|
||||
Event anEvent = (Event) session.load(Event.class, eventId);
|
||||
|
||||
aPerson.getEvents().add(anEvent);
|
||||
|
||||
tx.commit();
|
||||
HibernateUtil.closeSession();
|
||||
session.getTransaction().commit();
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -940,7 +923,9 @@ else if (args[0].equals("list")) {
|
|||
프로퍼티를 변경함으로써 그것을 시도할 수 있다. 그것들이 <emphasis>영속(persistent)</emphasis> 상태에 있는 동안, 즉 특정 Hibernate
|
||||
<literal>Session</literal>에 바인드되어 있는 동안(예를 들면. 그것들은 작업 단위 속에 방금 로드되었거나 저장되었다),
|
||||
Hibernate는 임의의 변경들을 모니터링하고 쓰기 이면의 형태로 SQL을 실행시킨다. 메모리 상태를 데이터베이스와 동기화 시키는
|
||||
과정은 대개 오직 작업 단위의 끝에서이고, <emphasis>flushing</emphasis>이라 명명된다.
|
||||
과정은 대개 오직 작업 단위의 끝에서이고, <emphasis>flushing</emphasis>이라 명명된다. 우리의 코드에서, 작업 단위는
|
||||
<literal>CurrentSessionContext</literal> 클래스에 대한 <literal>thread</literal> 구성 옵션에 의해 정의된
|
||||
대로 - 데이터베이스 트랜잭션의 커밋(또는 롤백)으로 끝이난다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -949,41 +934,54 @@ else if (args[0].equals("list")) {
|
|||
<emphasis>detached</emphasis>라고 부른다). (매우 사실적이지 않은) 코드 내에서 이것은 다음과 같을 수 있다:
|
||||
</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);
|
||||
Event anEvent = (Event) session.load(Event.class, eventId);
|
||||
Person aPerson = (Person) session
|
||||
.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();
|
||||
HibernateUtil.closeSession();
|
||||
Event anEvent = (Event) session.load(Event.class, eventId);
|
||||
|
||||
aPerson.getEvents().add(anEvent); // aPerson is detached
|
||||
session.getTransaction().commit();
|
||||
|
||||
Session session2 = HibernateUtil.getCurrentSession();
|
||||
Transaction tx2 = session.beginTransaction();
|
||||
// End of first unit of work
|
||||
|
||||
session2.update(aPerson); // Reattachment of aPerson
|
||||
aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
|
||||
|
||||
tx2.commit();
|
||||
HibernateUtil.closeSession();
|
||||
}
|
||||
]]></programlisting>
|
||||
// Begin second unit of work
|
||||
|
||||
Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
|
||||
session2.beginTransaction();
|
||||
|
||||
session2.update(aPerson); // Reattachment of aPerson
|
||||
|
||||
session2.getTransaction().commit();
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>update</literal>에 대한 호출은 한 개의 detached 객체를 영속화 시키고, 당신은 그것이 새로운 작업 단위에
|
||||
<literal>update</literal>에 대한 호출은 한 개의 detached 객체를 다시 영속화 시키고, 당신은 그것이 새로운 작업 단위에
|
||||
바인드된다고 말할 수 있고, 따라서 detached 동안에 당신이 그것에 대해 행한 임의의 변경들이 데이터베이스에 저장될 수 있다.
|
||||
이것은 당신이 그 엔티티 객체의 콜렉션에 대해 행했던 임의의 변경들(추가/삭제)를 포함한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
물론, 이것은 우리의 현재 상황에서 많이 사용되지 않지만, 그것은 당신이 당신 자신의 어플리케이션 속으로 설계할 수 있는 중요한
|
||||
개념이다. 지금 한 개의 새로운 액션을 <literal>EventManager</literal>의 main 메소드에 추가하고 명령 라인에서 그것을
|
||||
물론, 우리의 현재 상황에서 이것은 많이 사용되지 않지만, 그것은 당신이 당신 자신의 어플리케이션 내로 설계할 수 있는 중요한
|
||||
개념이다. 지금 <literal>EventManager</literal>의 main 메소드에 한 개의 새로운 액션을 추가하고 명령 라인에서 그것을
|
||||
호출하여 이 연습을 완료하라. 만일 당신이 한명의 개인과 한 개의 이벤트에 대한 식별자들을 필요로 할 경우 - <literal>save()</literal>
|
||||
메소드가 그것을 반환시킨다.
|
||||
메소드가 그것을 반환시킨다(당신은 그 식별자를 반환시키는 앞의 메소드들 중 몇몇을 변경시켜야 할 것이다):
|
||||
</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>
|
||||
이것은 두 개의 동등하게 중요한 클래스들, 두 개의 엔티티들 사이에서 한 개의 연관에 관한 예제였다. 앞서 언급했듯이, 전형적인 모형 내에는
|
||||
다른 클래스들과 타이들이 존재하는데, 대개 "덜 중요하다". 당신은 이미 <literal>int</literal> 또는 <literal>String</literal>과
|
||||
|
@ -1065,9 +1063,29 @@ public void setEmailAddresses(Set emailAddresses) {
|
|||
그것은 Java에서 동일한 코드이다.
|
||||
</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 id="tutorial-associations-bidirectional">
|
||||
<sect2 id="tutorial-associations-bidirectional" revision="1">
|
||||
<title>Bi-directional associations</title>
|
||||
|
||||
<para>
|
||||
|
@ -1097,7 +1115,7 @@ public void setParticipants(Set participants) {
|
|||
|
||||
<programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
|
||||
<key column="EVENT_ID"/>
|
||||
<many-to-many column="PERSON_ID" class="Person"/>
|
||||
<many-to-many column="PERSON_ID" class="events.Person"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
@ -1183,7 +1201,7 @@ public void removeFromEvent(Event event) {
|
|||
그것은 새로운 이벤트들을 입력하기 위한 HTML form을 제공한다.
|
||||
</para>
|
||||
|
||||
<sect2 id="tutorial-webapp-servlet">
|
||||
<sect2 id="tutorial-webapp-servlet" revision="1">
|
||||
<title>기본 서블릿 작성하기</title>
|
||||
|
||||
<para>
|
||||
|
@ -1198,17 +1216,9 @@ public void removeFromEvent(Event event) {
|
|||
|
||||
public class EventManagerServlet extends HttpServlet {
|
||||
|
||||
private final SimpleDateFormat dateFormatter =
|
||||
new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
// Servlet code
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>dateFormatter</literal>는 나중에 문자열들로부터 그리고 문자열로 <literal>Date</literal> 객체들을
|
||||
변환하는데 나중에 사용하게 될 도구이다. 서블릿의 멤버로서 오직 한 개의 formatter를 갖는 것이 도리에 맞다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
서블릿은 HTTP <literal>GET</literal> 요청들 만을 처리하므로, 우리가 구현하는 메소드는 <literal>doGet()</literal>이다:
|
||||
</para>
|
||||
|
@ -1217,6 +1227,8 @@ public class EventManagerServlet extends HttpServlet {
|
|||
HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
try {
|
||||
// Begin unit of work
|
||||
HibernateUtil.getSessionFactory()
|
||||
|
@ -1259,7 +1271,7 @@ public class EventManagerServlet extends HttpServlet {
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="tutorial-webapp-processing">
|
||||
<sect2 id="tutorial-webapp-processing" revision="1">
|
||||
<title>프로세싱과 렌더링</title>
|
||||
|
||||
<para>
|
||||
|
@ -1286,7 +1298,7 @@ if ( "store".equals(request.getParameter("action")) ) {
|
|||
|
||||
// Print page
|
||||
printEventForm(out);
|
||||
listEvents(out);
|
||||
listEvents(out, dateFormatter);
|
||||
|
||||
// Write HTML footer
|
||||
out.println("</body></html>");
|
||||
|
@ -1315,7 +1327,8 @@ out.close();]]></programlisting>
|
|||
쓰레드에 결합된 Hibernate <literal>Session</literal>을 사용한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[private void listEvents(PrintWriter out) {
|
||||
<programlisting><![CDATA[private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {
|
||||
|
||||
List result = HibernateUtil.getSessionFactory()
|
||||
.getCurrentSession().createCriteria(Event.class).list();
|
||||
if (result.size() > 0) {
|
||||
|
|
|
@ -43,10 +43,10 @@
|
|||
<fo:block>
|
||||
<fo:external-graphic src="file:images/hibernate_logo_a.png"/>
|
||||
</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"/>
|
||||
</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"/>
|
||||
</fo:block>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<xsl:variable name="Version">
|
||||
<xsl:choose>
|
||||
<xsl:when test="//releaseinfo">
|
||||
<xsl:text>하이버네이트 </xsl:text>
|
||||
<xsl:text>하이버네이트</xsl:text>
|
||||
<xsl:value-of select="//releaseinfo"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
|
@ -256,10 +256,10 @@
|
|||
################################################### -->
|
||||
|
||||
<!-- 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 -->
|
||||
<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 -->
|
||||
<xsl:attribute-set name="monospace.properties">
|
||||
|
@ -311,7 +311,6 @@
|
|||
<l:template name="sect4" text="the section called %t"/>
|
||||
<l:template name="sect5" text="the section called %t"/>
|
||||
</l:context>
|
||||
|
||||
</l:l10n>
|
||||
</l:i18n>
|
||||
|
||||
|
@ -516,9 +515,9 @@
|
|||
|
||||
<!-- Korean related Settings -->
|
||||
<xsl:param name="hyphenate">false</xsl:param>
|
||||
<xsl:param name="body.font.family">Gulim</xsl:param>
|
||||
<!-- xsl:param name="monospace.font.family">가을체</xsl:param-->
|
||||
<xsl:param name="title.font.family">가을체</xsl:param>
|
||||
<xsl:param name="body.font.family">Hankc</xsl:param>
|
||||
<!-- xsl:param name="monospace.font.family">Bangwool</xsl:param-->
|
||||
<xsl:param name="title.font.family">Bangwool</xsl:param>
|
||||
<xsl:param name="saxon.character.representation" select="native"/>
|
||||
<xsl:param name="callout.unicode" select="1"/>
|
||||
<xsl:param name="callout.unicode.start.character" select="10102"/>
|
||||
|
|
Loading…
Reference in New Issue