*** empty log message ***
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@7183 1b8cb986-b30d-0410-93ca-fae66ebed9b2
@ -28,6 +28,7 @@
|
||||
<antcall target="lang.all"><param name="lang" value="en"/></antcall>
|
||||
<antcall target="lang.all"><param name="lang" value="zh-cn"/></antcall>
|
||||
<antcall target="lang.all"><param name="lang" value="es"/></antcall>
|
||||
<antcall target="lang.all"><param name="lang" value="ko"/></antcall>
|
||||
|
||||
</target>
|
||||
|
||||
@ -37,6 +38,7 @@
|
||||
<!-- TRANSLATOR: Duplicate this line for your language -->
|
||||
<antcall target="lang.revdiff"><param name="lang" value="zh-cn"/></antcall>
|
||||
<antcall target="lang.revdiff"><param name="lang" value="es"/></antcall>
|
||||
<antcall target="lang.revdiff"><param name="lang" value="ko"/></antcall>
|
||||
|
||||
</target>
|
||||
|
||||
|
BIN
reference/ko/fop/Gaeul.ttf
Normal file
1
reference/ko/fop/Gaeul.xml
Normal file
1
reference/ko/fop/Gulim.xml
Normal file
BIN
reference/ko/fop/gulim.ttc
Normal file
113
reference/ko/fop/userconfig.xml
Normal file
@ -0,0 +1,113 @@
|
||||
<!--<!DOCTYPE configuration SYSTEM "config.dtd">-->
|
||||
<!--
|
||||
this file contains templates which allow an user easy
|
||||
configuration of Fop. Actually normally you don't need this configuration
|
||||
file, but if you need to change configuration, you should
|
||||
always use this file and *not* config.xml.
|
||||
Usage: java org.apache.fop.apps.Fop -c userconfig.xml -fo fo-file -pdf pdf-file
|
||||
-->
|
||||
|
||||
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
baseDir: normally the base directory is the directory where the fo file is
|
||||
located. if you want to specify your own, uncomment this entry.
|
||||
This value can also be a URL. Actually, the value is converted to
|
||||
a URL.
|
||||
-->
|
||||
<!--
|
||||
<entry>
|
||||
<key>baseDir</key>
|
||||
<value></value>
|
||||
</entry>
|
||||
-->
|
||||
<!--
|
||||
fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
|
||||
it isn't specified, the value from baseDir is used.
|
||||
-->
|
||||
<!--
|
||||
<entry>
|
||||
<key>fontBaseDir</key>
|
||||
<value></value>
|
||||
</entry>
|
||||
-->
|
||||
|
||||
<!--
|
||||
************************************************************************
|
||||
HYPHENATION
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<!--
|
||||
hyphenation directory
|
||||
if you want to specify your own directory with hyphenation pattern
|
||||
then uncomment the next entry and add the directory name
|
||||
-->
|
||||
|
||||
<!--
|
||||
<entry>
|
||||
<key>hyphenation-dir</key>
|
||||
<value>/java/xml-fop/hyph</value>
|
||||
</entry>
|
||||
-->
|
||||
|
||||
<!--
|
||||
************************************************************************
|
||||
Add fonts here
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<fonts>
|
||||
<!-- example -->
|
||||
<!--
|
||||
<font metrics-file="arial.xml" kerning="yes" embed-file="arial.ttf">
|
||||
<font-triplet name="Arial" style="normal" weight="normal"/>
|
||||
<font-triplet name="ArialMT" style="normal" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-file="arialb.xml" kerning="yes" embed-file="arialb.ttf">
|
||||
<font-triplet name="Arial" style="normal" weight="bold"/>
|
||||
<font-triplet name="ArialMT" style="normal" weight="bold"/>
|
||||
</font>
|
||||
<font metrics-file="ariali.xml" kerning="yes" embed-file="ariali.ttf">
|
||||
<font-triplet name="Arial" style="italic" weight="normal"/>
|
||||
<font-triplet name="ArialMT" style="italic" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-file="arialbi.xml" kerning="yes" embed-file="arialbi.ttf">
|
||||
<font-triplet name="Arial" style="italic" weight="bold"/>
|
||||
<font-triplet name="ArialMT" style="italic" weight="bold"/>
|
||||
</font>
|
||||
-->
|
||||
<!-- Example Japanese fonts
|
||||
<font metrics-file="msgothic.xml" embed-file="D:\winnt\font\msgothic.ttc" kerning="yes">
|
||||
<font-triplet name="Gothic" style="normal" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="normal" weight="bold"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="bold"/>
|
||||
</font>
|
||||
<font metrics-file="msmincho.xml" embed-file="Cyberbit.ttf" kerning="yes">
|
||||
<font-triplet name="Mincho" style="normal" weight="normal"/>
|
||||
<font-triplet name="Mincho" style="normal" weight="bold"/>
|
||||
<font-triplet name="Mincho" style="italic" weight="normal"/>
|
||||
<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>
|
||||
<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>
|
||||
</fonts>
|
||||
|
||||
|
||||
</configuration>
|
||||
|
||||
|
||||
|
BIN
reference/ko/images/AuthorWork.gif
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
reference/ko/images/AuthorWork.zargo
Normal file
BIN
reference/ko/images/CustomerOrderProduct.gif
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
reference/ko/images/CustomerOrderProduct.zargo
Normal file
BIN
reference/ko/images/EmployerEmployee.gif
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
reference/ko/images/EmployerEmployee.zargo
Normal file
BIN
reference/ko/images/full_cream.gif
Normal file
After Width: | Height: | Size: 9.1 KiB |
429
reference/ko/images/full_cream.svg
Normal file
@ -0,0 +1,429 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="354.331"
|
||||
height="336.614"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
|
||||
style="font-size:12;"
|
||||
id="g659">
|
||||
<rect
|
||||
width="212.257"
|
||||
height="57.2441"
|
||||
x="17.9576"
|
||||
y="100.132"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<rect
|
||||
width="325.86"
|
||||
height="63.6537"
|
||||
x="17.4083"
|
||||
y="15.194"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="325.86"
|
||||
height="63.6537"
|
||||
x="13.6713"
|
||||
y="12.4966"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
<g
|
||||
transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<text
|
||||
x="170.824753"
|
||||
y="58.402939"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="170.824997"
|
||||
y="58.402901"
|
||||
id="tspan360">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="178.076340"
|
||||
y="364.281433"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="178.076004"
|
||||
y="364.281006"
|
||||
id="tspan421">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="68.605331"
|
||||
y="138.524582"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="68.605301"
|
||||
y="138.524994"
|
||||
id="tspan384">
|
||||
SessionFactory</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="67.0014"
|
||||
height="101.35"
|
||||
x="196.927"
|
||||
y="89.2389"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect387" />
|
||||
<rect
|
||||
width="67.0014"
|
||||
height="101.35"
|
||||
x="194.633"
|
||||
y="86.4389"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect388" />
|
||||
<text
|
||||
x="249.108841"
|
||||
y="173.885559"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text389">
|
||||
<tspan
|
||||
x="249.108994"
|
||||
y="173.886002"
|
||||
id="tspan392">
|
||||
Session</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="73.0355"
|
||||
height="101.35"
|
||||
x="270.995"
|
||||
y="90.0018"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect395" />
|
||||
<rect
|
||||
width="73.0355"
|
||||
height="101.35"
|
||||
x="267.869"
|
||||
y="87.2018"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect396" />
|
||||
<text
|
||||
x="328.593658"
|
||||
y="174.715622"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text397">
|
||||
<tspan
|
||||
x="328.593994"
|
||||
y="174.716003"
|
||||
id="tspan563">
|
||||
Transaction</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
|
||||
style="font-size:12;"
|
||||
id="g565">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect566" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect567" />
|
||||
</g>
|
||||
<text
|
||||
x="25.592752"
|
||||
y="204.497803"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text568">
|
||||
<tspan
|
||||
x="25.592800"
|
||||
y="204.498001"
|
||||
id="tspan662">
|
||||
TransactionFactory</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
|
||||
style="font-size:12;"
|
||||
id="g573">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect574" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect575" />
|
||||
</g>
|
||||
<text
|
||||
x="134.030670"
|
||||
y="205.532791"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text576">
|
||||
<tspan
|
||||
x="134.031006"
|
||||
y="205.533005"
|
||||
id="tspan664">
|
||||
ConnectionProvider</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
|
||||
style="font-size:12;"
|
||||
id="g587">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect588" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect589" />
|
||||
</g>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="25.6196"
|
||||
y="206.028"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect594" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="24.4229"
|
||||
y="204.135"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect595" />
|
||||
<text
|
||||
x="85.575645"
|
||||
y="282.300354"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text596">
|
||||
<tspan
|
||||
x="85.575600"
|
||||
y="282.299988"
|
||||
id="tspan607">
|
||||
JNDI</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="236.937"
|
||||
y="206.791"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect610" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="235.741"
|
||||
y="204.898"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect611" />
|
||||
<text
|
||||
x="342.093201"
|
||||
y="283.226410"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text612">
|
||||
<tspan
|
||||
x="342.092987"
|
||||
y="283.226013"
|
||||
id="tspan621">
|
||||
JTA</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="130.134"
|
||||
y="206.791"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect616" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="128.937"
|
||||
y="204.898"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect617" />
|
||||
<text
|
||||
x="212.445343"
|
||||
y="283.226410"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text618">
|
||||
<tspan
|
||||
x="212.445007"
|
||||
y="283.226013"
|
||||
id="tspan623">
|
||||
JDBC</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
|
||||
style="font-size:12;"
|
||||
id="g637">
|
||||
<g
|
||||
transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="33.749969"
|
||||
y="50.589706"
|
||||
style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="33.750000"
|
||||
y="50.589699"
|
||||
id="tspan635">
|
||||
Transient Objects</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
|
||||
style="font-size:12;"
|
||||
id="g644">
|
||||
<g
|
||||
transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
|
||||
id="g364">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect365" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect366" />
|
||||
</g>
|
||||
<text
|
||||
x="277.123230"
|
||||
y="85.155571"
|
||||
style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text367">
|
||||
<tspan
|
||||
x="277.122986"
|
||||
y="85.155602"
|
||||
id="tspan631">
|
||||
Persistent</tspan>
|
||||
<tspan
|
||||
x="277.122986"
|
||||
y="96.155602"
|
||||
id="tspan633">
|
||||
Objects</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
BIN
reference/ko/images/hibernate_logo_a.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
reference/ko/images/lite.gif
Normal file
After Width: | Height: | Size: 6.6 KiB |
334
reference/ko/images/lite.svg
Normal file
@ -0,0 +1,334 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="318.898"
|
||||
height="248.031"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<rect
|
||||
width="291.837"
|
||||
height="57.0074"
|
||||
x="17.3169"
|
||||
y="18.646"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="291.837"
|
||||
height="57.0074"
|
||||
x="13.9703"
|
||||
y="16.2302"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
<g
|
||||
transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g161">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
|
||||
style="font-size:12;"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="302.277679"
|
||||
y="65.943230"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="302.277954"
|
||||
y="65.943184"
|
||||
id="tspan360">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="36.235924"
|
||||
y="63.796055"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="36.235950"
|
||||
y="63.796051"
|
||||
id="tspan427">
|
||||
Transient Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="180.416245"
|
||||
y="290.543701"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="180.415939"
|
||||
y="290.543549"
|
||||
id="tspan421">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="25.037701"
|
||||
y="179.154755"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="25.037655"
|
||||
y="179.154648"
|
||||
id="tspan384">
|
||||
SessionFactory</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g386">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect387" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect388" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
|
||||
style="font-size:12;"
|
||||
id="g364">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect365" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect366" />
|
||||
</g>
|
||||
<text
|
||||
x="202.746506"
|
||||
y="102.992203"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text367">
|
||||
<tspan
|
||||
x="202.746948"
|
||||
y="102.992249"
|
||||
id="tspan423">
|
||||
Persistent</tspan>
|
||||
<tspan
|
||||
x="202.746948"
|
||||
y="116.992355"
|
||||
id="tspan425">
|
||||
Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="174.458496"
|
||||
y="180.080795"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text389">
|
||||
<tspan
|
||||
x="174.458618"
|
||||
y="180.080338"
|
||||
id="tspan392">
|
||||
Session</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g394">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect395" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect396" />
|
||||
</g>
|
||||
<text
|
||||
x="260.413269"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text397">
|
||||
<tspan
|
||||
x="260.412964"
|
||||
y="179.154343"
|
||||
id="tspan400">
|
||||
JDBC</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g405">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect406" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect407" />
|
||||
</g>
|
||||
<text
|
||||
x="320.606903"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text408">
|
||||
<tspan
|
||||
x="320.606964"
|
||||
y="179.154343"
|
||||
id="tspan417">
|
||||
JNDI</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g411">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect412" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect413" />
|
||||
</g>
|
||||
<text
|
||||
x="377.096313"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text414">
|
||||
<tspan
|
||||
x="377.096008"
|
||||
y="179.154999"
|
||||
id="tspan145">
|
||||
JTA</tspan>
|
||||
</text>
|
||||
</svg>
|
After Width: | Height: | Size: 8.5 KiB |
BIN
reference/ko/images/overview.gif
Normal file
After Width: | Height: | Size: 8.4 KiB |
250
reference/ko/images/overview.svg
Normal file
@ -0,0 +1,250 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="248.031"
|
||||
height="248.031"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
|
||||
style="font-size:12;"
|
||||
id="g158">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="17.3527"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="15.3883"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
|
||||
style="font-size:12;"
|
||||
id="g161">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
|
||||
style="font-size:12;"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="105.392174"
|
||||
y="56.568123"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="105.392273"
|
||||
y="56.568146"
|
||||
id="tspan186">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="81.820183"
|
||||
y="103.149330"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="81.820213"
|
||||
y="103.149727"
|
||||
id="tspan206">
|
||||
Persistent Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="111.548180"
|
||||
y="278.927887"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="111.547874"
|
||||
y="278.927551"
|
||||
id="tspan200">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="94.436180"
|
||||
y="153.805740"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="94.436180"
|
||||
y="153.805740"
|
||||
id="tspan221">
|
||||
HIBERNATE</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
|
||||
style="font-size:12;"
|
||||
id="g254">
|
||||
<g
|
||||
transform="translate(4.58374,2.61928)"
|
||||
id="g176">
|
||||
<g
|
||||
transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
|
||||
id="g170">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect171" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect172" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
|
||||
id="g173">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect174" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect175" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
x="47.259438"
|
||||
y="182.367538"
|
||||
style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
|
||||
id="text191">
|
||||
<tspan
|
||||
x="47.259399"
|
||||
y="182.367996"
|
||||
id="tspan212">
|
||||
hibernate.</tspan>
|
||||
<tspan
|
||||
x="47.259399"
|
||||
y="194.367996"
|
||||
id="tspan214">
|
||||
properties</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="198.523010"
|
||||
y="188.260941"
|
||||
style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
|
||||
id="text194">
|
||||
<tspan
|
||||
id="tspan195">
|
||||
XML Mapping</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.5 KiB |
BIN
reference/ko/images/tutorial_schema.GIF
Normal file
After Width: | Height: | Size: 4.7 KiB |
191
reference/ko/master.xml
Normal file
@ -0,0 +1,191 @@
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
|
||||
"../support/docbook-dtd/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY quickstart SYSTEM "modules/quickstart.xml">
|
||||
<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
|
||||
<!ENTITY architecture SYSTEM "modules/architecture.xml">
|
||||
<!ENTITY configuration SYSTEM "modules/configuration.xml">
|
||||
<!ENTITY persistent-classes SYSTEM "modules/persistent_classes.xml">
|
||||
<!ENTITY basic-mapping SYSTEM "modules/basic_mapping.xml">
|
||||
<!ENTITY collection-mapping SYSTEM "modules/collection_mapping.xml">
|
||||
<!ENTITY association-mapping SYSTEM "modules/association_mapping.xml">
|
||||
<!ENTITY component-mapping SYSTEM "modules/component_mapping.xml">
|
||||
<!ENTITY inheritance-mapping SYSTEM "modules/inheritance_mapping.xml">
|
||||
<!ENTITY session-api SYSTEM "modules/session_api.xml">
|
||||
<!ENTITY transactions SYSTEM "modules/transactions.xml">
|
||||
<!ENTITY events SYSTEM "modules/events.xml">
|
||||
<!ENTITY batch SYSTEM "modules/batch.xml">
|
||||
<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
|
||||
<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
|
||||
<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
|
||||
<!ENTITY filters SYSTEM "modules/filters.xml">
|
||||
<!ENTITY xml SYSTEM "modules/xml.xml">
|
||||
<!ENTITY performance SYSTEM "modules/performance.xml">
|
||||
<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
|
||||
<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
|
||||
<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
|
||||
<!ENTITY example-mappings SYSTEM "modules/example_mappings.xml">
|
||||
<!ENTITY best-practices SYSTEM "modules/best_practices.xml">
|
||||
]>
|
||||
|
||||
<book lang="ko">
|
||||
|
||||
<bookinfo lang="ko">
|
||||
<title>HIBERNATE - 개성있는 자바를 위한 관계 영속</title>
|
||||
<subtitle>하이버네이트 참조 문서</subtitle>
|
||||
<releaseinfo lang="ko">3.0.5</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<toc lang="ko" />
|
||||
|
||||
<preface id="preface" revision="2">
|
||||
<title>머리말</title>
|
||||
|
||||
<para>
|
||||
객체 지향 소프트웨어와 관계형 데이터베이스로 작업하는 것은 오늘날의 엔터프라이즈 환경들에서 성가시고 시간이
|
||||
소비될 수 있다. Hibernate는 자바 환경들을 위한 객체/관계형 매핑 도구이다.
|
||||
object/relational mapping(ORM) 용어는 객체 모형으로부터 SQL-기반의 스키마를 가진
|
||||
관계형 데이터 모형으로의 데이터 표상을 매핑하는 기술을 언급한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 자바 클래스들로부터 데이터베이스로의 매핑(그리고 자바 데이터 타입들로부터 SQL 데이터
|
||||
타입들로의 매핑)을 처리할 뿐만 아니라, 또한 데이터 질의와 검색 편의들을 제공하며, SQL과 JDBC로
|
||||
수작업 데이터 핸들링에 소요되는 개발 시간을 현저하게 단축시켜줄 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate의 목적은 공통된 데이터 영속화 관련 프로그래밍 작업들의 95%를 덜어주는 것이다.
|
||||
Hibernate는 데이터베이스에서 비지니스 로직을 구현하는데 내장 프로시저들을 전용으로 사용하는 데이터
|
||||
중심적 어플리케이션에 대한 최상의 솔루션이 아닐 수도 있지만, 그것은 자바 기반 미들-티어에서 객체 지향
|
||||
도메인 모형들과 비지니스 로직에 가장 유용하다. 하지만 Hibernate는 벤더 지정적인 SQL 코드를
|
||||
제거하거나 캡슐화 시키는 당신을 확실히 도와줄 수 있고 테이블 형식의 표현으로부터 객체들의 그래프로 결과
|
||||
셋을 변환하는 공통된 태스크를 도와줄 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 당신이 Hibernate와 Object/Relational 매핑 또는 심지어 자바에 초심자라면, 다음
|
||||
단계들을 따르기 바란다:
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Tomcat을 사용하는 30분짜리 빠른시작,
|
||||
<xref linkend="quickstart" />
|
||||
을 읽어라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
더 많은 단계적인 사용 설명서들을 가진 더 긴 튜토리얼은
|
||||
<xref linkend="tutorial" />
|
||||
을 읽어라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate가 사용될 수 있는 환경을 이해려면
|
||||
<xref linkend="architecture" />
|
||||
를 읽어라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate 배포본 내의
|
||||
<literal>eg/</literal>
|
||||
디렉토리를 살펴 보라. 이 디렉토리는 간단한 스탠드얼론 어플리케이션을 포함하고 있다. 당신의
|
||||
JDBC 드라이버를
|
||||
<literal>lib/</literal>
|
||||
디렉토리에 복사하고 당신의 데이터베이스에 맞는 정확한 값을 지정하여
|
||||
<literal>etc/hibernate.properties</literal>
|
||||
를 편집하라. 배보본 디렉토리에서 명령 라인 프롬프트에서 (Ant를 사용하여)
|
||||
<literal>ant eg</literal>
|
||||
를 타이핑 하거나 , Windows 하에서
|
||||
<literal>build eg</literal>
|
||||
를 타이프 하라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
당신의 주된 정보의 소스로서 이 참조 문서를 사용하라. 만일 어플리케이션 설계에 대해 더 많은
|
||||
도움을 필요로 하거나 당신이 단계적인 튜토리얼을 선호한다면
|
||||
<emphasis>Hibernate in Action</emphasis>
|
||||
(http://www.manning.com/bauer)을 읽는 것을 고려하라.또한
|
||||
http://caveatemptor.hibernate.org에 방문하여 Hibernate in
|
||||
Action용 예제 어플리케이션을 다운로드 하라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>FAQ들은 Hibernate 웹 사이트 상에 답변되어 있다.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
제 3의 데모들, 예제들, 그리고 튜토리얼들은 Hibernate 웹 사이트 상에 링크되어
|
||||
있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate 웹사이트 상의 공동체 영역은 설계 패턴과 다양한 통합 솔루션들(Tomcat,
|
||||
JBoss AS, Struts, EJB 등.)에 관한 좋은 리소스이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>
|
||||
질문이 있다면, Hibernate 상에 링크되어 있는 사용자 포럼을 사용하라. 우리는 또한 버그 보고와 특징
|
||||
요청들을 위한 JIRA 쟁점 추적 시스템을 제공한다. 당신이 Hibernate의 개발에 관심이 있다면,
|
||||
개발자 메일링 리스트에 참여하라. 만일 당신이 이 문서를 당신의 언어로 번역하는 것에 관심이 있다면, 개발자
|
||||
메일링 리스트에 접촉하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate를 위한 상용 개발 지원, 제품 지원, 그리고 교육은 JBoss Inc를 통해 이용 가능하다
|
||||
(http://www.hibernate.org/SupportTraining/를 보라). Hibernate는
|
||||
JBoss Professional Open Source product 프로젝트이고 제품들에 대한 JBoss
|
||||
Enterprise Middleware System (JEMS) suite의 중대한 컴포넌트이다.
|
||||
</para>
|
||||
|
||||
</preface>
|
||||
|
||||
&quickstart;
|
||||
|
||||
&tutorial;
|
||||
|
||||
&architecture;
|
||||
|
||||
&configuration;
|
||||
|
||||
&persistent-classes;
|
||||
|
||||
&basic-mapping;
|
||||
&collection-mapping;
|
||||
&association-mapping;
|
||||
&component-mapping;
|
||||
&inheritance-mapping;
|
||||
|
||||
&session-api;
|
||||
&transactions;
|
||||
&events;
|
||||
&batch;
|
||||
|
||||
&query-hql;
|
||||
&query-criteria;
|
||||
&query-sql;
|
||||
&filters;
|
||||
&xml;
|
||||
|
||||
&performance;
|
||||
|
||||
&toolset-guide;
|
||||
|
||||
&example-parentchild;
|
||||
&example-weblog;
|
||||
&example-mappings;
|
||||
|
||||
&best-practices;
|
||||
|
||||
</book>
|
||||
|
240
reference/ko/modules/architecture.xml
Normal file
@ -0,0 +1,240 @@
|
||||
<chapter id="architecture">
|
||||
|
||||
<title>아키텍처</title>
|
||||
|
||||
<sect1 id="architecture-overview" revision="1">
|
||||
<title>개요</title>
|
||||
|
||||
<para>
|
||||
Hibernate 아키텍처에 대한 (매우) 높은 수준의 개요::
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/overview.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
이 다이어그램은 어플리케이션에 영속화 서비스들(과 영속 객체들)을 제공하기 위해 데이터베이스와
|
||||
컨피그레이션을 사용하는 Hibernate를 보여준다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 런타임 아키텍처에 대한 보다 상세한 뷰를 보여주고 싶다. 불행하게도, Hibernate는 유연하며
|
||||
몇 가지 접근법들을 제공한다. 우리는 두 가지 극단을 보여줄 것이다. "경량급" 아키텍처는 그것 자신의
|
||||
JDBC 커넥션들을 제공하고 그것 자신의 트랜잭션들을 관리하는 어플리케이션을 갖는다. 이 접근법은
|
||||
Hibernate의 API의 최소 부분집합을 사용한다:
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/lite.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
"전체 정수" 아키텍처는 기본 JDBC/JTA로부터 어플리케이션을 추상화 시키고 Hibernate로 하여금
|
||||
상세한 것을 처리하게 한다.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
다음은 다이어그램들 내에 있는 객체들에 대한 몇가지 정의들이다:
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
단일 데이터베이스에 대한 컴파일된 매핑들의 threadsafe (불변의) 캐시. Session과 ConnectionProvider의
|
||||
클라이언트를 위한 팩토리. 프로세스 레벨 또는 클러스터 레벨에서 트랜잭션들 사이에 재사용 가능한 데이터의 선택적인
|
||||
(second-level) 캐시를 보관할 수도 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Session (<literal>org.hibernate.Session</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
어플리케이션과 영속 저장소 사이의 대화를 표현하는 단일 쓰레드이고, 수명이 짧은 객체. JDBC 커넥션을 포장한다.
|
||||
<literal>Transaction</literal> 용 팩토리. 객체 그래프를 네비게이트 하거나 식별자로 객체들을 룩업할 때
|
||||
사용되는 영속 객체들에 대한 필수적인(첫 번째 레벨의) 캐시를 보관한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Persistent objects and collections</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>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session</literal>과 현재 연관되어 있지 않은 영속 클래스들의 인스턴스들. 그것들은 어플리케이션에 의해 초기화
|
||||
되었고 (아직) 영속화 되지 않았거나 그것들은 닫혀진<literal>Session</literal>에 의해 초기화 되었을 수도 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(옵션) 작업의 원자 단위를 지정하기 위해 어플리케이션에 의해 사용되는 단일 쓰레드이고, 수명이 짧은 객체. 기본 JDBC, JTA
|
||||
또는 CORBA 트랜잭션으로부터 어플리케이션을 추상화 시킨다. 몇몇 경우들에서 하나의 <literal>Session</literal>은
|
||||
여러 개의 <literal>Transaction</literal>들에 걸칠 수 있다. 하지만 기본 API 또는 <literal>Transaction</literal>을
|
||||
사용하는 트랜잭션 경계 설정은 결코 옵션이 아니다!
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(옵션) JDBC 커넥션들에 대한 팩토리(그리고 그것들의 pool). 기본 <literal>Datasource</literal> 또는
|
||||
<literal>DriverManager</literal>로부터 어플리케이션을 추상화 시킨다. 어플리케이션에 노출되지는 않지만
|
||||
개발자에 의해 확장/구현 된다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(옵션) <literal>Transaction</literal> 인스턴스들에 대한 팩토리. 어플리케이션에 노출되지는 않지만 개발자에 의해
|
||||
확장/구현 된다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis>Extension Interfaces</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate는 당신의 영속 계층의 특성을 맞춤화 시키기 위해 당신이 구현할 수 있는 선택적인 확장 인터페이스들을 제공한다.
|
||||
상세한 것은 API 문서를 보라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
주어진 "경량급" 아키텍처의 경우, 어플리케이션은 JTA 또는 JDBC와 직접 대화하기 위해서 <literal>Transaction</literal>/<literal>TransactionFactory</literal>
|
||||
그리고/또는 <literal>ConnectionProvider</literal> API들을 무시한다.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-states" revision="1">
|
||||
<title>인스턴스 상태들</title>
|
||||
<para>
|
||||
영속 클래스들의 인스턴스는 세개의 상태들 중 하나 일 수 있다. 그것들(상태들)은 영속 컨텍스트(<emphasis>persistence context</emphasis>)에
|
||||
대해 정의된다. Hibernate <literal>Session</literal> 객체는 영속 컨텍스트이다:
|
||||
</para>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>transient</term>
|
||||
<listitem>
|
||||
<para>
|
||||
인스턴스는 임의의 컨텍스트와 연관되어 있지 않고, 결코 연관된 적이 없었다. 그것은 영속 식별자(프라이머리 키 값)을 갖지 않는다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>persistent</term>
|
||||
<listitem>
|
||||
<para>
|
||||
인스턴스는 현재 영속 컨텍스트와 연관되어 있다. 그것은 영속 식별자(프라이머리 키 값) 그리고 아마 데이터베이스 내에 있는 대응하는
|
||||
행을 갖는다. 특별한 영속 컨텍스트의 경우, Hibernate는 영속 identity가 Java identity(객체의 메모리 내 위치)와 같다는 점을
|
||||
<emphasis>보증한다</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>detached</term>
|
||||
<listitem>
|
||||
<para>
|
||||
인스턴스는 영속 컨텍스트와 한번 연관되었지만, 그 컨텍스트가 닫혔거나, 그 인스턴스가 또 다른 프로세스로 직렬화 되었다. 그것은 영속
|
||||
identity 그리고, 아마 데이터베이스 내에 대응하는 행을 갖는다. detached 인스턴스들의 경우, Hibernate는 영속 identity과
|
||||
Java identity 사이의 관계를 보증하지 않는다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-jmx" revision="1">
|
||||
<title>JMX 통합</title>
|
||||
|
||||
<para>
|
||||
JMX는 자바 컴포넌트 관리를 위한 J2EE 표준이다. Hibernate는 JMX 표준 서비스를 통해 관리될 수도 있다. 우리는 배포본 내에 MBean 구현,
|
||||
<literal>org.hibernate.jmx.HibernateService</literal>를 제공한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
JBoss 어플리케이션 서버 상에 Hibernae를 JMX 서비스로서 배치하는 방법에 대한 예제는 JBoss 사용자 가이드를 보길 바란다. JBoss
|
||||
어플리케이션 서버 상에서, 만일 당신이 JMX를 사용하여 배치할 경우 당신은 또한 다음 이점들을 얻는다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Session 관리:</emphasis> Hibernate <literal>Session</literal>의 생명주기가 JTA 트랜잭션의
|
||||
영역 내에 자동적으로 바인드 될 수 있다. 이것은 당신이 더이상 <literal>Session</literal>을 수작업으로 열고 닫지 않아도
|
||||
됨을 의미하고, 이것은 JBoss EJB 인터셉터의 업무가 된다. 당신은 또한 더 이상 당신의 코드 어느 곳에서든 트랜잭션 경계설정에
|
||||
대해 걱정하지 않아도 된다(당신이 물론 이식성 있는 영속 계층을 작성하고자 원하지 않는한, 이를 위해 옵션 Hibernate <literal>Transaction</literal>
|
||||
API를 사용하라). 당신은 <literal>Session</literal>에 접근하기 위해 <literal>HibernateContext</literal>를 호출한다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>HAR 배치:</emphasis> 대개 당신은 JBoss 서비스 배치 디스크립터를 사용하여 Hibernate JMX 서비스를
|
||||
(EAR 과/또는 SAR 파일로) 배치하고, 그것은 Hibernate <literal>SessionFactory</literal>의 통상적인 구성
|
||||
옵션들 모두를 지원한다. 하지만 당신은 여전히 모든 당신의 매핑 파일들을 배치 디스크립터 속에 명명해야 한다. 만일 당신이
|
||||
옵션 HAR 배치를 사용하고자 결정하는 경우, JBoss는 당신의 HAR 파일 내에 있는 모든 매핑 파일들을 자동적으로 검출해낼 것이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
이들 옵션들에 대한 추가 정보는 JBoss 어플리케이션 서버 사용자 가이드를 참조하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
JMX 서비스로서 이용 가능한 또다른 특징은 런타임 Hibernate 통계이다.
|
||||
<xref linkend="configuration-optional-statistics"/>를 보라.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-jca" revision="1">
|
||||
<title>JCA 지원</title>
|
||||
<para>
|
||||
Hibernate는 JCA 커넥터로서 구성될 수도 있다. 상세한 것은 웹 사이트를 보길 바란다. Hibernate JCA 지원은 여전히 실험적으로
|
||||
검토 중에 있음을 노트하길 바란다.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
523
reference/ko/modules/association_mapping.xml
Normal file
@ -0,0 +1,523 @@
|
||||
<chapter id="associations">
|
||||
|
||||
<title>연관 매핑들</title>
|
||||
|
||||
<sect1 id="assoc-intro" revision="1">
|
||||
<title>개요</title>
|
||||
|
||||
<para>
|
||||
연관 매핑들은 올바른 것을 얻기가 종종 가장 어려운 것이다. 이 절에서 우리는 단방향 매핑들에서 시작하고, 그런 다음 양방향 경우들을
|
||||
검토함으로써, 하나씩 표준적인 경우들을 상세히 논의할 것이다. 우리는 모든 예제들에서 <literal>Person</literal>과
|
||||
<literal>Address</literal>를 사용할 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 연관들을 중재하는 join 테이블로 매핑시킬 것인지 여부에 따라, 그리고 multiplicity(다중성)에 따라 연관들을 분류할 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
null 허용 가능한 foreign 키들은 전통적인 데이터 모델링에서 좋은 실례로 간주되지 않아서, 모든 우리의 예제들은 not null
|
||||
foreign 키들을 사용한다. 이것은 Hibernate에서 필수가 아니고, 당신이 null 허용 가능 컨스트레인트들을 드롭시킬 경우 매핑들은
|
||||
모두 동작할 것이다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-unidirectional" revision="1">
|
||||
<title>단방향 연관들</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-m21">
|
||||
<title>many to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>단방향 many-to-one 연관</emphasis>은 가장 공통적인 종류의 단방향 연관이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-121">
|
||||
<title>one to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>foreign 키에 대한 단방향 one-to-one 연관은 대개 아주 동일하다.</emphasis> 유일한 차이점은
|
||||
컬럼 유일(unique) 컨스트레인트이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
unique="true"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 프라이머리 키에 대한 단방향 one-to-one 연관</emphasis>은 대개 특별한 id 생성기를 사용한다.
|
||||
(이 예제에서 연관의 방향이 역전되었음을 주목하라.)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="personId">
|
||||
<generator class="foreign">
|
||||
<param name="property">person</param>
|
||||
</generator>
|
||||
</id>
|
||||
<one-to-one name="person" constrained="true"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( personId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-12m">
|
||||
<title>one to many</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 foreign 키에 대한 단방향 one-to-many 연관</emphasis>은 매우 색다른 경우이고, 실제로 권장되지 않는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses">
|
||||
<key column="personId"
|
||||
not-null="true"/>
|
||||
<one-to-many class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</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 )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
우리는 이런 종류의 연관에 대해 하나의 join 테이블을 사용하는 것이 더 좋다고 생각한다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-unidirectional-join" revision="1">
|
||||
<title>join 테이블들에 대한 단방향 연관들</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-12m">
|
||||
<title>one to many</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 join 테이블에 대한 단방향 one-to-many 연관</emphasis>이 보다 더 선호된다. <literal>unique="true"</literal>를
|
||||
지정함으로써 우리는 many-to-many에서 one-to-many로 아중성(multiplicity)를 변경시켰음을 주목하라.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses" table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
unique="true"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m21">
|
||||
<title>many to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 join 테이블에 대한 단방향 many-to-one 연관</emphasis>은 그 연관이 선택적일 때 매우 공통적이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId" unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-121">
|
||||
<title>one to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 join 테이블에 대한 단방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만 가능하다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m2m">
|
||||
<title>many to many</title>
|
||||
|
||||
<para>
|
||||
마지막으로, 우리는 <emphasis>단방향 many-to-many 연관</emphasis>을 갖는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses" table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-bidirectional" revision="1">
|
||||
<title>양방향 연관들</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-m21">
|
||||
<title>one to many / many to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>양방향 many-to-one 연관</emphasis>은 가장 공통된 종류의 연관이다.(이것은 표준 부모/자식 관계이다. )
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="people" inverse="true">
|
||||
<key column="addressId"/>
|
||||
<one-to-many class="Person"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-121">
|
||||
<title>one to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>foreign에 대한 양방향 one-to-one 연관</emphasis>은 꽤 공통적이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
unique="true"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<one-to-one name="person"
|
||||
property-ref="address"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key,
|
||||
addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 프라이머리 키에 대한 양방향 one-to-one 연관</emphasis>은 특별한 id 생성기를 사용한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<one-to-one name="address"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="personId">
|
||||
<generator class="foreign">
|
||||
<param name="property">person</param>
|
||||
</generator>
|
||||
</id>
|
||||
<one-to-one name="person"
|
||||
constrained="true"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( personId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-bidirectional-join" revision="1">
|
||||
<title>join 테이블들에 대한 양방향 연관들</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-12m">
|
||||
<title>one to many / many to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 join 테이블에 대한 양방향 one-to-many 연관</emphasis>. <literal>inverse="true"</literal>는
|
||||
연관의 어느 쪽 끝이든 콜렉션 측으로 또는 join 측으로 갈 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses"
|
||||
table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
unique="true"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
inverse="true"
|
||||
optional="true">
|
||||
<key column="addressId"/>
|
||||
<many-to-one name="person"
|
||||
column="personId"
|
||||
not-null="true"/>
|
||||
</join>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-121">
|
||||
<title>one to one</title>
|
||||
|
||||
<para>
|
||||
<emphasis>하나의 join 테이블에 대한 양방향 one-to-one 연관</emphasis>은 극히 통상적이지 않지만, 가능하다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true"
|
||||
inverse="true">
|
||||
<key column="addressId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="personId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-m2m">
|
||||
<title>many to many</title>
|
||||
|
||||
<para>
|
||||
마지막으로, 우리는 하나의 <emphasis>양방향 many-to-many 연관</emphasis>을 갖는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="people" inverse="true">
|
||||
<key column="addressId"/>
|
||||
<many-to-many column="personId"
|
||||
class="Person"/>
|
||||
</set>
|
||||
</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 Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
</chapter>
|
||||
|
2962
reference/ko/modules/basic_mapping.xml
Normal file
178
reference/ko/modules/batch.xml
Normal file
@ -0,0 +1,178 @@
|
||||
<chapter id="batch">
|
||||
<title>Batch 처리</title>
|
||||
|
||||
<para>
|
||||
Hibernate를 사용하여 데이터베이스 내에서 100 000 개의 행들을 삽입시키는 본래의 접근법은 다음과 같다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
for ( int i=0; i<100000; i++ ) {
|
||||
Customer customer = new Customer(.....);
|
||||
session.save(customer);
|
||||
}
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
이것은 50 000번째 행 가까운 곳에서 <literal>OutOfMemoryException</literal>으로 떨어질 것이다. 그것은 Hibernate가
|
||||
session-level 캐시 속에 모든 새로이 삽입된 <literal>Customer</literal> 인스턴스들을 캐시시키기 때문이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 장에서 우리는 이 문제를 피하는 방법을 당신에게 보여줄 것이다. 하지만 먼저 당신이 배치 처리를 행하는 중이라면, 당신이 적당한 퍼포먼스를
|
||||
성취하려고 할 경우에 당신이 JDBC 배치 사용을 가능하게 하는 것은 절대적으로 필요하다. JDBC 배치 사이즈를 적당한 숫자(10-50)로 설정하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></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>
|
||||
|
||||
<sect1 id="batch-inserts">
|
||||
<title>Batch inserts</title>
|
||||
|
||||
<para>
|
||||
새로운 객체들을 영속화 시킬 때, 당신은 first-level 캐시의 사이즈를 제어하기 위해 세션을 정기적으로 <literal>flush()</literal>
|
||||
시키고 나서 <literal>clear()</literal> 시켜야 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
for ( int i=0; i<100000; i++ ) {
|
||||
Customer customer = new Customer(.....);
|
||||
session.save(customer);
|
||||
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
|
||||
//flush a batch of inserts and release memory:
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-update" >
|
||||
<title>Batch updates</title>
|
||||
|
||||
<para>
|
||||
데이터 검색과 업데이트의 경우 동일한 개념들이 적용된다. 게다가 당신은 많은 데이터 행들을 반환하는 질의들에 대해 서버-측 커서들의 장점을
|
||||
취하는데 <literal>scroll()</literal>을 사용할 필요가 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
ScrollableResults customers = session.getNamedQuery("GetCustomers")
|
||||
.setCacheMode(CacheMode.IGNORE)
|
||||
.scroll(ScrollMode.FORWARD_ONLY);
|
||||
int count=0;
|
||||
while ( customers.next() ) {
|
||||
Customer customer = (Customer) customers.get(0);
|
||||
customer.updateStuff(...);
|
||||
if ( ++count % 20 == 0 ) {
|
||||
//flush a batch of updates and release memory:
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-direct">
|
||||
<title>대량 update/delete</title>
|
||||
|
||||
<para>
|
||||
이미 논의했듯이, 자동적이고 투명한 객체/관계형 매핑은 객체 상태에 대한 관리에 관계된다. 이것은 객체 상태가 메모리 내에서 이용 가능함을
|
||||
의미하므로, (SQL <literal>UPDATE</literal>와 <literal>DELETE</literal>를 사용하여) 데이터베이스 내에서 직접 데이터를
|
||||
업데이트하거나 삭제하는 것은 메모리 내 상태에 영향을 주지 않을 것이다. 하지만 Hibernate는 Hibernate Query Language를 통해
|
||||
수행되는 대량 SQL-스타일의 <literal>UPDATE</literal>와 <literal>DELETE</literal> 문장 실행을 위한 방법들을 제공한다.
|
||||
(<xref linkend="queryhql">HQL</xref>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>UPDATE</literal>와 <literal>DELETE</literal> 문장들의 유사-구문은 다음과 같다:
|
||||
<literal>( UPDATE | DELETE ) FROM? ClassName (WHERE WHERE_CONDITIONS)?</literal>. 노트할 몇 가지 :
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
from-절에서, FROM 키워드는 옵션이다
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
from-절 내에 명명된 한 개의 클래스가 오직 존재할 수 있고, alias를 가질 수 <emphasis>없다</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
join들은 (함축적이든 명시적이든) 대량 HQL 질의 속에 지정될 수 없다. 서브-질의들이 where-절 속에서 사용될 수 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
where-절 또한 옵션이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
하나의 예제로서, 한 개의 HQL <literal>UPDATE</literal>를 실행하기 위해, <literal>Query.executeUpdate()</literal>
|
||||
메소드를 사용하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
String hqlUpdate = "update 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>
|
||||
한 개의 HQL <literal>DELETE</literal>를 실행하기 위해, 동일한 <literal>Query.executeUpdate()</literal> 메소드를
|
||||
사용하라(그 메소드는 JDBC의 <literal>PreparedStatement.executeUpdate()</literal>에 친숙한 사람들을 위해 명명되어 있다):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
String hqlDelete = "delete Customer where name = :oldName";
|
||||
int deletedEntities = s.createQuery( hqlDelete )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Query.executeUpdate()</literal> 메소드에 의해 반환되는 <literal>int</literal> 값은 그 오퍼레이션에 의해
|
||||
영향받은 엔티티들의 개수를 나타낸다. 이것이 데이터베이스 내에서 영향받은 행들의 개수와 상관이 있는지 없는지 여부를 살펴보자. HQL
|
||||
대량 오퍼레이션은 예를 들어 joined-subclass의 경우에 실행 중인 여러 개의 실제 SQL 문장들로 귀결될 수 있다. 반환되는 숫자는
|
||||
그 문장에 의해 영향받은 실제 엔티티들의 개수를 나타낸다. joined-subclass 예제로 되돌아가면, 서브 클래스들 중 하나에 대한 삭제는
|
||||
단지 그 서브클래스가 매핑되어 있는 테이블에 대한 삭제 뿐만 아니라 또한 "루트" 테이블과 상속 계층에서 더 내려온 잠정적으로
|
||||
조인된-서브클래스 테이블들에 대한 삭제들로 귀결될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
장래의 배포본들에서 전달될 대량 HQL 오퍼레이션들에 대한 몇 가지 제한들이 현재 존재함을 노트하라; 상세한 것은 JIRA 로드맵을 참조하라.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
204
reference/ko/modules/best_practices.xml
Normal file
@ -0,0 +1,204 @@
|
||||
<chapter id="best-practices" revision="3">
|
||||
<title>최상의 실전 경험들</title>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>fine-grained 클래스들을 작성하고 <literal><component></literal>를 사용하여 그것들을 매핑하라. </term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>street</literal>, <literal>suburb</literal>, <literal>state</literal>, <literal>postcode</literal>를
|
||||
캡슐화 시키는데 <literal>Address</literal> 클래스를 사용하라. 이것은 코드 재사용성을 촉진시키고 리팩토링을 단순화 시킨다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>영속 클래스들에 대해 식별자 프로퍼티들을 선언하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate는 식별자 프로퍼티들을 옵션으로 만든다. 왜 우리가 그것들을 사용해야 하는가에 대한 모든 종류의 이유들이 존재한다.
|
||||
우리는 식별자들이 '합성(synthetic)'이 되는(비지니스 의미 없이 생성되는) 것을 권장한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>고유 키들을 식별하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
모든 엔티티들에 대해 고유 키들을 식별하고, <literal><natural-id></literal>를 사용하여 그것들을 매핑하라.
|
||||
고유 키를 구성하는 프로퍼티들을 비교하기 위해 <literal>equals()</literal>와 <literal>hashCode()</literal>를
|
||||
구현하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry><term>각각의 클래스 매핑을 그것 자신의 파일 내에 위치지워라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
하나의 한덩어리 매핑 문서를 사용하지 말라. <literal>com/eg/Foo.hbm.xml</literal> 파일 속에
|
||||
<literal>com.eg.Foo</literal>를 매핑하라. 이것은 팀 환경에서 특히 좋은 의미를 준다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>매핑들을 리소스들로서 로드시켜라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
그것들이 매핑하는 클래스들에 따라서 매핑들을 배치하라
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>질의 문자열들을 객관화 시키는 것을 고려하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
당신의 질의들이 ANSI 표준이 아닌 SQL 함수들을 호출하는 경우는 좋은 실전연습이다. 질의 문자열들을 매핑 파일들에다가
|
||||
외부화 시키는 것은 어플리케이션을 보다 이식성 있도록 만들어줄 것이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>바인드 변수들을 사용하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
JDBC에서처럼, 상수 아닌 값들을 "?"로 대체시켜라. 질의 속에 상수 아닌 값을 바인드 시키는데 문자열 처리를 결코
|
||||
사용하지 말라! 더 좋게는 질의들 속에 명명된 파라미터들을 사용하는 것을 고려하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>당신 자신의 JDBC 커넥션들을 관리하지 말라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate는 어플리케이션으로 하여금 JDBC 커넥션들을 관리하도록 한다. 이 접근법은 마지막 수단으로서 고려되어야 한다.
|
||||
만일 당신이 미리 만들어진 커넥션 프로바이더들을 사용할 수 없을 경우, <literal>org.hibernate.connection.ConnectionProvider</literal>에
|
||||
대한 당신 자신의 구현을 제공하는 것을 고려하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>맞춤형 타입 사용을 고려하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
당신이 자바 타입을 갖고 있고, 어떤 라이브러리로부터 말하고, 그것이 영속화 될 필요가 있지만 그것을 컴포넌트로서 매핑시키는데
|
||||
필요한 accessor들을 제공할 필요가 없다고 가정하자. 당신은 <literal>org.hibernate.UserType</literal>을 구현하는
|
||||
것을 고려해야 할 것이다. 이 접근법은 Hibernate 타입으로/으로부터 변환들을 구현하는 것으로부터 어플리케이션 코드를 자유롭게
|
||||
해준다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>병목 지점들에서 수작업으로 코딩된 JDBC를 사용하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
시스템의 퍼포먼스가 중대한 영역들에서, 몇몇 종류의 오퍼레이션들은 직접적인 JDBC에서 이득을 본다. 그러나 당신이 어떤 것이 병목인지를
|
||||
<emphasis>알기</emphasis> 전까지 기다리길 바란다. 그리고 직접적인 JDBC가 반드시 더 빠르다고 가정하지 말라. 만일 당신이 직접적인
|
||||
JDBC를 사용할 필요가 있을 경우, Hibernate <literal>Session</literal>을 열고 그 SQL 커넥션을 사용할 가치가 있다. 그 방법으로
|
||||
당신은 동일한 트랜잭션 방도와 기본 커넥션 프로바이더를 여전히 사용할 수 있다
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><literal>Session</literal> flushing을 이해하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
시간이 지남에 따라 Session은 그것의 영속 상태를 데이터베이스와 동기화 시킨다. 만일 이 과정이 너무 자주 발생할 경우 퍼포먼스가
|
||||
영향을 받을 것이다. 당신은 때때로 자동적인 flushing을 사용 불가능하게 만들거나 특정 트랜잭션 내에서 질의들의 순서와 다른
|
||||
오퍼레이션들의 순서를 변경시켜서 불필요한 flushing을 최소화 시킬 수 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>3-tier 아키텍처에서, <literal>saveOrUpdate()</literal> 사용을 고려하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
servlet / session 빈 아키텍처를 사용할 때, 당신은 sesson bean 내에 로드된 영속 객체들을 서블릿/JSP 계층으로/으로부터
|
||||
전달할/받을 수 있다. 각각의 요청을 서비스하는데 새로운 세션을 사용하라. 객체들을 데이터베이스와 동기화 시키기 위해서
|
||||
<literal>Session.merge()</literal> 또는 <literal>Session.saveOrUpdate()</literal>를 사용하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>2-tier 아키텍처에서, 수명이 긴 영속 컨텍스트들을 사용하는 것을 고려하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
데이터베이스 트랜잭션들은 최상의 가용성을 위해 가능한 한 짧아야 한다. 하지만 장기간 실행되는 <emphasis>어플리케이션 트랜잭션들</emphasis>,
|
||||
사용자의 뷰 관점에서 한 개의 단위 작업을 구현하는 것이 가끔 필수적이다. 하나의 어플리케이션 트랜잭션은 몇 개의 클라이언트 요청들과
|
||||
응답 주기들에 걸칠 수도 있다. 어플리케이션 트랜잭션들을 구현하는데 detached 객체들을 사용하는 것이 공통적이다. 2-티어 아키텍처에서
|
||||
매우 적절한 대안은 어플리케이션 트랜잭션의 전체 생명주기 동안에 한 개의 열려진 영속 접속 (세션)을 유지하는 것이고 각각의 요청의 끝에서
|
||||
JDBC 커넥션을 간단하게 연결해제하고 차후의 요청의 시작 시에 다시 연결하는 것이다. 한 개 이상의 어플리케이션 트랜잭션을 가로질러서
|
||||
하나의 단일 세션을 결코 공유하지 말라. 공유할 경우에 당신은 실효성이 없는 데이터로 작업하게 될 것이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>예외상황들을 복구가능한 것으로서 다루지 말라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
이것은 "최상의" 실전이 아닌 보다 필수적인 실전이다. 예외상황이 발생할 때, <literal>Transaction</literal>을 롤백시키고
|
||||
<literal>Session</literal>을 닫아라. 만일 당신이 그렇게 하지 않을 경우, Hibernate는 메모리 내 상태가 영속 상태를 정확하게
|
||||
표현하는 것을 보증할 수 없다. 이 특별한 경우처럼, 만일 주어진 식별자를 가진 인스턴스가 데이터베이스 상에 존재하는지 여부를 결정하는데
|
||||
<literal>Session.load()</literal>를 사용하지 말라; 대신에 <literal>Session.get()</literal> 또는 하나의 질의를
|
||||
사용하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>연관들에 대한 lazy 페칭을 선호하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
eager 페칭을 관대하게 사용하라. second-level 캐시 내에 완전하게 보관되지 않을 것 같은 클래스들에 대한 대붑분의 연관들에
|
||||
대해 프락시들과 lazy 콜렉션들을 사용하라. 캐시된 클래스들에 대한 연관들의 경우, 이곳은 캐시 성공의 매우 높은 확률이 존재하는
|
||||
곳이며, <literal>lazy="false"</literal>를 사용하여 eager 페칭을 명시적으로 사용 불가능하게 하라. 한의 join 페칭이
|
||||
특정 쓰임새에 대해 적절할 때, 하나의 <literal>left join fetch</literal>를 가진 질의를 사용하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
페치되지 않은 데이터 문제점들을 피하기 위해 <emphasis>뷰 내에 열려진 세션(open session in view)</emphasis> 패턴 또는
|
||||
하나의 정리된 <emphasis>어셈블리 단계(assembly phase)</emphasis>를 사용하라.
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate는 개발자들이 <emphasis>Data Transfer Objects</emphasis> (DTO)를 지루하게 작성하는 것으로부터
|
||||
자유롭게 해준다. 전통적인 EJB 아키텍처에서, DTO는 이중 용도로 기능한다: 첫 번째로 그것들은 엔티티 빈즈가 직렬화 가능하지 않는
|
||||
문제점에 대해 착수한다; 두 번째로 그것들은 뷰에 의해 사용되는 모든 데이터가 프리젠테이션 티어로 컨트롤을 반환하기 전에 DTO들 속으로
|
||||
페치되고 마샬링되는 어셈블리 단계를 암묵적으로 정의한다. Hibernate는 첫 번째 용도를 제거시킨다. 하지만 당신이 뷰 렌더링 프로세스를
|
||||
가로질러 열려져 있는 영속 컨텍스트(세션)을 보관할 준비가 되어 있지 않는 한, 당신은 여전히 어셈블리 단계를 필요로 할 것이다(detached
|
||||
객체들에서 이용가능한 데이터가 무엇인지에 대해 프리젠테이션 티어와 엄격하게 계약을 갖도록 당신의 비지니스 메소드들을 고려하라)
|
||||
이것은 Hibernate의 한계점이 아니다! 그것은 안전한 트랜잭션 데이터 접근의 필수 조건이다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Hibernate에서 당신의 비지니스 로직을 추상화 시키는 것을 고려하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(Hibernate) 데이터 액세스 코드를 인터페이스 이면에 은폐시켜라. <emphasis>DAO</emphasis>와
|
||||
<emphasis>Thread Local Session</emphasis> 패턴들을 결합시켜라. 당신은 심지어 <literal>UserType</literal>을
|
||||
통해 Hibernate에 연관된, 수작업으로 코딩된 JDBC로서 몇몇 클래스들을 영속화 시킬 수도 있다. (이 충고는 "충분히 큰"
|
||||
어플리케이션들에 대한 것이다; 그것은 5개의 테이블들을 가진 어플리케이션에 대해서는 적절하지 않다!)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>신종의 연관 매핑을 사용하지 말라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
실제의 many-to-many 연관들에 대한 좋은 쓰임새들은 드물다. 대부분의 시간 동안 당신은 "연결 테이블" 내에 저장된 추가적인 정보를 필요로 한다.
|
||||
이 경우에, 매개하는 연결 클래스에 대해 두 개의 one-to-many 연관들을 사용하는 것이 훨씬 더 좋다. 사실 우리는 대부분의 연관들이 one-to-many와
|
||||
many-to-one이라고 생각하며, 당신은 다른 연관 스타일을 사용할 때 주의해야 하고 그것이 진정 필수적인지를 당신 스스로 질문하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>양방향 연관들을 선호하라.</term>
|
||||
<listitem>
|
||||
<para>
|
||||
단방향 연관들은 질의하기가 더 어렵다. 많은 어플리케이션에서, 거의 모든 연관들은 질의들 내에서 양 방향으로 네비게이트 가능해야 한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</chapter>
|
||||
|
1075
reference/ko/modules/collection_mapping.xml
Normal file
374
reference/ko/modules/component_mapping.xml
Normal file
@ -0,0 +1,374 @@
|
||||
<chapter id="components">
|
||||
<title>Component 매핑</title>
|
||||
|
||||
<para>
|
||||
<emphasis>component</emphasis>의 개념은 Hibernate에서 다른 용도로 몇몇 다른 컨텍스트들 내에서 재사용된다.
|
||||
</para>
|
||||
|
||||
<sect1 id="components-dependentobjects">
|
||||
<title>종속 객체들</title>
|
||||
|
||||
<para>
|
||||
하나의 컴포넌트는 엔티티 참조가 아닌, value 타입으로서 영속화 되는 하나의 포함된 객체이다. "컴포넌트" 용어는
|
||||
(아키텍처 수준의 컴포넌트들이 아닌) composition(구성,합성)에 대한 객체-지향적인 개념을 언급한다.
|
||||
예를 들어 당신은 다음과 같이 개인을 모형화 시킬 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Person {
|
||||
private java.util.Date birthday;
|
||||
private Name name;
|
||||
private String key;
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
private void setKey(String key) {
|
||||
this.key=key;
|
||||
}
|
||||
public java.util.Date getBirthday() {
|
||||
return birthday;
|
||||
}
|
||||
public void setBirthday(java.util.Date birthday) {
|
||||
this.birthday = birthday;
|
||||
}
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(Name name) {
|
||||
this.name = name;
|
||||
}
|
||||
......
|
||||
......
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public class Name {
|
||||
char initial;
|
||||
String first;
|
||||
String last;
|
||||
public String getFirst() {
|
||||
return first;
|
||||
}
|
||||
void setFirst(String first) {
|
||||
this.first = first;
|
||||
}
|
||||
public String getLast() {
|
||||
return last;
|
||||
}
|
||||
void setLast(String last) {
|
||||
this.last = last;
|
||||
}
|
||||
public char getInitial() {
|
||||
return initial;
|
||||
}
|
||||
void setInitial(char initial) {
|
||||
this.initial = initial;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
이제 <literal>Name</literal>은 <literal>Person</literal>의 컴포넌트로서 영속화 될 수도 있다. <literal>Name</literal>이
|
||||
그것의 영속 프로퍼티들에 대한 getter 메소드와 setter 메소드를 정의하지만, 어떤 인터페이스들이나 식별자 프로퍼티들을 선언하는 것을
|
||||
필요로 하지 않음을 주목하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리의 Hibernate 매핑은 다음과 같을 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<id name="Key" column="pid" type="string">
|
||||
<generator class="uuid.hex"/>
|
||||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name"> <!-- class attribute optional -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
person 테이블은
|
||||
<literal>pid</literal>,
|
||||
<literal>birthday</literal>,
|
||||
<literal>initial</literal>,
|
||||
<literal>first</literal>,
|
||||
<literal>last</literal> 컬럼들을 가질 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
모든 값(value) 타입들처럼, 컴포넌트들은 공유된 참조들을 지원하지 않는다. 달리 말해, 두 명의 개인들은 동일한 이름을 가질 수
|
||||
있지만, 두 개의 person 객체들은 오직 값 만이 "동일한" 두 개의 독립적인 name 객체들을 포함할 것이다. 컴포넌트의 null 값 의미는
|
||||
<emphasis>특별한 용도를 위한 것이다</emphasis>. 포함된 객체를 다시 로드시킬 때, Hibernate는 모든 컴포넌트 컬럼들이
|
||||
null일 경우에 전체 컴포넌트가 null이라고 가정할 것이다. 이것은 대부분의 용도에 맞을 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
컴포넌트의 프로퍼티들은 임의의 Hibernate 타입일 수 있다(콜렉션들, many-to-one 연관들, 다른 컴포넌트들, 기타).
|
||||
내포된 컴포넌트들은 신종의 사용례로 간주되지 <emphasis>않을</emphasis> 것이다. Hibernate는 매우 잘 정제된 객체 모형을
|
||||
지원하도록 고안되어있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal><component></literal> 요소는 컴포넌트 클래스의 프로퍼티를 포함되는 엔티티에 대한 역 참조로서 매핑시키는
|
||||
<literal><parent></literal> 서브요소를 허용한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<id name="Key" column="pid" type="string">
|
||||
<generator class="uuid.hex"/>
|
||||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name" unique="true">
|
||||
<parent name="namedPerson"/> <!-- reference back to the Person -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-incollections" revision="1">
|
||||
<title>종속 객체들을 가진 콜렉션들</title>
|
||||
|
||||
<para>
|
||||
컴포넌트들을 가진 콜렉션들이 지원된다(예를 들면 <literal>Name</literal> 타입을 가진 배열).
|
||||
<literal><element></literal> 태그를 <literal><composite-element></literal> 태그로
|
||||
대체시켜서 당신의 컴포넌트 콜렉션을 선언하라.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
|
||||
<key column="id"/>
|
||||
<composite-element class="eg.Name"> <!-- class attribute required -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</composite-element>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
노트: 만일 당신이 composite 요소를 가진 하나의 <literal>Set</literal>를 정의할 경우, <literal>equals()</literal>와
|
||||
<literal>hashCode()</literal>를 정확하게 구현하는 것이 매우 중요하다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Composite 요소들은 컴포넌트들을 포함하지만 콜렉션들을 포함하지 않는다. 만일 당신의 composite 요소 자체가 컴포넌트들을 포함할
|
||||
경우, <literal><nested-composite-element></literal> 태그를 사용하라. 이것은 꽤 신종의 경우-그것들 자체가
|
||||
컴포넌트들을 갖고 있는 컴포넌트들의 콜렉션-이다. 이 단계에서 당신은 one-to-many 연관이 더 적절한지를 당신 스스로에게 질문하게
|
||||
될 것이다. 하나의 엔티티로서 composite 요소를 다시 모델링하려고 시도하라 - 그러나 자바 모형들이 동일할지라도,
|
||||
관계형 모형과 영속화 의미들은 여전히 약간 다르다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신이 하나의 <literal><set></literal>을 사용 중이라면, 하나의 composite 요소 매핑은 null 가능한 프로퍼티들을
|
||||
지원하지 않음을 노트하길 바란다. Hibernate는 객체들을 삭제할 때 하나의 레코드를 식별하는데 각각의 컬럼들 값을 사용해야 하며
|
||||
(composite 요소 테이블 내에 별도의 프라이머리 키 컬럼이 존재하지 않는다), 그것은 null 값들에 대해서는 불가능하다. 당신은
|
||||
하나의 composite-요소 내에 not-null 프로퍼티들 만을 사용해야 하거나 하나의 <literal><list></literal>,
|
||||
<literal><map></literal>, <literal><bag></literal> 또는 <literal><idbag></literal>을
|
||||
선택해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
composite 요소에 대한 하나의 특별한 경우는 내포된 <literal><many-to-one></literal> 요소를 가진 composite 요소이다.
|
||||
이같은 매핑은 many-to-many 연관 테이블의 특별한 컬럼들을 composite 요소 클래스로 매핑시키는 것을 당신에게 허용해준다. 다음은
|
||||
<literal>Order</literal>로부터 <literal>Item</literal>으로의 many-to-many 연관이다. 여기서
|
||||
<literal>purchaseDate</literal>, <literal>price</literal>, 그리고 <literal>quantity</literal>는 연관의
|
||||
프로퍼티들이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
<composite-element class="eg.Purchase">
|
||||
<property name="purchaseDate"/>
|
||||
<property name="price"/>
|
||||
<property name="quantity"/>
|
||||
<many-to-one name="item" class="eg.Item"/>
|
||||
<!-- class attribute is optional -->
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
물론, 양방향 연관 네비게이션의 경우, 다른 측 상에 있는 purchase에 대한 참조가 존재할 수 없다. 컴포넌트들이 값(value) 타입들이고
|
||||
공유된 참조들을 허용하지 않음을 기억하라. 하나의 <literal>Purchase</literal>는<literal>Order</literal>를 가진 set
|
||||
내에 있을 수 있지만, 그것은 동시에 <literal>Item</literal>에 의해 참조될 수 없다.
|
||||
</para>
|
||||
|
||||
<para>심지어 세겹의(또는 네 겹의, 기타) 연관들이 가능하다:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
<composite-element class="eg.OrderLine">
|
||||
<many-to-one name="purchaseDetails class="eg.Purchase"/>
|
||||
<many-to-one name="item" class="eg.Item"/>
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
composite 요소들은 다른 엔티티들에 대한 연관들과 동일한 구문을 사용하여 질의들 내에 나타날 수도 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-asmapindex">
|
||||
<title>Map 인덱스들로서 컴포넌트들</title>
|
||||
|
||||
<para>
|
||||
<literal><composite-map-key></literal> 요소는 당신에게 하나의 컴포넌트 클래스를 하나의 <literal>Map</literal>의
|
||||
키로서 매핑시키도록 한다. 당신은 컴포넌트 클래스 상에서 <literal>hashCode()</literal>와 <literal>equals()</literal>를
|
||||
정확하게 오버라이드 시키도록 하라.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-compositeid" revision="1">
|
||||
<title>composite 식별자들로서 컴포넌트들</title>
|
||||
|
||||
<para>
|
||||
당신은 하나의 컴포넌트를 하나의 엔티티 클래스에 대한 하나의 식별자로서 사용할 수도 있다. 당신의 컴포넌트 클래스는 어떤 사양들을
|
||||
충족시켜야 한다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
그것은 <literal>java.io.Serializable</literal>을 구현해야 한다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
그것은 composite 키 등가(equality)에 대한 데이터베이스 개념과 일치되게, <literal>equals()</literal>와
|
||||
<literal>hashCode()</literal>를 다시 구현해야 한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>노트: Hibernate3에서, 두 번째 사양은 Hibernate의 절대적으로 엄격한 사양이 아니다.
|
||||
그러나 아무튼 그것을 행하라.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 compsite 키들을 생성시키는데 <literal>IdentifierGenerator</literal>를 사용할 수 없다. 대신에 어플리케이션은
|
||||
그것 자신의 식별자들을 할당해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
통상의 <literal><id></literal> 선언 위치에 (내포된 <literal><key-property></literal> 요소들을 가진)
|
||||
<literal><composite-id></literal> 태그를 사용하라. 예를 들어, <literal>OrderLine</literal> 클래스는
|
||||
<literal>Order</literal>의 (composite) 프라이머리 키에 의존하는 프라이머리 키를 갖는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
|
||||
<composite-id name="id" class="OrderLineId">
|
||||
<key-property name="lineId"/>
|
||||
<key-property name="orderId"/>
|
||||
<key-property name="customerId"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="name"/>
|
||||
|
||||
<many-to-one name="order" class="Order"
|
||||
insert="false" update="false">
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-one>
|
||||
....
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이제 <literal>OrderLine</literal> 테이블을 참조하는 임의의 foreign 키들이 또한 compsite이다. 당신은 다른 클래스들에 대한
|
||||
당신의 매핑들 속에 이것을 선언해야 한다. <literal>OrderLine</literal>에 대한 하나의 연관은 다음과 같이 매핑될 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
|
||||
<!-- the "class" attribute is optional, as usual -->
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-one>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal><column></literal> 태그가 모든 곳에서 <literal>column</literal> 속성에 대한 대안임을 노트하라.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>OrderLine</literal>에 대한 <literal>many-to-many</literal> 연관은 또한 composite foreign 키를 사용한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="undeliveredOrderLines">
|
||||
<key column name="warehouseId"/>
|
||||
<many-to-many class="OrderLine">
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-many>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Order</literal>에서 <literal>OrderLine</literal>들의 콜렉션이 사용될 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="orderLines" inverse="true">
|
||||
<key>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</key>
|
||||
<one-to-many class="OrderLine"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(통상적으로 <literal><one-to-many></literal> 요소는 컬럼들을 선언하지 않는다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 <literal>OrderLine</literal> 자체가 하나의 콜렉션을 소유할 경우, 그것은 또한 하나의 composite foreign 키를 갖는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
....
|
||||
....
|
||||
<list name="deliveryAttempts">
|
||||
<key> <!-- a collection inherits the composite key type -->
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</key>
|
||||
<list-index column="attemptId" base="1"/>
|
||||
<composite-element class="DeliveryAttempt">
|
||||
...
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-dynamic" revision="1">
|
||||
<title>동적인 컴포넌트들</title>
|
||||
|
||||
<para>
|
||||
당신은 <literal>Map</literal> 타입의 프로퍼티를 매핑시킬 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
||||
<property name="foo" column="FOO"/>
|
||||
<property name="bar" column="BAR"/>
|
||||
<many-to-one name="baz" class="Baz" column="BAZ_ID"/>
|
||||
</dynamic-component>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal><dynamic-component></literal> 매핑의 의미는 <literal><component></literal>와 동일하다.
|
||||
이런 종류의 매핑의 장점은 배치 시에 단지 매핑 문서를 편집함으로써 그 bean의 실제 프로퍼티들을 결정하는 가용성이다. 매핑 문서에
|
||||
대한 런타임 처리는 또한 DOM 파서를 사용하여 가능하다. 더 좋게는 당신이 <literal>Configuration</literal> 객체를 통해
|
||||
Hibernate의 구성-시 메타모형에 접근할 수 있다(그리고 변경시킬 수 있다)
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
1595
reference/ko/modules/configuration.xml
Normal file
219
reference/ko/modules/events.xml
Normal file
@ -0,0 +1,219 @@
|
||||
<chapter id="events">
|
||||
<title>인터셉터들과 이벤트들</title>
|
||||
|
||||
<para>
|
||||
어플리케이션이 Hibernate 내부에서 발생하는 어떤 이벤트들에 대해 반응하는 것에 흔히 유용하다. 이것은 어떤 종류의 일반적인 기능,
|
||||
그리고 Hibernate의 확장 기능의 구현을 허용해준다.
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-interceptors" revision="1">
|
||||
<title>인터셉터들</title>
|
||||
|
||||
<para>
|
||||
<literal>Interceptor</literal> 인터페이스는 영속 객체가 저장되고, 업데이트되고, 삭제되거나 로드되기 전에 영속 객체의
|
||||
프로퍼티들을 조사하고/하거나 처리하는 것을 어플리케이션에 허용해줌으로써 세션으로부터 어플리케이션으로의 콜백들을 제공한다.
|
||||
이것에 대한 한 가지 가능한 사용은 감사 정보를 추적하는 것이다. 예를 들어, 다음 <literal>Interceptor</literal>는
|
||||
<literal>Auditable</literal>이 생성될 때 <literal>createTimestamp</literal>를 자동적으로 설정하고
|
||||
<literal>Auditable</literal>이 업데이트될 때 <literal>lastUpdateTimestamp</literal> 프로퍼티를 업데이트 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package org.hibernate.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
public class AuditInterceptor implements Interceptor, Serializable {
|
||||
|
||||
private int updates;
|
||||
private int creates;
|
||||
|
||||
public void onDelete(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public boolean onFlushDirty(Object entity,
|
||||
Serializable id,
|
||||
Object[] currentState,
|
||||
Object[] previousState,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if ( entity instanceof Auditable ) {
|
||||
updates++;
|
||||
for ( int i=0; i < propertyNames.length; i++ ) {
|
||||
if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
|
||||
currentState[i] = new Date();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onLoad(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSave(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if ( entity instanceof Auditable ) {
|
||||
creates++;
|
||||
for ( int i=0; i<propertyNames.length; i++ ) {
|
||||
if ( "createTimestamp".equals( propertyNames[i] ) ) {
|
||||
state[i] = new Date();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void postFlush(Iterator entities) {
|
||||
System.out.println("Creations: " + creates + ", Updates: " + updates);
|
||||
}
|
||||
|
||||
public void preFlush(Iterator entities) {
|
||||
updates=0;
|
||||
creates=0;
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
세션이 생성될 때 인터셉터가 지정될 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 또한 <literal>Configuration</literal>을 사용하여 인터셉터를 전역 레벨 상에 설정할 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-events" revision="2">
|
||||
<title>이벤트 시스템</title>
|
||||
|
||||
<para>
|
||||
만일 당신이 당신의 영속 계층에서 특별한 이벤트들에 대해 반응해야 한다면, 당신은 또한 Hibernate3 <emphasis>이벤트</emphasis>
|
||||
아키텍처를 사용할 수도 있다. 이벤트 시스템은 부가물로 사용될 수 있거나 인터셉터들에 대한 대체물로 사용될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
본질적으로 <literal>Session</literal> 인터페이스의 모든 메소드들은 이벤트와 서로 관련되어 있다. 당신은 <literal>LoadEvent</literal>,
|
||||
<literal>FlushEvent</literal>, 등을 갖는다 (정의된 이벤트 타입들의 전체 리스트에 대해서는 XML 구성 파일 DTD 또는
|
||||
<literal>org.hibernate.event</literal> 패키지를 참조하라). 하나의 요청이 이들 메소드들 중 하나에 의해 만들어질 때,
|
||||
Hibernate <literal>Session</literal>은 적절한 이벤트를 생성시키고 그것을 그 타입에 대한 구성된 이벤트 리스너에게 전달한다.
|
||||
박싱없이, 이들 리스너들은 그들 메소드들이 항상 귀결되었던 동일한 프로세싱을 구현한다. 하지만 당신이 리스너 인터페이스들 중 하나의 맞춤을
|
||||
구현하는 것이 자유롭고(예를 들어 <literal>LoadEvent</literal>는 <literal>LoadEventListener</literal> 인터페이스의
|
||||
등록된 구현에 의해 처리된다), 그 경우에 그들 구현은 <literal>Session</literal>에 대해 행해진 임의의 <literal>load()</literal>
|
||||
요청들을 처리할 책임이 있을 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
리스너들은 효율적이게끔 싱글톤(singleton)들로 간주되어야 할 것이다; 이것은 그것들이 요청들 사이에서 공유되고, 따라서 임의의 상태를
|
||||
인스턴스 변수들로서 저장하지 말아야 함을 의미한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
맞춤형 리스너는 그것이 편의적인 기저 클래스들(또는 리스너들이 이 용도로 final이 아닌 것으로 선언되므로 Hibernate
|
||||
out-of-the-box에 의해 사용된 디폴트 이벤트 리스너들) 중 하나를 처리하고자 그리고/또는 확장하고자 원하는 이벤트들에 대해
|
||||
적절한 인터페이스를 구현해야 한다. 맞춤형 리스너들은 <literal>Configuration</literal> 객체를 통해 프로그램 상으로
|
||||
등록될 수 있거나, Hibernate 구성 XML 속에 지정될 수 있다 (properties 파일을 통한 선언적인 구성은 지원되지 않는다).
|
||||
다음은 맞춤형 load 이벤트 리스너에 대한 예제이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class MyLoadListener extends DefaultLoadEventListener {
|
||||
// this is the single method defined by the LoadEventListener interface
|
||||
public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
|
||||
throws HibernateException {
|
||||
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
|
||||
throw MySecurityException("Unauthorized access");
|
||||
}
|
||||
return super.onLoad(event, loadType);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 또한 디폴트 리스너 대신에 해당 리스너를 사용하도록 Hibernate에게 알려주는 구성 엔트리를 필요로 한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-configuration>
|
||||
<session-factory>
|
||||
...
|
||||
<listener type="load" class="MyLoadListener"/>
|
||||
</session-factory>
|
||||
</hibernate-configuration>]]></programlisting>
|
||||
|
||||
<para>
|
||||
대신에 당신은 그것을 프로그래밍 방식으로 등록할 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = new Configuration();
|
||||
cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );]]></programlisting>
|
||||
|
||||
<para>
|
||||
선언적으로 등록된 리스너들은 인스턴스들을 공유할 수 없다. 만일 동일한 클래스 이름이 여러 <literal><listener/></literal>
|
||||
요소들에서 사용될 경우, 각각의 참조는 그 클래스에 대한 별도의 인스턴스로 귀결될 것이다. 만일 당신이 리스너 타입들 사이에서 리스너 인스턴스들을
|
||||
공유할 가용성을 필요로 할 경우 당신은 프로그래밍 방식의 등록 접근법을 사용해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
컨피그레이션 동안에 왜 인터페이스를 구현하고 특정 타입을 지정하는가? 물론 리스너 구현은 여러 개의 이벤트 리스너 인터페이스들을
|
||||
구현할 수 있다. 등록 동안에 추가적으로 타입을 정의하는 것은 컨피그레이션 동안에 맞춤형 리스너들의 사용 여부를 전환시키는 것을
|
||||
더 쉽게 해준다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-decl-security">
|
||||
<title>Hibernate 선언적인 보안</title>
|
||||
<para>
|
||||
대개 Hibernate 어플리케이션들에서 선언적인 보안은 session facade 계층 내에서 관리된다. 이제, Hibernate3는 어떤 액션들이
|
||||
JACC를 통해 퍼미션을 주어지고, JAAS를 통해 인가되는 것을 허용해준다. 이것은 모든 아키텍처의 상단에 빌드된 옵션 기능이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
먼저, 당신은 JAAS authorization 사용을 이용 가능하도록 하기 위해 적절한 이벤트 리스터들을 구성해야 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
|
||||
<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
|
||||
<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
|
||||
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
다음으로, 여전히 <literal>hibernate.cfg.xml</literal> 내에서 퍼미션들을 role들에 바인드 시킨다 :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
|
||||
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
역할(role) 이름들은 당신의 JACC 프로바이더에 의해 인지된 역할(role)들이다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
652
reference/ko/modules/example_mappings.xml
Normal file
@ -0,0 +1,652 @@
|
||||
<chapter id="example-mappings">
|
||||
<title>예제: 여러 가지 매핑들</title>
|
||||
|
||||
<para>
|
||||
이 장은 몇몇 보다 복잡한 연관 매핑들을 보여준다.
|
||||
</para>
|
||||
|
||||
<sect1 id="example-mappings-emp">
|
||||
<title>Employer/Employee</title>
|
||||
|
||||
<para>
|
||||
<literal>Employer</literal>와 <literal>Employee</literal> 사이의 관계에 대한 다음 모형은 그 연관를 표현하는 데
|
||||
실제 엔티티 클래스(<literal>Employment</literal>)를 사용한다. 동일한 두 부분들에 대해 하나 이상의 채용 주기가 존재할 수 있기
|
||||
때문에 이것이 행해진다. 컴포넌트들이 화폐 값들과 종업원 이름들을 모형화 시키는데 사용된다.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
다음은 가능한 매핑 문서이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Employer" table="employers">
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employer_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
</class>
|
||||
|
||||
<class name="Employment" table="employment_periods">
|
||||
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employment_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="startDate" column="start_date"/>
|
||||
<property name="endDate" column="end_date"/>
|
||||
|
||||
<component name="hourlyRate" class="MonetaryAmount">
|
||||
<property name="amount">
|
||||
<column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
|
||||
</property>
|
||||
<property name="currency" length="12"/>
|
||||
</component>
|
||||
|
||||
<many-to-one name="employer" column="employer_id" not-null="true"/>
|
||||
<many-to-one name="employee" column="employee_id" not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Employee" table="employees">
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employee_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="taxfileNumber"/>
|
||||
<component name="name" class="Name">
|
||||
<property name="firstName"/>
|
||||
<property name="initial"/>
|
||||
<property name="lastName"/>
|
||||
</component>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
그리고 다음은 <literal>SchemaExport</literal>에 의해 생성된 테이블 스키마이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table employers (
|
||||
id BIGINT not null,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table employment_periods (
|
||||
id BIGINT not null,
|
||||
hourly_rate NUMERIC(12, 2),
|
||||
currency VARCHAR(12),
|
||||
employee_id BIGINT not null,
|
||||
employer_id BIGINT not null,
|
||||
end_date TIMESTAMP,
|
||||
start_date TIMESTAMP,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table employees (
|
||||
id BIGINT not null,
|
||||
firstName VARCHAR(255),
|
||||
initial CHAR(1),
|
||||
lastName VARCHAR(255),
|
||||
taxfileNumber VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table employment_periods
|
||||
add constraint employment_periodsFK0 foreign key (employer_id) references employers
|
||||
alter table employment_periods
|
||||
add constraint employment_periodsFK1 foreign key (employee_id) references employees
|
||||
create sequence employee_id_seq
|
||||
create sequence employment_id_seq
|
||||
create sequence employer_id_seq]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-mappings-authorwork">
|
||||
<title>Author/Work</title>
|
||||
|
||||
<para>
|
||||
<literal>Work</literal>, <literal>Author</literal> 그리고 <literal>Person</literal> 사이의 관계들에 대한
|
||||
다음 모형을 검토하자. 우리는 <literal>Work</literal>과 <literal>Author</literal> 사이의 관계를 many-to-many
|
||||
연관으로 표현한다. 우리는 <literal>Author</literal>와 <literal>Person</literal> 사이의 관계를 one-to-one
|
||||
연관으로 표현하고자 선택한다. 또 다른 가능성은 <literal>Author</literal>가 <literal>Person</literal>을 확장하도록
|
||||
하는 것일 것이다.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
다음 매핑 문서는 이들 관계들을 정확하게 표현한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Work" table="works" discriminator-value="W">
|
||||
|
||||
<id name="id" column="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="type" type="character"/>
|
||||
|
||||
<property name="title"/>
|
||||
<set name="authors" table="author_work">
|
||||
<key column name="work_id"/>
|
||||
<many-to-many class="Author" column name="author_id"/>
|
||||
</set>
|
||||
|
||||
<subclass name="Book" discriminator-value="B">
|
||||
<property name="text"/>
|
||||
</subclass>
|
||||
|
||||
<subclass name="Song" discriminator-value="S">
|
||||
<property name="tempo"/>
|
||||
<property name="genre"/>
|
||||
</subclass>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Author" table="authors">
|
||||
|
||||
<id name="id" column="id">
|
||||
<!-- The Author must have the same identifier as the Person -->
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="alias"/>
|
||||
<one-to-one name="person" constrained="true"/>
|
||||
|
||||
<set name="works" table="author_work" inverse="true">
|
||||
<key column="author_id"/>
|
||||
<many-to-many class="Work" column="work_id"/>
|
||||
</set>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Person" table="persons">
|
||||
<id name="id" column="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 매핑에는 네 개의 테이블들이 존재한다. <literal>works</literal>, <literal>authors</literal>와
|
||||
<literal>persons</literal>은 각각 작업 데이터, 저자 데이터, 개인 데이터를 보관한다. <literal>author_work</literal>는
|
||||
저자들을 작업들에 연결시키는 연관 테이블이다. 다음은 <literal>SchemaExport</literal>에 의해 생성된 테이블
|
||||
스키마이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table works (
|
||||
id BIGINT not null generated by default as identity,
|
||||
tempo FLOAT,
|
||||
genre VARCHAR(255),
|
||||
text INTEGER,
|
||||
title VARCHAR(255),
|
||||
type CHAR(1) not null,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table author_work (
|
||||
author_id BIGINT not null,
|
||||
work_id BIGINT not null,
|
||||
primary key (work_id, author_id)
|
||||
)
|
||||
|
||||
create table authors (
|
||||
id BIGINT not null generated by default as identity,
|
||||
alias VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table persons (
|
||||
id BIGINT not null generated by default as identity,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table authors
|
||||
add constraint authorsFK0 foreign key (id) references persons
|
||||
alter table author_work
|
||||
add constraint author_workFK0 foreign key (author_id) references authors
|
||||
alter table author_work
|
||||
add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-mappings-customerorderproduct">
|
||||
<title>Customer/Order/Product</title>
|
||||
|
||||
<para>
|
||||
이제 <literal>Customer</literal>, <literal>Order</literal>와 <literal>LineItem</literal>
|
||||
그리고 <literal>Product</literal> 사이의 관계들에 관한 모형을 검토하자. <literal>Customer</literal>와
|
||||
<literal>Order</literal> 사이의 one-to-many 연관이 존재하지만, 우리는 어떻게
|
||||
<literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>를
|
||||
표현할 것인가? 나는 <literal>Order</literal>와 <literal>Product</literal> 사이의 many-to-many
|
||||
연관를 나타내는 하나의 연관 클래스로서 <literal>LineItem</literal>을 매핑하기로 선택했다. Hibernate에서
|
||||
이것은 composite 요소로 명명된다.
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
매핑 문서:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Customer" table="customers">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
<set name="orders" inverse="true">
|
||||
<key column="customer_id"/>
|
||||
<one-to-many class="Order"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Order" table="orders">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="date"/>
|
||||
<many-to-one name="customer" column="customer_id"/>
|
||||
<list name="lineItems" table="line_items">
|
||||
<key column="order_id"/>
|
||||
<list-index column="line_number"/>
|
||||
<composite-element class="LineItem">
|
||||
<property name="quantity"/>
|
||||
<many-to-one name="product" column="product_id"/>
|
||||
</composite-element>
|
||||
</list>
|
||||
</class>
|
||||
|
||||
<class name="Product" table="products">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="serialNumber"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> 그리고
|
||||
<literal>products</literal>는 각각 고객 데이터, 주문 데이터, 주문 라인 아이템 데이터, 그리고 제품 데이터를
|
||||
보관한다. <literal>line_items</literal>는 또한 주문들을 제품들과 연결시키는 연관 테이블로서 동작한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table customers (
|
||||
id BIGINT not null generated by default as identity,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table orders (
|
||||
id BIGINT not null generated by default as identity,
|
||||
customer_id BIGINT,
|
||||
date TIMESTAMP,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table line_items (
|
||||
line_number INTEGER not null,
|
||||
order_id BIGINT not null,
|
||||
product_id BIGINT,
|
||||
quantity INTEGER,
|
||||
primary key (order_id, line_number)
|
||||
)
|
||||
|
||||
create table products (
|
||||
id BIGINT not null generated by default as identity,
|
||||
serialNumber VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table orders
|
||||
add constraint ordersFK0 foreign key (customer_id) references customers
|
||||
alter table line_items
|
||||
add constraint line_itemsFK0 foreign key (product_id) references products
|
||||
alter table line_items
|
||||
add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="misc">
|
||||
<title>기타 예제 매핑들</title>
|
||||
|
||||
<para>
|
||||
이들 예제들은 모두 Hiberante test suite로부터 취했다. 당신은 거기서 많은
|
||||
다른 유용한 예제 매핑들을 발견할 것이다. Hibernate 배포본의 <literal>test</literal>
|
||||
폴더를 살펴보라.
|
||||
</para>
|
||||
|
||||
<para>TODO: 이 내용을 둘러싼 말들을 집어넣을 것.</para>
|
||||
|
||||
<sect2 id="example-mappings-typed-onetone">
|
||||
<title>"형식화된(Typed)" one-to-one 연관</title>
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="name"/>
|
||||
<one-to-one name="address"
|
||||
cascade="all">
|
||||
<formula>name</formula>
|
||||
<formula>'HOME'</formula>
|
||||
</one-to-one>
|
||||
<one-to-one name="mailingAddress"
|
||||
cascade="all">
|
||||
<formula>name</formula>
|
||||
<formula>'MAILING'</formula>
|
||||
</one-to-one>
|
||||
</class>
|
||||
|
||||
<class name="Address" batch-size="2"
|
||||
check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
|
||||
<composite-id>
|
||||
<key-many-to-one name="person"
|
||||
column="personName"/>
|
||||
<key-property name="type"
|
||||
column="addressType"/>
|
||||
</composite-id>
|
||||
<property name="street" type="text"/>
|
||||
<property name="state"/>
|
||||
<property name="zip"/>
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key">
|
||||
<title>Composite 키 예제</title>
|
||||
<programlisting><![CDATA[<class name="Customer">
|
||||
|
||||
<id name="customerId"
|
||||
length="10">
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="name" not-null="true" length="100"/>
|
||||
<property name="address" not-null="true" length="200"/>
|
||||
|
||||
<list name="orders"
|
||||
inverse="true"
|
||||
cascade="save-update">
|
||||
<key column="customerId"/>
|
||||
<index column="orderNumber"/>
|
||||
<one-to-many class="Order"/>
|
||||
</list>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Order" table="CustomerOrder" lazy="true">
|
||||
<synchronize table="LineItem"/>
|
||||
<synchronize table="Product"/>
|
||||
|
||||
<composite-id name="id"
|
||||
class="Order$Id">
|
||||
<key-property name="customerId" length="10"/>
|
||||
<key-property name="orderNumber"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="orderDate"
|
||||
type="calendar_date"
|
||||
not-null="true"/>
|
||||
|
||||
<property name="total">
|
||||
<formula>
|
||||
( select sum(li.quantity*p.price)
|
||||
from LineItem li, Product p
|
||||
where li.productId = p.productId
|
||||
and li.customerId = customerId
|
||||
and li.orderNumber = orderNumber )
|
||||
</formula>
|
||||
</property>
|
||||
|
||||
<many-to-one name="customer"
|
||||
column="customerId"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true"/>
|
||||
|
||||
<bag name="lineItems"
|
||||
fetch="join"
|
||||
inverse="true"
|
||||
cascade="save-update">
|
||||
<key>
|
||||
<column name="customerId"/>
|
||||
<column name="orderNumber"/>
|
||||
</key>
|
||||
<one-to-many class="LineItem"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="LineItem">
|
||||
|
||||
<composite-id name="id"
|
||||
class="LineItem$Id">
|
||||
<key-property name="customerId" length="10"/>
|
||||
<key-property name="orderNumber"/>
|
||||
<key-property name="productId" length="10"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="quantity"/>
|
||||
|
||||
<many-to-one name="order"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true">
|
||||
<column name="customerId"/>
|
||||
<column name="orderNumber"/>
|
||||
</many-to-one>
|
||||
|
||||
<many-to-one name="product"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true"
|
||||
column="productId"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Product">
|
||||
<synchronize table="LineItem"/>
|
||||
|
||||
<id name="productId"
|
||||
length="10">
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="description"
|
||||
not-null="true"
|
||||
length="200"/>
|
||||
<property name="price" length="3"/>
|
||||
<property name="numberAvailable"/>
|
||||
|
||||
<property name="numberOrdered">
|
||||
<formula>
|
||||
( select sum(li.quantity)
|
||||
from LineItem li
|
||||
where li.productId = productId )
|
||||
</formula>
|
||||
</property>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key-manytomany">
|
||||
<title>공유된 합성 키 속성을 가진 Many-to-many</title>
|
||||
<programlisting><![CDATA[<class name="User" table="`User`">
|
||||
<composite-id>
|
||||
<key-property name="name"/>
|
||||
<key-property name="org"/>
|
||||
</composite-id>
|
||||
<set name="groups" table="UserGroup">
|
||||
<key>
|
||||
<column name="userName"/>
|
||||
<column name="org"/>
|
||||
</key>
|
||||
<many-to-many class="Group">
|
||||
<column name="groupName"/>
|
||||
<formula>org</formula>
|
||||
</many-to-many>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Group" table="`Group`">
|
||||
<composite-id>
|
||||
<key-property name="name"/>
|
||||
<key-property name="org"/>
|
||||
</composite-id>
|
||||
<property name="description"/>
|
||||
<set name="users" table="UserGroup" inverse="true">
|
||||
<key>
|
||||
<column name="groupName"/>
|
||||
<column name="org"/>
|
||||
</key>
|
||||
<many-to-many class="User">
|
||||
<column name="userName"/>
|
||||
<formula>org</formula>
|
||||
</many-to-many>
|
||||
</set>
|
||||
</class>
|
||||
]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-content-discrimination">
|
||||
<title>내용 기반 판별</title>
|
||||
<programlisting><![CDATA[<class name="Person"
|
||||
discriminator-value="P">
|
||||
|
||||
<id name="id"
|
||||
column="person_id"
|
||||
unsaved-value="0">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
|
||||
<discriminator
|
||||
type="character">
|
||||
<formula>
|
||||
case
|
||||
when title is not null then 'E'
|
||||
when salesperson is not null then 'C'
|
||||
else 'P'
|
||||
end
|
||||
</formula>
|
||||
</discriminator>
|
||||
|
||||
<property name="name"
|
||||
not-null="true"
|
||||
length="80"/>
|
||||
|
||||
<property name="sex"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
|
||||
<component name="address">
|
||||
<property name="address"/>
|
||||
<property name="zip"/>
|
||||
<property name="country"/>
|
||||
</component>
|
||||
|
||||
<subclass name="Employee"
|
||||
discriminator-value="E">
|
||||
<property name="title"
|
||||
length="20"/>
|
||||
<property name="salary"/>
|
||||
<many-to-one name="manager"/>
|
||||
</subclass>
|
||||
|
||||
<subclass name="Customer"
|
||||
discriminator-value="C">
|
||||
<property name="comments"/>
|
||||
<many-to-one name="salesperson"/>
|
||||
</subclass>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-association-alternatekeys" >
|
||||
<title>대체 키들에 대한 연관들</title>
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
||||
<id name="id">
|
||||
<generator class="hilo"/>
|
||||
</id>
|
||||
|
||||
<property name="name" length="100"/>
|
||||
|
||||
<one-to-one name="address"
|
||||
property-ref="person"
|
||||
cascade="all"
|
||||
fetch="join"/>
|
||||
|
||||
<set name="accounts"
|
||||
inverse="true">
|
||||
<key column="userId"
|
||||
property-ref="userId"/>
|
||||
<one-to-many class="Account"/>
|
||||
</set>
|
||||
|
||||
<property name="userId" length="8"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
|
||||
<id name="id">
|
||||
<generator class="hilo"/>
|
||||
</id>
|
||||
|
||||
<property name="address" length="300"/>
|
||||
<property name="zip" length="5"/>
|
||||
<property name="country" length="25"/>
|
||||
<many-to-one name="person" unique="true" not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Account">
|
||||
<id name="accountId" length="32">
|
||||
<generator class="uuid.hex"/>
|
||||
</id>
|
||||
|
||||
<many-to-one name="user"
|
||||
column="userId"
|
||||
property-ref="userId"/>
|
||||
|
||||
<property name="type" not-null="true"/>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
343
reference/ko/modules/example_parentchild.xml
Normal file
@ -0,0 +1,343 @@
|
||||
<chapter id="example-parentchild">
|
||||
<title>예제: 부모/자식</title>
|
||||
|
||||
<para>
|
||||
새로운 사용자들이 Hibernate로 행하고자 시도하는 바로 첫 번째 것들 중 하나는 부모/자식 타입의 관계를 모형화 시키는 것이다. 이것에 대한
|
||||
두 가지 다른 접근법들이 존재한다. 여러가지 이유들로 인해 특히 새로운 사용자들에게 가장 편한 접근법은 <literal>Parent</literal>로부터
|
||||
<literal>Child</literal>로의 <literal><one-to-many></literal> 연관을 가진 엔티티 클래스들로서 <literal>Parent</literal>와
|
||||
<literal>Child</literal> 양자를 모형화 시키는 것이다. (다른 접근법은 <literal>Child</literal>를
|
||||
<literal><composite-element></literal>로 선언하는 것이다.) 이제, (Hibernate에서) one to many 연관에 대한 디폴트
|
||||
의미는 composite 요소 매핑의 의미보다 부모/자식 관계의 통상적인 의미에 훨씬 덜 가깝다는 것이 판명된다. 우리는 부모/자식 관계를 효율적이고
|
||||
강력하게 모형화 시키기 위해 <emphasis>케스케이드들을 가진 양방향 one to many 연관</emphasis>을 사용하는 방법을 설명할 것이다.
|
||||
그것은 전혀 어렵지 않다!
|
||||
</para>
|
||||
|
||||
<sect1 id="example-parentchild-collections">
|
||||
<title>콜렉션들에 관한 노트</title>
|
||||
|
||||
<para>
|
||||
Hibernate 콜렉션들은 그것들의 소유하고 있는 엔티티의 논리적 부분으로 간주된다; 결코 포함된 엔티티들의 부분이 아니다. 이것은
|
||||
중대한 구분점이다! 그것은 다음은 다음 결과들을 갖는다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
콜렉션으로부터 객체를 제거하고/콜렉션에 객체를 추가 시킬 때, 콜렉션 소유자의 버전 번호가 증가된다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
만일 콜렉션으로부터 제거되었던 객체가 하나의 값 타입의 인스턴스(예를 들어 composite 요소)이면, 그 객체는 영속상태를 끝내고
|
||||
그것의 상태가 데이터베이스로부터 완전히 제거될 것이다. 마찬가지로 하나의 값 타입의 인스턴스를 콜렉션에 추가시키는 것은 그것의
|
||||
상태가 즉시 영속화 되도록 강제시킬 것이다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
반면에, 만일 엔티티가 콜렉션으로부터 제거될 경우(one-to-many 또는 many-to-many 연관), 그것은 디폴트로 삭제되지 않을
|
||||
것이다. 이 특징은 완전하게 일관적이다 - 다른 엔티티의 내부 상태에 대한 변경은 연관된 엔티티를 사라지도록 강제하지 않을 것이다!
|
||||
마찬가지로 콜렉션에 엔티티를 추가시키는 것은 디폴트로 그 엔티티가 영속화 되도록 강제시키지 않는다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
대신에 콜렉션으로의 엔티티 추가가 두 엔티티들 사이에 단지 하나의 링크를 생성시키는 반면에, 그것을 제거하는 것은 링크를 제거한다는 점이
|
||||
디폴트 특징이다. 이것은 모든 종류의 경우들에 대해 매우 적절하다. 그것이 전혀 적절하지 않은 곳은 부모/자식 관계인 경우이고, 여기서
|
||||
자식의 생애는 부모의 생명주기에 묶여져 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-bidir">
|
||||
<title>양방향 one-to-many</title>
|
||||
|
||||
<para>
|
||||
<literal>Parent</literal>로부터 <literal>Child</literal>로의 간단한 <literal><one-to-many></literal>
|
||||
연관관계로 시작한다고 가정하자.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
우리가 다음 코드를 실행시켰다면
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = .....;
|
||||
Child c = new Child();
|
||||
p.getChildren().add(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate는 두 개의 SQL 문장들을 실행할 것이다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>c</literal>에 대한 레코드를 생성시키는 <literal>INSERT</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>p</literal>로부터 <literal>c</literal>로의 링크를 생성시키는 <literal>UPDATE</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
이것은 비효율적일 뿐만 아니라, 또한 <literal>parent_id</literal> 컬럼 상의 임의의 <literal>NOT NULL</literal>
|
||||
컨스트레인트에 위배된다. 우리는 콜렉션 매핑에서 <literal>not-null="true"</literal>를 지정함으로써 null 허용 가능
|
||||
컨스트레인트 위반을 정정할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children">
|
||||
<key column="parent_id" not-null="true"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
하지만 이것은 권장되는 해결책이 아니다.
|
||||
</para>
|
||||
<para>
|
||||
이 행위의 기본 원인은 <literal>p</literal>로부터 <literal>c</literal>로의 링크(foreign key <literal>parent_id</literal>)가
|
||||
<literal>Child</literal> 객체의 상태의 부분으로 간주되지 않고 그러므로 <literal>INSERT</literal>로 생성되지 않는다는
|
||||
점이다. 따라서 해결책은 <literal>Child</literal> 매핑의 링크 부분을 만드는 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(우리는 또한 <literal>parent</literal> 프로퍼티를 <literal>Child</literal> 클래스에 추가시킬 필요가 있다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이제 <literal>Child</literal> 엔티티가 링크의 상태를 관리한다는 점을 노트하고, 우리는 링크를 업데이트 시키지 말도록 콜렉션에게
|
||||
통보한다. 우리는 <literal>inverse</literal> 속성을 사용한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
다음 코드는 새로운 <literal>Child</literal>를 추가시키는데 사용될 것이다
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
c.setParent(p);
|
||||
p.getChildren().add(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
그리고 이제, 유일하게 한 개의 SQL <literal>INSERT</literal>가 실행될 것이다!
|
||||
</para>
|
||||
|
||||
<para>
|
||||
약간 거칠게, 우리는 <literal>Parent</literal>의 <literal>addChild()</literal> 메소드를 생성시킬 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public void addChild(Child c) {
|
||||
c.setParent(this);
|
||||
children.add(c);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
이제, <literal>Child</literal>를 추가하는 코드는 다음과 같다
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
p.addChild(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-cascades">
|
||||
<title>케스케이딩 생명주기</title>
|
||||
|
||||
<para>
|
||||
<literal>save()</literal>에 대한 명시적인 호출은 여전히 성가시다. 우리는 케스케이딩을 사용하여 이것을 얘기할 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
다음은 위의 코드를 단순화 시킨다
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
p.addChild(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
유사하게, 우리는 <literal>Parent</literal>를 저장하거나 삭제할 때 자식들에 대해 반복하는 것을 필요로 하지 않는다. 다음은
|
||||
데이터베이스로부터 <literal>p</literal>와 모든 그것의 자식들을 제거시킨다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
session.delete(p);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
하지만, 다음 코드
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = (Child) p.getChildren().iterator().next();
|
||||
p.getChildren().remove(c);
|
||||
c.setParent(null);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
는 데이터베이스로부터 <literal>c</literal>를 제거하지 않을 것이다; 그것은 오직 <literal>p</literal>에 대한 링크만을 제거할
|
||||
것이다(그리고 이 경우에 <literal>NOT NULL</literal> 컨스트레인트 위반을 일으킬 것이다 ). 당신은 명시적으로
|
||||
<literal>Child</literal>를 <literal>delete()</literal> 시킬 필요가 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = (Child) p.getChildren().iterator().next();
|
||||
p.getChildren().remove(c);
|
||||
session.delete(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
이제 우리의 경우에 <literal>Child</literal>는 그것의 부모 없이는 진정으로 존재할 수 없다. 따라서 만일 우리가 콜렉션으로부터
|
||||
하나의 <literal>Child</literal>를 제거할 경우, 우리는 그것이 정말로 삭제되기를 원한다. 이를 위해 우리는
|
||||
<literal>cascade="all-delete-orphan"</literal>을 사용해야 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
노트: 비록 콜렉션 매핑이 <literal>inverse="true"</literal>를 지정할 지라도, 케스케이드들은 여전히 콜렉션 요소들을
|
||||
반복함으로써 처리된다. 따라서 객체가 케스케이드에 의해 저장되고, 삭제되거나 업데이트 되는 것을 당신이 필요로 할 경우, 당신은
|
||||
그것을 그 콜렉션에 추가해야 한다. 단순히 <literal>setParent()</literal>를 호출하는 것으로는 충분하지 않다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-update">
|
||||
<title>케스케이드들과 <literal>unsaved-value</literal></title>
|
||||
|
||||
<para>
|
||||
우리가 하나의 <literal>Session</literal> 속에 <literal>Parent</literal>를 로드시켰고 UI 액션에서 어떤 변경들을 행했고,
|
||||
<literal>update()</literal>를 호출하여 새로운 세션에서 이들 변경들을 영속화 시키는 것을 원한다고 가정하자. <literal>Parent</literal>는
|
||||
자식들을 가진 콜렉션을 포함할 것이고, 케스케이딩 업데이트가 사용 가능하기 때문에, Hibernate는 어느 자식들이 새로이 초기화 되는지
|
||||
그리고 어느 것이 데이터베이스에서 현재 행들을 표현하는지를 알 필요가 있다. <literal>Parent</literal>와 <literal>Child</literal>
|
||||
모두 <literal>Long</literal> 타입의 식별자 프로퍼티들을 생성시켰다고 가정하자. Hibernate는 어느 자식들이 새로운 것인지를
|
||||
결정하는데 식별자와 version/timestamp 프로퍼티 값을 사용할 것이다.(<xref linkend="objectstate-saveorupdate"/>을 보라.)
|
||||
<emphasis>Hibernate3에서는<literal>unsaved-value</literal>를 더이상 명시적으로 지정할 필요가 없다.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다음 코드는 <literal>parent</literal>와 <literal>child</literal>를 업데이트하고 <literal>newChild</literal>를
|
||||
삽입시킬 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[//parent and child were both loaded in a previous session
|
||||
parent.addChild(child);
|
||||
Child newChild = new Child();
|
||||
parent.addChild(newChild);
|
||||
session.update(parent);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
물론 그것은 생성되는 식별자의 경우에는 모두 매우 좋지만, 할당되는 식별자들과 composite 식별자들에 대해서는 어떠한가? 이것은 보다
|
||||
어렵다. 왜냐하면 Hibernate는 (사용자에 의해 할당된 식별자를 가진) 새로이 초기화 된 객체와 이전 세션에서 로드되었던 객체 사이를
|
||||
구별짓는데 식별자 프로퍼티를 사용할 수 없기 때문이다. 이 경우에, Hibernate는 timestamp 프로퍼티 또는 version 프로퍼티를
|
||||
사용하거나 실제로 second-level 캐시를 질의하거나 가장 나쁜 경우에는 행이 존재하는지를 알기 위해 데이터베이스를 질의할 것이다.
|
||||
</para>
|
||||
|
||||
<!-- undocumenting
|
||||
<para>
|
||||
There is one further possibility. The <literal>Interceptor</literal> method named
|
||||
<literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
|
||||
newly instantiated objects. For example, you could define a base class for your persistent classes.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Persistent {
|
||||
private boolean _saved = false;
|
||||
public void onSave() {
|
||||
_saved=true;
|
||||
}
|
||||
public void onLoad() {
|
||||
_saved=true;
|
||||
}
|
||||
......
|
||||
public boolean isSaved() {
|
||||
return _saved;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
(The <literal>saved</literal> property is non-persistent.)
|
||||
Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
|
||||
and <literal>onSave()</literal> as follows.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
|
||||
if (entity instanceof Persistent) {
|
||||
return new Boolean( !( (Persistent) entity ).isSaved() );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onLoad(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSave(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
|
||||
return false;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
|
||||
</para>
|
||||
-->
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-conclusion">
|
||||
<title>결론</title>
|
||||
|
||||
<para>
|
||||
여기에 숙지할 것이 약간 있고 그것은 처음에는 혼동스러운 것처럼 보일 수 있다. 하지만 실제로 그것은 모두 매우 좋게 동작한다. 대부분의
|
||||
Hibernate 어플리케이션들은 많은 장소들에서 부모/자식 패턴을 사용한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 첫 번째 단락에서 대안을 언급했다. 위의 쟁점들 중 어느 것도 정확하게 부모/자식 관계의 의미를 가진,
|
||||
<literal><composite-element></literal> 매핑들의 경우에는 존재하지 않는다. 불행히도, composite 요소 클래스들에
|
||||
대한 두 개의 커다란 제약들이 존재한다: composite 요소들은 콜렉션들을 소유하지 않고, 그것들은 유일한 부모가 아닌 다른 어떤
|
||||
엔티티의 자식일 수는 없다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
428
reference/ko/modules/example_weblog.xml
Normal file
@ -0,0 +1,428 @@
|
||||
<chapter id="example-weblog">
|
||||
<title>예제: Weblog 어플리케이션</title>
|
||||
|
||||
<sect1 id="example-weblog-classes">
|
||||
<title>영속 클래스들</title>
|
||||
|
||||
<para>
|
||||
영속 클래스들은 웹로그, 그리고 웹 로그 내에 게시된 항목을 표현한다.그것들은
|
||||
표준 부모/자식 관계로 모형화 될 것이지만, 우리는 set 대신에 순서지워진 bag를 사용할 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Blog {
|
||||
private Long _id;
|
||||
private String _name;
|
||||
private List _items;
|
||||
|
||||
public Long getId() {
|
||||
return _id;
|
||||
}
|
||||
public List getItems() {
|
||||
return _items;
|
||||
}
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
public void setId(Long long1) {
|
||||
_id = long1;
|
||||
}
|
||||
public void setItems(List list) {
|
||||
_items = list;
|
||||
}
|
||||
public void setName(String string) {
|
||||
_name = string;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class BlogItem {
|
||||
private Long _id;
|
||||
private Calendar _datetime;
|
||||
private String _text;
|
||||
private String _title;
|
||||
private Blog _blog;
|
||||
|
||||
public Blog getBlog() {
|
||||
return _blog;
|
||||
}
|
||||
public Calendar getDatetime() {
|
||||
return _datetime;
|
||||
}
|
||||
public Long getId() {
|
||||
return _id;
|
||||
}
|
||||
public String getText() {
|
||||
return _text;
|
||||
}
|
||||
public String getTitle() {
|
||||
return _title;
|
||||
}
|
||||
public void setBlog(Blog blog) {
|
||||
_blog = blog;
|
||||
}
|
||||
public void setDatetime(Calendar calendar) {
|
||||
_datetime = calendar;
|
||||
}
|
||||
public void setId(Long long1) {
|
||||
_id = long1;
|
||||
}
|
||||
public void setText(String string) {
|
||||
_text = string;
|
||||
}
|
||||
public void setTitle(String string) {
|
||||
_title = string;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-weblog-mappings">
|
||||
<title>Hibernate 매핑들</title>
|
||||
|
||||
<para>
|
||||
XML 매핑들은 이제 매우 간단해질 것이다.
|
||||
</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">
|
||||
|
||||
<hibernate-mapping package="eg">
|
||||
|
||||
<class
|
||||
name="Blog"
|
||||
table="BLOGS">
|
||||
|
||||
<id
|
||||
name="id"
|
||||
column="BLOG_ID">
|
||||
|
||||
<generator class="native"/>
|
||||
|
||||
</id>
|
||||
|
||||
<property
|
||||
name="name"
|
||||
column="NAME"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
|
||||
<bag
|
||||
name="items"
|
||||
inverse="true"
|
||||
order-by="DATE_TIME"
|
||||
cascade="all">
|
||||
|
||||
<key column="BLOG_ID"/>
|
||||
<one-to-many class="BlogItem"/>
|
||||
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<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">
|
||||
|
||||
<hibernate-mapping package="eg">
|
||||
|
||||
<class
|
||||
name="BlogItem"
|
||||
table="BLOG_ITEMS"
|
||||
dynamic-update="true">
|
||||
|
||||
<id
|
||||
name="id"
|
||||
column="BLOG_ITEM_ID">
|
||||
|
||||
<generator class="native"/>
|
||||
|
||||
</id>
|
||||
|
||||
<property
|
||||
name="title"
|
||||
column="TITLE"
|
||||
not-null="true"/>
|
||||
|
||||
<property
|
||||
name="text"
|
||||
column="TEXT"
|
||||
not-null="true"/>
|
||||
|
||||
<property
|
||||
name="datetime"
|
||||
column="DATE_TIME"
|
||||
not-null="true"/>
|
||||
|
||||
<many-to-one
|
||||
name="blog"
|
||||
column="BLOG_ID"
|
||||
not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-weblog-code">
|
||||
<title>Hibernate 코드</title>
|
||||
|
||||
<para>
|
||||
다음 클래스는 우리가 Hibernate를 사용하여 이들 클래스들로 행할 수 있는 몇몇 종류의 것들을 설명한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
|
||||
public class BlogMain {
|
||||
|
||||
private SessionFactory _sessions;
|
||||
|
||||
public void configure() throws HibernateException {
|
||||
_sessions = new Configuration()
|
||||
.addClass(Blog.class)
|
||||
.addClass(BlogItem.class)
|
||||
.buildSessionFactory();
|
||||
}
|
||||
|
||||
public void exportTables() throws HibernateException {
|
||||
Configuration cfg = new Configuration()
|
||||
.addClass(Blog.class)
|
||||
.addClass(BlogItem.class);
|
||||
new SchemaExport(cfg).create(true, true);
|
||||
}
|
||||
|
||||
public Blog createBlog(String name) throws HibernateException {
|
||||
|
||||
Blog blog = new Blog();
|
||||
blog.setName(name);
|
||||
blog.setItems( new ArrayList() );
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.persist(blog);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return blog;
|
||||
}
|
||||
|
||||
public BlogItem createBlogItem(Blog blog, String title, String text)
|
||||
throws HibernateException {
|
||||
|
||||
BlogItem item = new BlogItem();
|
||||
item.setTitle(title);
|
||||
item.setText(text);
|
||||
item.setBlog(blog);
|
||||
item.setDatetime( Calendar.getInstance() );
|
||||
blog.getItems().add(item);
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.update(blog);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public BlogItem createBlogItem(Long blogid, String title, String text)
|
||||
throws HibernateException {
|
||||
|
||||
BlogItem item = new BlogItem();
|
||||
item.setTitle(title);
|
||||
item.setText(text);
|
||||
item.setDatetime( Calendar.getInstance() );
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Blog blog = (Blog) session.load(Blog.class, blogid);
|
||||
item.setBlog(blog);
|
||||
blog.getItems().add(item);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public void updateBlogItem(BlogItem item, String text)
|
||||
throws HibernateException {
|
||||
|
||||
item.setText(text);
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.update(item);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBlogItem(Long itemid, String text)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
|
||||
item.setText(text);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public List listAllBlogNamesAndItemCounts(int max)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
List result = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"select blog.id, blog.name, count(blogItem) " +
|
||||
"from Blog as blog " +
|
||||
"left outer join blog.items as blogItem " +
|
||||
"group by blog.name, blog.id " +
|
||||
"order by max(blogItem.datetime)"
|
||||
);
|
||||
q.setMaxResults(max);
|
||||
result = q.list();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Blog getBlogAndAllItems(Long blogid)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
Blog blog = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"from Blog as blog " +
|
||||
"left outer join fetch blog.items " +
|
||||
"where blog.id = :blogid"
|
||||
);
|
||||
q.setParameter("blogid", blogid);
|
||||
blog = (Blog) q.uniqueResult();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return blog;
|
||||
}
|
||||
|
||||
public List listBlogsAndRecentItems() throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
List result = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"from Blog as blog " +
|
||||
"inner join blog.items as blogItem " +
|
||||
"where blogItem.datetime > :minDate"
|
||||
);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.roll(Calendar.MONTH, false);
|
||||
q.setCalendar("minDate", cal);
|
||||
|
||||
result = q.list();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
123
reference/ko/modules/filters.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<chapter id="filters">
|
||||
<title>데이터 필터링하기</title>
|
||||
|
||||
<para>
|
||||
Hibernate3은 혁신적인 "가시성(visibility)" 규칙들로서 데이터를 처리하는 새로운 접근법을 제공한다. <emphasis>Hibernate
|
||||
필터</emphasis>는 특정 Hibernate 세션에 대해 이용 가능하게 되거나 이용 불가능하게 될 수도 있는 전역, 명명된 파라미터화 된 필터이다.
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-filters">
|
||||
<title>Hibernate 필터들</title>
|
||||
|
||||
<para>
|
||||
Hibernate3은 필터 기준(criteria)을 미리 정의하고 클래스 레벨과 콜렉션 레벨 양자에서 그들 필터들을 첨부할 능력을 추가시킨다.
|
||||
필터 기준(criteria)은 클래스 요소와 다양한 콜렉션 요소들에 대해 이용 가능한 기존의 "where" 속성과 매우 유사한 하나의 제한 절을
|
||||
정의하는 능력이다. 이것들을 제외하면 필터 조건들은 파라미터화 될 수 있다. 그때 어플리케이션은 주어진 필터들이 이용 가능한지 여부
|
||||
그리고 그들 파라미터 값들이 무엇이어야 하는지를 실행 시에 결정할 수 있다. 필터들은 데이터베이스 뷰들 처럼 사용될 수 있지만,
|
||||
어플리케이션 내부에 파라미터화 된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
필터들을 사용하기 위해서, 그것들은 먼저 정의되고 나서 적절한 매핑 요소들에 첨가되어야 한다. 필터를 정의하기 위해,
|
||||
<literal><hibernate-mapping/></literal> 요소 내부에 <literal><filter-def/></literal> 요소를
|
||||
사용하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="myFilter">
|
||||
<filter-param name="myFilterParam" type="string"/>
|
||||
</filter-def>]]></programlisting>
|
||||
|
||||
<para>
|
||||
그때 이 필터는 클래스에 첨가될 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="myClass" ...>
|
||||
...
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
또는 콜렉션에 첨가될 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set ...>
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
또는 동시에 양자에(또는 각각의 여러번) 첨가될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal> 상의 메소드들은 다음과 같다: <literal>enableFilter(String filterName)</literal>,
|
||||
<literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal>.
|
||||
디폴트로, 필터들은 주어진 세션에 대해 이용 가능하지 <emphasis>않다</emphasis>; 그것들은 <literal>Session.enabledFilter()</literal>
|
||||
메소드의 사용을 통해 명시적으로 이용 가능하게 되어야 한다. <literal>Session.enabledFilter()</literal>는
|
||||
<literal>Filter</literal> 인터페이스의 인스턴스를 반환한다. 위에 정의된 간단한 필터를 사용하면, 이것은 다음과 같을 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
|
||||
|
||||
<para>
|
||||
org.hibernate.Filter 인터페이스 상의 메소드들은 Hibernate에 매우 공통된 method-chaining을 허용한다는 점을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
유효한 기록 날짜 패턴을 가진 시간 데이터를 사용하는 전체 예제 :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="effectiveDate">
|
||||
<filter-param name="asOfDate" type="date"/>
|
||||
</filter-def>
|
||||
|
||||
<class name="Employee" ...>
|
||||
...
|
||||
<many-to-one name="department" column="dept_id" class="Department"/>
|
||||
<property name="effectiveStartDate" type="date" column="eff_start_dt"/>
|
||||
<property name="effectiveEndDate" type="date" column="eff_end_dt"/>
|
||||
...
|
||||
<!--
|
||||
Note that this assumes non-terminal records have an eff_end_dt set to
|
||||
a max db date for simplicity-sake
|
||||
-->
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</class>
|
||||
|
||||
<class name="Department" ...>
|
||||
...
|
||||
<set name="employees" lazy="true">
|
||||
<key column="dept_id"/>
|
||||
<one-to-many class="Employee"/>
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
그때 당신이 현재 유효한 레코드들을 항상 얻는 것을 확실히 하기 위해, employee 데이터를 검색하기 전에 세션 상에 필터를
|
||||
간단하게 이용 가능하게 하라:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = ...;
|
||||
session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
|
||||
List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
|
||||
.setLong("targetSalary", new Long(1000000))
|
||||
.list();
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
위의 HQL 에서, 심지어 비록 우리가 결과들에 대한 봉급 컨스트레인트를 명시적으로 언급만 했을지라도, 이용 가능한 필터 때문에
|
||||
그 질의는 봉급이 백만달러 이상인 현재 채용중인 직원들만을 반환할 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
노트: 만일 당신이 outer 조인에 대해 필터들을 사용할 계획이라면 (HQL이든 로드 페칭이든) 조건 표현식의 방향을 주의하라.
|
||||
이것을 left outer join으로 설정하는 것이 가장 안전하다; 일반적으로 오퍼레이터 뒤에 있는 컬럼 이름(들)이 뒤따르는 첫번째에
|
||||
파라미터를 위치지워라.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
436
reference/ko/modules/inheritance_mapping.xml
Normal file
@ -0,0 +1,436 @@
|
||||
<chapter id="inheritance">
|
||||
<title>상속 매핑</title>
|
||||
|
||||
<sect1 id="inheritance-strategies" revision="2">
|
||||
<title>세 가지 방도들</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 세 가지 기본적인 상속 매핑 방도들을 지원한다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
table per class hierarchy
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
table per subclass
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
table per concrete class
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
게다가 Hibernate는 네 번째의 약간 다른 종류의 다형성을 지원한다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
implicit polymorphism(함축적인 다형성)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
동일한 상속 계층구조의 다른 가지들에 대해 다른 매핑 방도들을 사용하는 것이 가능하고, 그런 다음 전체 계층 구조를 가로질러
|
||||
다형성을 성취하는데 함축적인 다형성을 사용하라. 하지만 Hibernate는 동일한 루트 <literal><class></literal> 요소
|
||||
하에서 <literal><subclass></literal> 그리고 <literal><joined-subclass></literal> 그리고
|
||||
<literal><union-subclass></literal> 매핑들을 혼합하는 것을 지원하지 않는다. 동일한 <literal><class></literal>
|
||||
요소 하에서 <literal><subclass></literal> 요소와 <literal><join></literal> 요소를 결합시킴으로써
|
||||
table per hierarchy 방도와 table per subclass 방도를 함께 혼합시키는 것이 가능하다(아래를 보라).
|
||||
</para>
|
||||
|
||||
<sect2 id="inheritance-tableperclass" >
|
||||
<title>Table per class hierarchy</title>
|
||||
|
||||
<para>
|
||||
우리가 <literal>CreditCardPayment</literal>, <literal>CashPayment</literal>, <literal>ChequePayment</literal>
|
||||
구현자들을 가진 하나의 인터페이스 <literal>Payment</literal>를 갖고 있다고 가정하자. table per hierarchy 매핑은
|
||||
다음과 같을 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
...
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
정확히 하나의 테이블이 필요하다. 이 매핑 방도에는 다음의 하나의 큰 제약이 존재한다: <literal>CCTYPE</literal>과 같이,
|
||||
서브 클래스들에 의해 선언된 컬럼들은 <literal>NOT NULL</literal> 컨스트레인트들을 가질 수 없다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tablepersubclass">
|
||||
<title>Table per subclass</title>
|
||||
|
||||
<para>
|
||||
table per subclass 매핑은 다음과 같을 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
네 개의 테이블들이 필요하다. 세 개의 서브클래스 테이블들은 슈퍼클래스 테이블에 대한 프라이머리 키 연관들을 갖는다
|
||||
(따라서 그 관계형 모형은 실제로 one-to-one 연관이다).
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
|
||||
<title>discriminator를 사용하는, table per subclass</title>
|
||||
|
||||
<para>
|
||||
table-per-subclass에 대한 Hibernate의 구현은 discriminator(판별자) 컬럼을 필요로 하지 않음을 노트하라.
|
||||
다른 객체/관계형 매핑기들은 슈퍼클래스 테이블 속에 하나의 타입 판별자 컬럼을 필요로 하는 table-per-subclass에 대한 다른 구현을
|
||||
사용한다. Hibernate에 의해 채택된 접근법은 구현하기가 훨씬 더 어렵지만 관계형 관점에서는 아마 틀림없이 보다 더 정확하다.
|
||||
만일 당신이 table per subclass 방도에 대해 하나의 판별자 컬럼을 사용하고 싶다면, 당신은 다음과 같이
|
||||
<literal><subclass></literal>와 <literal><join></literal>의 사용을 결합시킬 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<join table="CREDIT_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
<join table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
<join table="CHEQUE_PAYMENT" fetch="select">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
선택적인 <literal>fetch="select"</literal> 선언은 슈퍼클래스를 질의할 때 outer join을 사용하여
|
||||
<literal>ChequePayment</literal> 서브클래스 데이터를 페치시키지 않도록 Hibernate에게 알려준다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
|
||||
<title>table per class hierarchy와 table per subclass를 혼합하기</title>
|
||||
|
||||
<para>
|
||||
당신은 이 접근법을 사용하여 table per hierarchy 방도와 table per subclass 방도를 혼합시킬 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<join table="CREDIT_PAYMENT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
...
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이들 매핑 방도들 중 어떤 것에 대해, 루트 <literal>Payment</literal> 클래스에 대한 하나의 다형성 연관은
|
||||
<literal><many-to-one></literal>을 사용하여 매핑된다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcrete" revision="1">
|
||||
<title>Table per concrete class</title>
|
||||
|
||||
<para>
|
||||
우리가 table per concrete class 방도 매핑에 대해 취할 수 있는 두 가지 방법들이 존재한다. 첫 번째는
|
||||
<literal><union-subclass></literal>를 사용하는 것이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</union-subclass>
|
||||
<union-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
...
|
||||
</union-subclass>
|
||||
<union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
...
|
||||
</union-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
세 개의 테이블들이 수반된다. 각각의 테이블은 상속된 프로퍼티들을 포함하여, 그 클래스의 모든 프로퍼티들에 대한 컬럼들을 정의한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 접근법의 제약은 만일 하나의 프로퍼티가 슈퍼클래스 상으로 매핑될 경우, 그 컬럼 이름이 모든 서브클래스 테이블들 상에서 같아야 한다는
|
||||
점이다.(장래의 Hibernate 배포본에서 우리는 이 제약을 풀 수도 있다.) identity 생성기 방도는 union 서브클래스 상속에서 허용되지
|
||||
않으며, 진정 프라이머리 키 시드는 하나의 계층구조의 모든 unioned 서브클래스들을 가로질러 공유되어야 한다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcreate-polymorphism">
|
||||
<title>함축적인 다형성을 사용하는, table per concrete class</title>
|
||||
|
||||
<para>
|
||||
대안적인 접근법은 함축적인 다형성을 사용하는 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CREDIT_AMOUNT"/>
|
||||
...
|
||||
</class>
|
||||
|
||||
<class name="CashPayment" table="CASH_PAYMENT">
|
||||
<id name="id" type="long" column="CASH_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CASH_AMOUNT"/>
|
||||
...
|
||||
</class>
|
||||
|
||||
<class name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<id name="id" type="long" column="CHEQUE_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CHEQUE_AMOUNT"/>
|
||||
...
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
어느 곳에서도 우리가 명시적으로 <literal>Payment</literal> 인터페이스를 언급하지 않음을 주목하라.
|
||||
또한 <literal>Payment</literal>의 프로퍼티들이 서브클래스들 각각에서 매핑된다는 점을 주목하라.
|
||||
만일 당신이 중복을 피하고자 원한다면, XML 엔티티들을 사용하는 것을 고려하라(예를 들어 매핑에서
|
||||
<literal>DOCTYPE</literal> 선언과 <literal>&allproperties;</literal>에서
|
||||
<literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 접근법의 단점은 다형성 질의들을 수행할 때 Hibernate가 생성된 SQl <literal>UNION</literal>들을 생성시키는
|
||||
않는다는 점이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 매핑 방도의 경우, <literal>Payment</literal>에 대한 하나의 다형성 연관은 대개 <literal><any></literal>를
|
||||
사용하여 매핑된다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
|
||||
<meta-value value="CREDIT" class="CreditCardPayment"/>
|
||||
<meta-value value="CASH" class="CashPayment"/>
|
||||
<meta-value value="CHEQUE" class="ChequePayment"/>
|
||||
<column name="PAYMENT_CLASS"/>
|
||||
<column name="PAYMENT_ID"/>
|
||||
</any>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritace-mixingpolymorphism">
|
||||
<title>함축적인 다형성을 다른 상속 매핑들과 혼합하기</title>
|
||||
|
||||
<para>
|
||||
이 매핑에 대해 주목할 하나 이상의 것이 존재한다. 서브클래스들이 그것들 자신의<literal><class></literal> 요소 내에
|
||||
각각 매핑되므로(그리고 <literal>Payment</literal>가 단지 인터페이스이므로), 서브클래스들 각각은 쉽게 또 다른 상속 계층구조의
|
||||
부분일 수 있다! (그리고 당신은 <literal>Payment</literal> 인터페이스에 대해 여전히 다형성 질의들을 사용할 수 있다.)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="CREDIT_CARD" type="string"/>
|
||||
<property name="amount" column="CREDIT_AMOUNT"/>
|
||||
...
|
||||
<subclass name="MasterCardPayment" discriminator-value="MDC"/>
|
||||
<subclass name="VisaPayment" discriminator-value="VISA"/>
|
||||
</class>
|
||||
|
||||
<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
|
||||
<id name="id" type="long" column="TXN_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
...
|
||||
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="amount" column="CASH_AMOUNT"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="amount" column="CHEQUE_AMOUNT"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
다시 한번, 우리는 <literal>Payment</literal>를 명시적으로 언급하지 않는다. 만일 우리가 <literal>Payment</literal>
|
||||
인터페이스에 대해 하나의 질의를 실행할 경우-예를 들어, from Payment-, Hibernate는 <literal>CreditCardPayment</literal>
|
||||
(와 그것의 서브클래스들, 왜냐하면 그것들 또한 <literal>Payment</literal>를 구현하므로), <literal>CashPayment</literal>
|
||||
그리고 <literal>ChequePayment</literal> 인스턴스들을 자동적으로 반환할 것이지만
|
||||
<literal>NonelectronicTransaction</literal>의 인스턴스들을 반환하지 않는다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="inheritance-limitations">
|
||||
<title>제약들</title>
|
||||
|
||||
<para>
|
||||
table per concrete-class 매핑 방도에 대한 "함축적인 다형성" 접근법에는 어떤 제약들이 존재한다.
|
||||
<literal><union-subclass></literal> 매핑들에 대해서는 다소 덜 제한적인 제약들이 존재한다:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다음 표는 Hibernate에서 table per concrete-class 매핑들에 대한 제약들, 그리고 함축적인 다형성에 대한 제약들을 보여준다.
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title>상속 매핑들의 특징들</title>
|
||||
<tgroup cols='8' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname='c1' colwidth="1*"/>
|
||||
<colspec colname='c2' colwidth="1*"/>
|
||||
<colspec colname='c3' colwidth="1*"/>
|
||||
<colspec colname='c4' colwidth="1*"/>
|
||||
<colspec colname='c5' colwidth="1*"/>
|
||||
<colspec colname='c6' colwidth="1*"/>
|
||||
<colspec colname='c7' colwidth="1*"/>
|
||||
<colspec colname='c8' colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>상속 방도</entry>
|
||||
<entry>다형성 다대일</entry>
|
||||
<entry>다형성 일대일</entry>
|
||||
<entry>다형성 일대다</entry>
|
||||
<entry>다형성 다대다</entry>
|
||||
<entry>다형성 <literal>load()/get()</literal></entry>
|
||||
<entry>다형성 질의들</entry>
|
||||
<entry>다형성 조인들</entry>
|
||||
<entry>Outer 조인 페칭</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>table per class-hierarchy</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal></entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>지원됨</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per subclass</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal></entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>지원됨</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per concrete-class (union-subclass)</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>지원됨</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per concrete class (implicit polymorphism)</entry>
|
||||
<entry><literal><any></literal></entry>
|
||||
<entry><emphasis>지원되지 않음</emphasis></entry>
|
||||
<entry><emphasis>지원되지 않음</emphasis></entry>
|
||||
<entry><literal><many-to-any></literal></entry>
|
||||
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><emphasis>지원되지 않음</emphasis></entry>
|
||||
<entry><emphasis>지원되지 않음</emphasis></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
1234
reference/ko/modules/performance.xml
Normal file
440
reference/ko/modules/persistent_classes.xml
Normal file
@ -0,0 +1,440 @@
|
||||
<chapter id="persistent-classes" revision="2">
|
||||
<title>영속 클래스들</title>
|
||||
|
||||
<para>
|
||||
영속 클래스들은 비지니스 문제의 엔티티들(예를 들어 E-Commerce 어플리케이션에서 고객이나 주문)을 구현하는
|
||||
어플리케이션 내의 클래스들이다. 영속 클래스들의 인스턴스들은 영속 상태에 있는 것으로 전혀 간주되지 않는다 -
|
||||
대신에 하나의 인스턴스는 transient 또는 detached 상태일 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 이들 클래스들이 Plain Old Java Object (POJO) 프로그래밍 모형으로서 알려진, 몇몇 간단한
|
||||
규칙들을 따를 경우에 가장 잘 동작한다. 하지만 이들 규칙들 중 어떤 것도 어려운 사양들이 아니다. 진정 Hibernate3는
|
||||
당신의 영속 객체들의 특징에 대해 매우 적은 것을 가정한다. 당신은 다른 방법들로 도메인 모형을 표현할 수 있다 :
|
||||
예를 들어 <literal>Map</literal> 인스턴스의 트리들을 사용하기.
|
||||
</para>
|
||||
|
||||
<sect1 id="persistent-classes-pojo">
|
||||
<title>간단한 POJO 예제</title>
|
||||
|
||||
<para>
|
||||
대부분의 자바 어플리케이션들은 고양이과들을 표현하는 영속 클래스를 필요로 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
|
||||
public class Cat {
|
||||
private Long id; // identifier
|
||||
|
||||
private Date birthdate;
|
||||
private Color color;
|
||||
private char sex;
|
||||
private float weight;
|
||||
private int litterId;
|
||||
|
||||
private Cat mother;
|
||||
private Set kittens = new HashSet();
|
||||
|
||||
private void setId(Long id) {
|
||||
this.id=id;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setBirthdate(Date date) {
|
||||
birthdate = date;
|
||||
}
|
||||
public Date getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
|
||||
void setWeight(float weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
void setSex(char sex) {
|
||||
this.sex=sex;
|
||||
}
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
void setLitterId(int id) {
|
||||
this.litterId = id;
|
||||
}
|
||||
public int getLitterId() {
|
||||
return litterId;
|
||||
}
|
||||
|
||||
void setMother(Cat mother) {
|
||||
this.mother = mother;
|
||||
}
|
||||
public Cat getMother() {
|
||||
return mother;
|
||||
}
|
||||
void setKittens(Set kittens) {
|
||||
this.kittens = kittens;
|
||||
}
|
||||
public Set getKittens() {
|
||||
return kittens;
|
||||
}
|
||||
|
||||
// addKitten not needed by Hibernate
|
||||
public void addKitten(Cat kitten) {
|
||||
kitten.setMother(this);
|
||||
kitten.setLitterId( kittens.size() );
|
||||
kittens.add(kitten);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
준수할 네 개의 주요 규칙들이 다음에 있다:
|
||||
</para>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
||||
<title>아규먼트 없는 생성자를 구현하라 </title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal>은 아규먼트 없는 생성자를 갖는다. 모든 영속 클래스들은 Hibernate는
|
||||
<literal>Constructor.newInstance()</literal>를 사용하여 그것들을 초기화 시킬 수 있도록 디폴트 생성자
|
||||
(public이 아닐 수 있다)를 가져야 한다. 우리는 Hibernate 내에서 런타임 프락시 생성을 위한 최소한의
|
||||
<emphasis>패키지</emphasis> 가시성(visibility)를 가진 디폴트 생성자를 가질 것을 강력하게 권장한다.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-identifier" revision="2">
|
||||
<title>identifier 프로퍼티를 제공하라(옵션)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal>은 <literal>id</literal>로 명명된 하나의 프로퍼티를 갖는다. 이 프로퍼티는
|
||||
데이터베이스 테이블의 프라이머리 키 컬럼으로 매핑된다. 이 프로퍼티는 어떤 것으로 명명될 수도 있고, 그것의 타입은
|
||||
임의의 원시 타입, 원시 "wrapper" 타입, <literal>java.lang.String</literal> 또는 <literal>java.util.Date</literal>일
|
||||
수 있다. (만일 당신의 리거시 데이터베이스 테이블이 composite 키들을 갖고 있다면, 당신은 이들 타입들을 가진
|
||||
사용자 정의 클래스를 사용할 수도 있다 - 나중에 composite 식별자들에 대한 절을 보라)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
identifier 프로퍼티는 엄격하게 옵션이다. 당신은 그것을 생략할 수도 있고, Hibernate로 하여금 내부적으로
|
||||
객체 식별자들을 추적하도록 할 수 있다. 하지만 우리는 이것을 권장하지 않는다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
사실, 어떤 기능은 identifier 프로퍼티를 선언하는 클래스들에 대해서만 이용 가능하다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
detached 객체들에 대한 Transitive reattachment(cascade update 또는 cascade merge)
|
||||
- <xref linkend="objectstate-transitive"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session.saveOrUpdate()</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session.merge()</literal>
|
||||
</para>
|
||||
<para>
|
||||
를 보라
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
우리는 당신이 영속 클래스들에 대해 일관되게 명명된 identifier 프로퍼티들을 선언할 것을 권장한다. 게다가 우리는
|
||||
당신이 nullable 타입(예를 들어 non-primitive)을 사용할 것을 권장한다.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-final">
|
||||
<title>final이 아닌 클래스들을 선호하라(옵션)</title>
|
||||
<para>
|
||||
Hibernate의 중심 특징인, 프락시(<emphasis>proxies</emphasis>)들은 final이 아닌 영속 클래스들 또는 모두
|
||||
public 메소드들로 선언된 인터페이스의 구현인 영속 클래스들에 의존한다.
|
||||
</para>
|
||||
<para>
|
||||
당신은 Hibernate로 인터페이스를 구현하지 않은 <literal>final</literal> 클래스들을 영속화 시킬 수 있지만
|
||||
당신은 lazy 연관 페칭(lazy association fetching)에 대해 프락시들을 사용할 수 없을 것이다 -그것은 퍼포먼스
|
||||
튜닝을 위한 당신의 옵션들을 제한시킬 것이다.
|
||||
</para>
|
||||
<para>
|
||||
당신은 또한 non-final 클래스들 상에 <literal>public final</literal> 메소드들을 선언하는 것을 피해야 한다.
|
||||
만일 당신이 <literal>public final</literal> 메소드를 가진 클래스를 사용하고자 원할 경우, 당신은
|
||||
<literal>lazy="false"</literal>를 설정함으로써 명시적으로 프락싱을 사용 불가능하도록 해야 한다.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-accessors" revision="2">
|
||||
<title>영속 필드들을 위한 accessor들과 mutator들을 선언하라(옵션)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal>은 그것의 모든 영속 필드들에 대해 accessor 메소드들을 선언한다. 많은 다른 ORM 도구들은
|
||||
인스턴스 변수들을 직접 영속화 시킨다. 우리는 관계형 스키마와 클래스의 내부적인 데이터 구조들 사이에 간접적인 수단을
|
||||
제공하는 것이 더 좋다고 믿고 있다. 디폴트로 Hibernate는 자바빈즈 스타일 프로퍼티들을 영속화 시키고, <literal>getFoo</literal>,
|
||||
<literal>isFoo</literal>와 <literal>setFoo</literal> 형식의 메소드 이름들을 인지한다. 당신은 진정으로
|
||||
특정 프로퍼티에 대한 직접적인 필드 접근으로 전환할 수도 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
프로퍼티들은 public으로 선언될 필요가 <emphasis>없다</emphasis> - Hibernate는 디폴트로
|
||||
<literal>protected</literal> get/set 쌍 또는 <literal>private</literal> get/set
|
||||
쌍을 가진 프로퍼티를 영속화 시킬 수 있다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-inheritance">
|
||||
<title>상속 구현하기</title>
|
||||
|
||||
<para>
|
||||
서브클래스는 또한 첫 번째 규칙들과 두 번째 규칙들을 주시해야 한다. 그것은 슈퍼클래스 <literal>Cat</literal>으로부터
|
||||
그것의 identifier 프로퍼티를 상속받는다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
public class DomesticCat extends Cat {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
protected void setName(String name) {
|
||||
this.name=name;
|
||||
}
|
||||
}]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-equalshashcode" revision="1">
|
||||
<title><literal>equals()</literal>와 <literal>hashCode()</literal> 구현하기</title>
|
||||
|
||||
<para>
|
||||
만일 당신이
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
하나의 <literal>Set</literal> 속에 영속 클래스들의 인스턴스들을 집어넣고자 의도하고
|
||||
(many-valued 연관들에 대해 권장되는 방법)
|
||||
<emphasis>그리고</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
detached 인스턴스들의 reattachment(재첨부)를 사용하고자 의도하는
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
경우에 당신은 <literal>equals()</literal>와 <literal>hashCode()</literal> 메소드들을 오버라이드 시켜야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 특정 session 범위 내에서만 persistent identity(데이터베이스 행)과 Java identity의 같음을 보장한다.
|
||||
따라서 우리가 다른 세션들에서 검색된 인스턴스들을 혼합시키자마자, 우리가 <literal>Set</literal>들에 대해 유의미하게
|
||||
만들고자 원할 경우, 우리는 <literal>equals()</literal>와 <literal>hashCode()</literal>를 구현해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
가장 명백한 방법은 두 객체들의 identifier 값을 비교함으로써 <literal>equals()</literal>/<literal>hashCode()</literal>를
|
||||
구현하는 것이다. 만일 그 값이 동일하다면, 둘다 동일한 데이터베이스 행이어야 하고, 그러므로 그것들은 같다(둘다 하나의
|
||||
<literal>Set</literal>에 추가되는 경우에, 우리는 <literal>Set</literal> 속에서 하나의 요소만을 갖게 될 것이다).
|
||||
불행하게도, 우리는 생성되는 식별자들을 갖는 그 접근법을 사용할 수 없다! Hibernate는 오직 식별자 값들을 영속화 되는 객체들에
|
||||
할당할 것이고, 새로이 생성된 인스턴스는 임의의 identifier 값을 갖지 않을 것이다! 만일 인스턴스가 저장되지 않고 현재 하나의
|
||||
<literal>Set</literal> 속에 있을 경우에, 그것을 저장하는것은 하나의 식별자 값을 그 객체에게 할당할 것이다. 만일
|
||||
<literal>equals()</literal>와 <literal>hashCode()</literal>가 그 식별자 값에 기초할 경우, hash 코드는
|
||||
<literal>Set</literal>의 계약을 파기하여 변경될 것이다. 이 문제에 대한 전체 논의에 대해서는 Hibernate 웹 사이트를 보라.
|
||||
이것은 Hibernate 쟁점이 아닌, 객체 identity와 equality에 관한 통상의 자바 의미론임을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 <emphasis>Business key equality</emphasis>를 사용하여 <literal>equals()</literal>와 <literal>hashCode()</literal>를
|
||||
구현할 것 권장한다. Business key equality는 <literal>equals()</literal> 메소드가 비지니스 키, 즉 실세계에서 우리의 인스턴스를
|
||||
식별하게 될 키(<emphasis>natural</emphasis> 후보 키)를 형성하는 프로퍼티들만을 비교한다는 점을 의미한다 :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Cat {
|
||||
|
||||
...
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if ( !(other instanceof Cat) ) return false;
|
||||
|
||||
final Cat cat = (Cat) other;
|
||||
|
||||
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
|
||||
if ( !cat.getMother().equals( getMother() ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = getMother().hashCode();
|
||||
result = 29 * result + getLitterId();
|
||||
return result;
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
하나의 비지니스 키는 데이터베이스 프라이머리 키 후보 만큼 견고하지 않아야 한다(<xref linkend="transactions-basics-identity"/>를 보라).
|
||||
대개 변경할 수 없는 프로퍼티 또는 유일한(unique) 프로퍼티는 대개 비지니스 키에 대한 좋은 후보들이다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-dynamicmodels">
|
||||
<title>동적인 모형들</title>
|
||||
|
||||
<para>
|
||||
<emphasis>다음 특징들은 현재 실험적으로 고려되고 있으며 장래에는 변경될 수 있음을 노트하라.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
영속 엔티티들은 반드시 실행시에 POJO 클래스들로 또는 자바빈즈 객체들로 표현되어야할 필요는 없다. Hibernate는
|
||||
또한 (실행 시에 <literal>Map</literal>들을 가진 <literal>Map</literal>들을 사용하여) 동적인 모형들을 지원하고
|
||||
DOM4J 트리들로서 엔티티들에 대한 표현을 지원한다. 이 접근법으로, 당신은 영속 클래스들을 작성하지 않고, 오직 매핑 파일들
|
||||
만을 작성한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
디폴트로, Hibernate는 통산의 POJO 모드로 동작한다. 당신은 <literal>default_entity_mode</literal> 구성 옵션을
|
||||
사용하여 특별한 <literal>SessionFactory</literal>에 대해 디폴트 엔티티 표현 모드를 설정할 수 있다
|
||||
(<xref linkend="configuration-optional-properties"/>을 보라).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다음 예제들은<literal>Map</literal>들을 사용하는 표현을 설명한다. 먼저 매핑 파일에서, <literal>entity-name</literal>은
|
||||
클래스 이름 대신에(또는 클래스 이름에 덧붙여) 선언되어야 한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class entity-name="Customer">
|
||||
|
||||
<id name="id"
|
||||
type="long"
|
||||
column="ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
|
||||
<property name="name"
|
||||
column="NAME"
|
||||
type="string"/>
|
||||
|
||||
<property name="address"
|
||||
column="ADDRESS"
|
||||
type="string"/>
|
||||
|
||||
<many-to-one name="organization"
|
||||
column="ORGANIZATION_ID"
|
||||
class="Organization"/>
|
||||
|
||||
<bag name="orders"
|
||||
inverse="true"
|
||||
lazy="false"
|
||||
cascade="all">
|
||||
<key column="CUSTOMER_ID"/>
|
||||
<one-to-many class="Order"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
심지어 비록 연관들이 대상(target) 클래스 이름들을 사용하여 선언될지라도, 연관들의 대상(target) 타입은 또한 POJO가 아닌
|
||||
동적인 엔티티일 수 있음을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal>에 대한 디폴트 엔티티 모드를 <literal>dynamic-map</literal>으로 설정한 후에,
|
||||
우리는 <literal>Map</literal>들을 가진 <literal>Map</literal>들에 대해 실행 시에 작업할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session s = openSession();
|
||||
Transaction tx = s.beginTransaction();
|
||||
Session s = openSession();
|
||||
|
||||
// Create a customer
|
||||
Map david = new HashMap();
|
||||
david.put("name", "David");
|
||||
|
||||
// Create an organization
|
||||
Map foobar = new HashMap();
|
||||
foobar.put("name", "Foobar Inc.");
|
||||
|
||||
// Link both
|
||||
david.put("organization", foobar);
|
||||
|
||||
// Save both
|
||||
s.save("Customer", david);
|
||||
s.save("Organization", foobar);
|
||||
|
||||
tx.commit();
|
||||
s.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
dynamic 매핑의 장점들은 엔티티 클래스 구현에 대한 필요 없이도 프로토타이핑을 위한 빠른 전환 시간이다. 하지만 당신은
|
||||
컴파일 시 타입 체킹을 잃고 실행 시에 많은 예외상황들을 다루게 될 것이다. Hibernate 매핑 덕분에,
|
||||
나중에 고유한 도메인 모형 구현을 상단에 추가하는 것이 허용되어서, 데이터베이스 스키마가 쉽게 정규화 되고 소리가 울려 퍼질 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
엔티티 표현 모드들은 또한 하나의 단위 <literal>Session</literal> 기준에 대해 설정될 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
|
||||
|
||||
// Create a customer
|
||||
Map david = new HashMap();
|
||||
david.put("name", "David");
|
||||
dynamicSession.save("Customer", david);
|
||||
...
|
||||
dynamicSession.flush();
|
||||
dynamicSession.close()
|
||||
...
|
||||
// Continue on pojoSession
|
||||
]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
<literal>EntityMode</literal>를 사용하는 <literal>getSession()</literal>에 대한 호출은
|
||||
<literal>SessionFactory</literal>가 아닌, <literal>Session</literal> API에 대한 것임을 노트하길 바란다.
|
||||
그 방법으로, 새로운 <literal>Session</literal>은 기본 JDBC 커넥션, 트랜잭션, 그리고 다른 컨텍스트 정보를 공유한다.
|
||||
이것은 당신이 두 번째 <literal>Session</literal> 상에서 <literal>flush()</literal>와 <literal>close()</literal>를
|
||||
호출하지 말아야 하고, 또한 트랜잭션 및 커넥션 핸들링을 주된 작업 단위에게 맡긴다는 점을 의미한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
XML 표현 가용성들에 대한 추가 정보는 <xref linkend="xml"/>에서 찾을 수 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<para>
|
||||
TODO: property 패키지와 proxy 패키지 내에 user-extension 프레임웍을 문서화 할 것.
|
||||
</para>
|
||||
|
||||
</chapter>
|
||||
|
419
reference/ko/modules/query_criteria.xml
Normal file
@ -0,0 +1,419 @@
|
||||
<chapter id="querycriteria">
|
||||
<title>Criteria 질의들</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 직관적인, 확장 가능한 criteria query API를 특징 짓는다.
|
||||
</para>
|
||||
|
||||
<sect1 id="querycriteria-creating">
|
||||
<title><literal>Criteria</literal> 인스턴스 생성하기</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.Criteria</literal>인터페이스는 특정 영속 클래스에 대한 질의를 표현한다.
|
||||
<literal>Session</literal>은 <literal>Criteria</literal> 인스턴스들에 대한 팩토리이다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
|
||||
crit.setMaxResults(50);
|
||||
List cats = crit.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-narrowing">
|
||||
<title>결과 셋 제한하기</title>
|
||||
|
||||
<para>
|
||||
개별적인 질의 기준은 <literal>org.hibernate.criterion.Criterion</literal> 인터페이스의 인스턴스이다.
|
||||
<literal>org.hibernate.criterion.Restrictions</literal> 클래스는 어떤 미리 만들어진 <literal>Criterion</literal>
|
||||
타입들을 얻는 팩토리 메소드들을 정의한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.add( Restrictions.between("weight", minWeight, maxWeight) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
제한들은 논리적으로 그룹지워질 수도 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.add( Restrictions.or(
|
||||
Restrictions.eq( "age", new Integer(0) ),
|
||||
Restrictions.isNull("age")
|
||||
) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
|
||||
.add( Restrictions.disjunction()
|
||||
.add( Restrictions.isNull("age") )
|
||||
.add( Restrictions.eq("age", new Integer(0) ) )
|
||||
.add( Restrictions.eq("age", new Integer(1) ) )
|
||||
.add( Restrictions.eq("age", new Integer(2) ) )
|
||||
) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
미리 만들어진 criterion 타입들(<literal>Restrictions</literal> 서브클래스들)의 영역이 꽤 존재하지만, 특히 유용한 것은
|
||||
당신으로 하여금 SQL을 직접 지정하도록 해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
질의된 엔티티의 행 alias에 의해 대체된 <literal>{alias}</literal> placeholder.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
criterion을 얻는 대안적인 접근법은 <literal>Property</literal> 인스턴스로부터 그것을 얻는 것이다. 당신은
|
||||
<literal>Property.forName()</literal>을 호출하여 <literal>Property</literal>를 생성시킬 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
Property age = Property.forName("age");
|
||||
List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.disjunction()
|
||||
.add( age.isNull() )
|
||||
.add( age.eq( new Integer(0) ) )
|
||||
.add( age.eq( new Integer(1) ) )
|
||||
.add( age.eq( new Integer(2) ) )
|
||||
) )
|
||||
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-ordering">
|
||||
<title>결과들을 순서지우기(ordering)</title>
|
||||
|
||||
<para>
|
||||
당신은 <literal>org.hibernate.criterion.Order</literal>를 사용하여 결과들을 순서(ordering)지울 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "F%")
|
||||
.addOrder( Order.asc("name") )
|
||||
.addOrder( Order.desc("age") )
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Property.forName("name").like("F%") )
|
||||
.addOrder( Property.forName("name").asc() )
|
||||
.addOrder( Property.forName("age").desc() )
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-associations">
|
||||
<title>연관들</title>
|
||||
|
||||
<para>
|
||||
당신은 <literal>createCriteria()</literal>를 사용하여 연관들을 네비게이트함으로써 관계된 엔티티들에 대한 컨스트레인트들을
|
||||
쉽게 지정할 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "F%")
|
||||
.createCriteria("kittens")
|
||||
.add( Restrictions.like("name", "F%")
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
두 번째 <literal>createCriteria()</literal>는 <literal>Criteria</literal>의 새로운 인스턴스를 반환하며, 그것은
|
||||
<literal>kittens</literal> 콜렉션의 요소들을 참조한다는 점을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다음 대체 형식은 어떤 환경들에서 유용하다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.createAlias("kittens", "kt")
|
||||
.createAlias("mate", "mt")
|
||||
.add( Restrictions.eqProperty("kt.name", "mt.name") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal>createAlias()</literal>는 <literal>Criteria</literal>의 새로운 인스턴스를 생성시키지 않는다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
앞의 두 개의 질의들에 의해 반환된 <literal>Cat</literal> 인스턴스들에 의해 보관된 kittens 콜렉션들은 criteria에 의해
|
||||
사전-필터링되지 <emphasis>않는다</emphasis>는 점을 노트하라! 만일 당신이 criteria(기준)과 일치하는 고양이 새끼들을
|
||||
단지 검색하고자 원할 경우, 당신은 <literal>returnMaps()</literal>를 사용해야 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.createCriteria("kittens", "kt")
|
||||
.add( Restrictions.eq("name", "F%") )
|
||||
.returnMaps()
|
||||
.list();
|
||||
Iterator iter = cats.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map map = (Map) iter.next();
|
||||
Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
|
||||
Cat kitten = (Cat) map.get("kt");
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-dynamicfetching" revision="1">
|
||||
<title>동적인 연관 페칭</title>
|
||||
|
||||
<para>
|
||||
당신은 <literal>setFetchMode()</literal>를 사용하여 실행 시에 연관 페칭 의미를 지정할 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.setFetchMode("mate", FetchMode.EAGER)
|
||||
.setFetchMode("kittens", FetchMode.EAGER)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 질의는 outer 조인으로 <literal>mate</literal>와 <literal>kittens</literal> 모두를 페치할 것이다. 추가 정보는
|
||||
<xref linkend="performance-fetching"/>을 보라.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-examples">
|
||||
<title>예제 질의들</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Example</literal> 클래스는 주어진 인스턴스로부터 질의 기준(criterion)을 구조화
|
||||
시키는 것을 당신에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Cat cat = new Cat();
|
||||
cat.setSex('F');
|
||||
cat.setColor(Color.BLACK);
|
||||
List results = session.createCriteria(Cat.class)
|
||||
.add( Example.create(cat) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
버전 프로퍼티들, 식별자들, 연관관계들이 무시된다. 디폴트로 null 값 프로퍼티들이 제외된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 <literal>Example</literal>이 적용되는 방법을 조정할 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Example example = Example.create(cat)
|
||||
.excludeZeroes() //exclude zero valued properties
|
||||
.excludeProperty("color") //exclude the property named "color"
|
||||
.ignoreCase() //perform case insensitive string comparisons
|
||||
.enableLike(); //use like for string comparisons
|
||||
List results = session.createCriteria(Cat.class)
|
||||
.add(example)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 연관된 객체들에 대한 criteria(기준)을 위치지우는데 examples를 사용할 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.add( Example.create(cat) )
|
||||
.createCriteria("mate")
|
||||
.add( Example.create( cat.getMate() ) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-projection">
|
||||
<title>Projections, aggregation 그리고 grouping</title>
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Projections</literal> 클래스는 <literal>Projection</literal> 인스턴스들에
|
||||
대한 팩토리이다. 우리는 <literal>setProjection()</literal>을 호출하여 하나의 질의에 projection(투사,투영)을 적용시킨다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.rowCount() )
|
||||
.add( Restrictions.eq("color", Color.BLACK) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount() )
|
||||
.add( Projections.avg("weight") )
|
||||
.add( Projections.max("weight") )
|
||||
.add( Projections.groupProperty("color") )
|
||||
)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
criteria 질의 내에서는 명시적인 "group by"가 필수적이지 않다. 어떤 projection 타입들은
|
||||
<emphasis>grouping projections</emphasis>들이게끔 정의되고, 그것은 또한 SQL <literal>group by</literal> 절 속에
|
||||
나타난다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
alias는 선택적으로 projection에 할당될 수 있어서, 투사된(projected) 값은 제한(restriction)들 또는 ordering들 내에서
|
||||
참조될 수 있다. 다음은 이것을 행하는 두 개의 다른 방법들이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
|
||||
.addOrder( Order.asc("colr") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.groupProperty("color").as("colr") )
|
||||
.addOrder( Order.asc("colr") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>alias()</literal> 메소드와 <literal>as()</literal> 메소드는 또 다른 alias 된
|
||||
<literal>Projection</literal>의 인스턴스 내에 하나의 projection 인스턴스를 간단하게 포장한다. 지름길로서,
|
||||
당신이 projection을 projection 리스트에 추가할 때 당신은 alias를 할당할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount(), "catCountByColor" )
|
||||
.add( Projections.avg("weight"), "avgWeight" )
|
||||
.add( Projections.max("weight"), "maxWeight" )
|
||||
.add( Projections.groupProperty("color"), "color" )
|
||||
)
|
||||
.addOrder( Order.desc("catCountByColor") )
|
||||
.addOrder( Order.desc("avgWeight") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
|
||||
.createAlias("kittens", "kit")
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.property("cat.name"), "catName" )
|
||||
.add( Projections.property("kit.name"), "kitName" )
|
||||
)
|
||||
.addOrder( Order.asc("catName") )
|
||||
.addOrder( Order.asc("kitName") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 또한 projection들을 표현하는데 <literal>Property.forName()</literal>을 사용할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Property.forName("name") )
|
||||
.add( Property.forName("color").eq(Color.BLACK) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount().as("catCountByColor") )
|
||||
.add( Property.forName("weight").avg().as("avgWeight") )
|
||||
.add( Property.forName("weight").max().as("maxWeight") )
|
||||
.add( Property.forName("color").group().as("color" )
|
||||
)
|
||||
.addOrder( Order.desc("catCountByColor") )
|
||||
.addOrder( Order.desc("avgWeight") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-detachedqueries">
|
||||
<title>Detached 질의들과 서브질의들</title>
|
||||
<para>
|
||||
<literal>DetachedCriteria</literal> 클래스는 당신에게 세션 영역의 외부에서 질의를 생성시키도록 하고, 그런 다음 나중에
|
||||
어떤 임의의 <literal>Session</literal>을 사용하여 그것을 실행하도록 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
|
||||
.add( Property.forName("sex").eq('F') );
|
||||
|
||||
Session session = ....;
|
||||
Transaction txn = session.beginTransaction();
|
||||
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
|
||||
txn.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>DetachedCriteria</literal>는 또한 서브질의를 표현하는데 사용된다. 서브질의들을 포함하는 Criterion 인스턴스들은
|
||||
<literal>Subqueries</literal> 또는 <literal>Property</literal>를 통해 얻어질 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
|
||||
.setProjection( Property.forName("weight").avg() );
|
||||
session.createCriteria(Cat.class)
|
||||
.add( Property.forName("weight).gt(avgWeight) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
|
||||
.setProjection( Property.forName("weight") );
|
||||
session.createCriteria(Cat.class)
|
||||
.add( Subqueries.geAll("weight", weights) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
심지어 상관관계 지워진 서브질의들이 가능하다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
|
||||
.setProjection( Property.forName("weight").avg() )
|
||||
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
|
||||
session.createCriteria(Cat.class, "cat")
|
||||
.add( Property.forName("weight).gt(avgWeightForSex) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer는 -JDO2에서 setResultClass와 유사한- 임의적인
|
||||
사용자 객체들을 반환하는 것을 허용한다. ResultTransformer에 대한 일반적인 사용이 또한 설명될 수 있다. -->
|
||||
|
||||
<sect1 id="query-criteria-naturalid">
|
||||
<title>natural 식별자에 의한 질의들</title>
|
||||
|
||||
<para>
|
||||
대부분의 질의들에서, criteria 질의들을 포함하여, 질의 캐시는 매우 효율적이지 않다. 왜냐하면 질의 캐시 비유효성이
|
||||
너무 자주 발생하기 때문이다. 하지만, 우리가 캐시 비유효성 알고리즘을 최적화 시킬 수 있는 한 가지 특별한 종류의 질의가
|
||||
존재한다: 상수 natural 키에 의한 룩업. 몇몇 어플리케이션들에서, 이런 종류의 질의가 자주 발생한다. criteria API는
|
||||
이 쓰임새를 위한 특별한 설비를 제공한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
첫번째로 당신은 <literal><natural-id></literal>를 사용하여 당신의 엔티티에 대한 natural 키를 매핑
|
||||
시켜야 하고, second-level 캐시 사용을 가능하게 해야 한다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="User">
|
||||
<cache usage="read-write"/>
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<natural-id>
|
||||
<property name="name"/>
|
||||
<property name="org"/>
|
||||
</natural-id>
|
||||
<property name="password"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 기능은 <emphasis>가변성 있는</emphasis> natural 키들을 가진 엔티티들의 용도로 고안되어 있지 않음을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다음으로 , Hibernate 질의 캐시를 사용 가능하도록 하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이제 <literal>Restrictions.naturalId()</literal>는 캐시 알고리즘을 보다 효율적으로 사용할 수 있도록 우리에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.createCriteria(User.class)
|
||||
.add( Restrictions.naturalId()
|
||||
.set("name", "gavin")
|
||||
.set("org", "hb")
|
||||
).setCacheable(true)
|
||||
.uniqueResult();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
1048
reference/ko/modules/query_hql.xml
Normal file
457
reference/ko/modules/query_sql.xml
Normal file
@ -0,0 +1,457 @@
|
||||
<chapter id="querysql" revision="2">
|
||||
<title>Native SQL</title>
|
||||
|
||||
<para>
|
||||
당신은 또한 당신의 데이터베이스의 native SQL dialect로 질의들을 표현할 수도 있다. 당신이 오라클의 질의 힌트들 또는
|
||||
<literal>CONNECT</literal> 키워드와 같은 데이터베이스 지정적인 특징들을 활용하고자 원할 경우에 이것이 유용하다.
|
||||
그것은 또한 직접적인 SQL/JDBC 기반의 어플리케이션으로부터 Hibernate로의 보다 명료한 이전 경로를 제공한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate3은 또한 모든 create, update, delete, load 오퍼레이션들에 대해 (내장 프로시저들을 포함하여) 손으로 작성된 SQL을
|
||||
지정하는 것을 당신에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<sect1 id="querysql-creating">
|
||||
<title>native SQL <literal>Query</literal> 생성시키기</title>
|
||||
|
||||
<para>
|
||||
SQL 질의들은 <literal>SQLQuery</literal> 인터페이스를 통해 제어되고, 그것은
|
||||
<literal>Session.createSQLQuery()</literal>를 호출하여 얻어진다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
|
||||
.addEntity("cat", Cat.class)
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 질의는 다음을 지정했다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate가 컬럼 alias들을 도입하기 위한, placeholder를 가진, SQL 질의 문자열
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
그 질의에 의해 반환된 엔티티와 그것의 SQL 테이블 alias
|
||||
</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>
|
||||
|
||||
<programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight
|
||||
from cats cat")
|
||||
.addScalar("maxWeight", Hibernate.DOUBLE);
|
||||
.uniqueResult();]]></programlisting>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-aliasreferences">
|
||||
<title>Alias 참조와 프로퍼티 참조</title>
|
||||
|
||||
<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"
|
||||
|
||||
List loggedCats = sess.createSQLQuery(sql)
|
||||
.addEntity("cat", Cat.class)
|
||||
.setLong("catId", catId)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>노트:</emphasis> 만일 당신이 각각의 프로퍼티를 명시적으로 리스트할 경우, 당신은 그 클래스와
|
||||
<emphasis>그것의 서브클래스들</emphasis>의 모든 프로퍼티들을 포함해야 한다!
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-namedqueries" revision="2">
|
||||
<title>명명된 SQL 질의들</title>
|
||||
|
||||
<para>
|
||||
명명된 SQL 질의들은 HQL 질의와 동일한 방법으로 매핑 문서 속에 정의될 수 있고 정확하게 호출될 수도 있다. 이 경우에, 우리는
|
||||
<literal>addEntity()</literal> 호출을 필요로 하지 <emphasis>않는다</emphasis>.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="persons">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
SELECT person.NAME AS {person.name},
|
||||
person.AGE AS {person.age},
|
||||
person.SEX AS {person.sex}
|
||||
FROM PERSON person
|
||||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
||||
.setString("namePattern", namePattern)
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
<para>
|
||||
The <literal><return-join></literal> and <literal><load-collection></literal>
|
||||
elements are used to join associations and define queries which initialize collections,
|
||||
respectively.
|
||||
</para>
|
||||
|
||||
<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},
|
||||
person.AGE AS {person.age},
|
||||
person.SEX AS {person.sex},
|
||||
adddress.STREET AS {address.street},
|
||||
adddress.CITY AS {address.city},
|
||||
adddress.STATE AS {address.state},
|
||||
adddress.ZIP AS {address.zip}
|
||||
FROM PERSON person
|
||||
JOIN ADDRESS adddress
|
||||
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
||||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
명명된 SQL 질의는 스칼라 값을 반환할수도 있다. 당신은 <literal><return-scalar></literal> 요소를 사용하여
|
||||
컬럼 alias와 Hibernate 타입을 지정해야 한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return-scalar column="name" type="string"/>
|
||||
<return-scalar column="age" type="long"/>
|
||||
SELECT p.NAME AS name,
|
||||
p.AGE AS age,
|
||||
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<sect2 id="propertyresults">
|
||||
<title>명시적으로 column/alias 이름들을 지정하는데 return-property 사용하기</title>
|
||||
|
||||
<para>
|
||||
Hibernate로 하여금 그것 자신의 alias들을 끼워넣도록 하기 위해 <literal>{}</literal>-구문을 사용하는 것 대신에,
|
||||
<literal><return-property></literal>로서 당신은 사용할 컬럼 alias들이 무엇인지를 Hibernate에게 명시적으로
|
||||
알려줄 수 있다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return alias="person" class="eg.Person">
|
||||
<return-property name="name" column="myName"/>
|
||||
<return-property name="age" column="myAge"/>
|
||||
<return-property name="sex" column="mySex"/>
|
||||
</return>
|
||||
SELECT person.NAME AS myName,
|
||||
person.AGE AS myAge,
|
||||
person.SEX AS mySex,
|
||||
FROM PERSON person WHERE person.NAME LIKE :name
|
||||
</sql-query>
|
||||
]]></programlisting>
|
||||
|
||||
<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"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
<return-property name="endDate" column="myEndDate"/>
|
||||
</return>
|
||||
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
||||
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
||||
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT
|
||||
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>
|
||||
|
||||
<sect2 id="sp_query">
|
||||
<title>질의를 위한 내장 프로시저 사용하기</title>
|
||||
|
||||
<para>
|
||||
Hibernate 3은 내장 프로시저들을 통한 질의들에 대한 지원을 도입한다. 내장 프로시저들은 Hibernate와 동작하는 것이
|
||||
가능하도록 첫 번째 출력-파라미터로서 한 개의 결과셋을 반환해야 한다. Oracle9 이상의 버전에서 그런 내장 프로시저에
|
||||
대한 예제는 다음과 같다:
|
||||
</para>
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||
RETURN SYS_REFCURSOR
|
||||
AS
|
||||
st_cursor SYS_REFCURSOR;
|
||||
BEGIN
|
||||
OPEN st_cursor FOR
|
||||
SELECT EMPLOYEE, EMPLOYER,
|
||||
STARTDATE, ENDDATE,
|
||||
REGIONCODE, EID, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT;
|
||||
RETURN st_cursor;
|
||||
END;]]></programlisting>
|
||||
|
||||
<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"/>
|
||||
<return-property name="startDate" column="STARTDATE"/>
|
||||
<return-property name="endDate" column="ENDDATE"/>
|
||||
<return-property name="regionCode" column="REGIONCODE"/>
|
||||
<return-property name="id" column="EID"/>
|
||||
<return-property name="salary">
|
||||
<return-column name="VALUE"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
</return>
|
||||
{ ? = call selectAllEmployments() }
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
내장 프로시저들은 현재 스칼라들과 엔티티들 만을 반환함을 주목하라. <literal><return-join></literal>과
|
||||
<literal><load-collection></literal>은 지원되지 않는다.
|
||||
</para>
|
||||
|
||||
<sect3 id="querysql-limits-storedprocedures">
|
||||
<title>내장 프로시저들을 사용하는 규칙들/제약들</title>
|
||||
|
||||
<para>
|
||||
Hibernate에서 내장 프로시저들을 사용하기 위해서 프로시저들은 다음 몇몇 규칙들을 따라야 한다. 만일 그것들이 그들 규칙들을
|
||||
따르지 않을 경우 그것들은 Hibernate와 함께 사용 불가능하다. 만일 당신이 여전히 이들 프로시저들을 사용하고자 원할 경우,
|
||||
당신은 <literal>session.connection()</literal>을 통해 그것들을 실행시켜야 한다. 데이터베이스 벤더들이 다른 내장
|
||||
프로시저 의미론/구문을 갖고 있기 때문에, 규칙들은 각각의 데이터베이스에 따라 차이가 난다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
내장 프로시저 질의들은 <literal>setFirstResult()/setMaxResults()</literal>로서 쪽매김 될 수 없다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Oracle의 경우 다음 규칙들이 적용된다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
프로시저는 한 개의 결과 셋을 반환해야 한다. 이것은 Oracle 9 또는 10에서 한 개의 <literal>SYS_REFCURSOR</literal>를
|
||||
반환함으로써 행해진다. Oracle에서 당신은 한 개의 <literal>REF CURSOR</literal> 타입을 정의할 필요가 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
권장되는 형식은 <literal>{ ? = call procName(<parameters>) }</literal> 또는
|
||||
<literal>{ ? = call procName }</literal>이다.(이것은 Hibernate 규칙이라기 보다는 Oracle 규칙이다.)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Sybase 또는 MS SQL server의 경우 다음 규칙들이 적용된다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
프로시저는 한 개의 결과 셋을 반환해야 한다. 이들 서버들이 여러 개의 결과셋들과 업데이트 카운트들을 반환 할수 있다/할 것이이므로,
|
||||
Hibernate는 결과들을 반복 순환할 것이고 그것의 반환 값으로서 하나의 결과 셋인 첫 번째 결과를 취할 것이다. 그 밖의 모든 것은
|
||||
폐기될 것이다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
만일 당신이 당신의 프로시저 내에 <literal>SET NOCOUNT ON</literal>을 이용 가능하게 할 수 있다면 그것은 아마
|
||||
보다 효율적이게 될 것이지만 이것은 필요 조건이 아니다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<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>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
SQL이 당신의 데이터베이스 내에서 직접 실행되어서, 당신이 좋아하는 임의의 dialect를 사용하는 것이 자유롭다. 만일 당신이 데이터베이스
|
||||
지정적인 SQL을 사용할 경우 이것은 물론 당신의 매핑의 이식성을 감소시킬 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 <literal>callable</literal> 속성이 설정되면 내장 프로시저들이 지원된다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
||||
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
||||
<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가 문장의 성공을 위해 몇몇 실행 시 체크들을 행하므로, 내장 프로시저들은 대부분의 경우들(읽기:다른 경우들 보다 그것을 더 잘
|
||||
행한다)에서 insert되고/업데이트되고/삭제된 행들의 개수를 반환하는데 필요하다. Hibernate는 항상 CUD 오퍼레이션들에 대한 숫자
|
||||
출력 파라미터로서 첫 번째 문장 파라미터를 등록시킨다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
||||
RETURN NUMBER IS
|
||||
BEGIN
|
||||
|
||||
update PERSON
|
||||
set
|
||||
NAME = uname,
|
||||
where
|
||||
ID = uid;
|
||||
|
||||
return SQL%ROWCOUNT;
|
||||
|
||||
END updatePerson;]]></programlisting>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-load">
|
||||
<title>로딩을 위한 맞춤형 SQL</title>
|
||||
|
||||
<para>
|
||||
당신은 또한 엔티티 로딩을 위한 당신 자신의 SQL (또는 HQL)을 선언할 수도 있다:
|
||||
</para>
|
||||
|
||||
<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
|
||||
WHERE ID=?
|
||||
FOR UPDATE
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이것은 앞서 논의했듯이 단지 명명된 질의 선언이다. 당신은 class 매핑 속에 이 명명된 질의를 참조할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<loader query-ref="person"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<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.*}
|
||||
FROM EMPLOYMENT emp
|
||||
WHERE EMPLOYER = :id
|
||||
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 심지어 조인 페칭에 의해 하나의 콜렉션을 로드시키는 하나의 엔티티를 정의할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person"/>
|
||||
<return-join alias="emp" property="pers.employments"/>
|
||||
SELECT NAME AS {pers.*}, {emp.*}
|
||||
FROM PERSON pers
|
||||
LEFT OUTER JOIN EMPLOYMENT emp
|
||||
ON pers.ID = emp.PERSON_ID
|
||||
WHERE ID=?
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
572
reference/ko/modules/quickstart.xml
Normal file
@ -0,0 +1,572 @@
|
||||
<chapter id="quickstart">
|
||||
<title>Tomcat으로 빠른 시작</title>
|
||||
|
||||
<sect1 id="quickstart-intro" revision="2">
|
||||
<title>Hibernate 시작하기</title>
|
||||
|
||||
<para>
|
||||
이 튜토리얼은 웹 기반의 어플리케이션 용 Apache Tomcat 서블릿 컨테이너에 대한 Hibernate 3.0 셋업을
|
||||
설명한다(우리는 버전 4.1을 사용했다. 5.0에 대한 차이점들은 적을 것이다). Hibernate는 모든 주요 J2EE
|
||||
어플리케이션 서버들의 관리되는 환경에서 잘 동작하고, 또는 심지어 스탠드얼론 어플리케이션들에서도 잘 동작
|
||||
한다. 이 튜토리얼에 사용되는 데이터베이스 시스템은 PostgreSQL 7.4이고, 다른 데이터베이스에 대한 지원은
|
||||
단지 Hibernate SQL dialect 구성과 커넥션 프로퍼티들을 변경시키는 것에만 관계된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
먼저 우리는 모든 필수적인 라이브러리들을 Tomcat 설치 장소에 복사해야 한다. 우리는 이 튜토리얼을 위해 별도의
|
||||
웹 컨텍스트(<literal>webapps/quickstart</literal>)를 사용하며, 따라서 우리는 전역 라이브러리 검색 경로
|
||||
(<literal>TOMCAT/common/lib</literal>)와 <literal>webapps/quickstart/WEB-INF/lib</literal>
|
||||
(JAR 파일들의 경우)와 <literal>webapps/quickstart/WEB-INF/classes</literal> 내 에 있는 컨텍스트
|
||||
레벨에서 클래스로더 양자를 고려해야 한다. 우리는 두 개의 클래스로더 레벨들을 전역 classpath와 컨텍스트
|
||||
classpath로서 언급한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이제 라이브러리들을 두 개의 classpath들에 복사하라:
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
데이터베이스 용 JDBC 드라이버를 전역 classpath로 복사하라. 이것은 Tomcat에 번들로구성된 DBCP 커넥션
|
||||
풀 소프트웨어에 필요하다. Hibernate는 데이터베이스 상에서 SQL을 실행시키는데 JDBC 커넥션들을 사용하므로,
|
||||
당신은 풀링된 JDBC 커넥션들을 제공해야 하거나, 직접 지원되는 풀들(C3P0, Proxool) 중 하나를 사용하기
|
||||
위해 Hibernate를 구성해야 한다. 이 튜토리얼을 위해, (PostgreSQL 7.4와 JDK 1.4용) <literal>pg74jdbc3.jar</literal>
|
||||
라이브러리를 전역 classloaders 경로로 복사하라. 만일 당신이 다른 데이터베이스를 사용하고자 원할 경우,
|
||||
간단하게 그것의 적절한 JDBC 드라이버를 복사하라.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
그 밖의 어떤 것을 Tomcat 내의 전역 클래스로더 경로에 복사하지 말라. 또는 당신은 Log4j, commons-logging
|
||||
그리고 다른 것들을 포함하는 여러 가지 도구들에 관련된 문제점들을 얻게 될 것이다. 각각의 웹 어플리케이션에 대해
|
||||
컨텍스트 classpath를 사용하라. 즉 라이브러리들을 <literal>WEB-INF/lib</literal>에 복사하고, 당신 자신의 클래스들과
|
||||
구성 파일들/프로퍼티 파일들을 <literal>WEB-INF/classes</literal>에 복사하라. 두 디렉토리들 양자는 디폴트로 컨텍스트
|
||||
classpath 내에 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate는 JAR 라이브러리로서 패키지화 되어 있다. <literal>hibernate3.jar</literal> 파일은 어플리케이션의 다른 클래스들과
|
||||
함께 컨텍스트 classpath 속에 복사되어야 한다. Hibernate는 실행 시에 어떤 제 3의 라이브러리들을 필요로하고,
|
||||
이것들은 <literal>lib/</literal> 디렉토리 내의 Hibernate 배포본에 번들화되어 있다; <xref linkend="3rdpartylibs"/>를
|
||||
보라. 필요한 제3의 라이브러리들을 컨텍스트 classpath로 복사하라.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<table frame="topbot" id="3rdpartylibs">
|
||||
<title>
|
||||
Hibernate 제3의 라이브러리
|
||||
</title>
|
||||
<tgroup cols="2" rowsep="1" colsep="1">
|
||||
<colspec colname="c1" colwidth="1*"/>
|
||||
<colspec colname="c2" colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry align="center">
|
||||
라이브러리
|
||||
</entry>
|
||||
<entry align="center">
|
||||
설명
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>
|
||||
antlr (필수)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 질의 파서들을 산출하는데 ANTLR을 사용하고, 이 라이브러리는 또한
|
||||
실행 시에 필요하다.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
dom4j (필수)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 XML 구성과 XML 매핑 메타데이터 파일들을 파싱하는데 dom4j를 사용
|
||||
한다.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
CGLIB, asm (필수)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 (Java reflection과 결합하여) 런타임 시에 클래스들을 고양시키는데
|
||||
코드 생성 라이브러리를 사용한다.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
Commons Collections, Commons Logging (필수)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 Apache Jakarta Commons 프로젝트로부터 다양한 유틸리티 라이브러리
|
||||
들을 사용한다.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
EHCache (필수)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 second-level 캐시를 위한 다양한 캐시 프로바이더들을 사용할 수 있다.
|
||||
만일 구성에서 변하지 않을 경우 EHCache가 디폴트 캐시 프로바이더이다.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
Log4j (옵션)
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate는 기본 로깅 메커니즘으로서 Log4j를 사용할 수 있는, Commons Logging
|
||||
API를 사용한다. 만일 Log4j 라이브러리가 컨텍스트 라이브러리 디렉토리 속에서 이용
|
||||
가능하다면, Commons Logging은 Log4j와 컨텍스트 classpath 내에 있는 <literal>log4j.properties</literal>
|
||||
구성을 사용할 것이다. Log4j에 대한 예제 properties 파일은 Hibernate 배포본에
|
||||
번들화 되어 있다. 따라서 당신이 이면에서 무엇이 진행되는 지을 보고자 원할 경우에 log4j.jar와
|
||||
(<literal>src/</literal>에 있는) 구성 파일을 당신의 컨텍스트 classpath 속으로 복사하라.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
필수 여부?
|
||||
</entry>
|
||||
<entry>
|
||||
Hibernate 배포본 내에 있는 <literal>lib/README.txt</literal> 파일을 살펴보라.
|
||||
이것은 Hibernate에 배포된 제 3의 라이브러리들의 최신 목록이다. 당신은 그곳에 열거된
|
||||
모든 필수 라이브러리들과 옵션 라이브러리들을 찾게 될 것이다(여기서 "빌드 시 필요함"은
|
||||
당신의 어플리케이션이 아니라 Hibernate에 대한 의미임을 노트하라).
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
우리는 이제 Tomcat과 Hibernate 양자에서 데이터베이스 커넥션 풀링과 공유를 설정한다. 이것은 Tomcat이
|
||||
(그것의 미리 빌드되어 있는 DBCP 풀링 특징을 사용하여) 풀링된 JDBC 커넥션들을 제공할 것이고, Hibernate가
|
||||
JNDI를 통해 이들 커넥션들을 요청한다는 것을 의미한다. 달리 당신은 Hibernate로 하여금 커넥션 풀을 관리하도록
|
||||
할 수 있다. Tomcat은 그것의 커넥션 풀을 JNDI에 바인드 시킨다; 우리는 리소스 선언을 Tomcat 메인 구성 파일인
|
||||
<literal>TOMCAT/conf/server.xml</literal>에 추가한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
|
||||
<Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
|
||||
<ResourceParams name="jdbc/quickstart">
|
||||
<parameter>
|
||||
<name>factory</name>
|
||||
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
|
||||
</parameter>
|
||||
|
||||
<!-- DBCP database connection settings -->
|
||||
<parameter>
|
||||
<name>url</name>
|
||||
<value>jdbc:postgresql://localhost/quickstart</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>driverClassName</name><value>org.postgresql.Driver</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>username</name>
|
||||
<value>quickstart</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>password</name>
|
||||
<value>secret</value>
|
||||
</parameter>
|
||||
|
||||
<!-- DBCP connection pooling options -->
|
||||
<parameter>
|
||||
<name>maxWait</name>
|
||||
<value>3000</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxIdle</name>
|
||||
<value>100</value>
|
||||
</parameter>
|
||||
<parameter>
|
||||
<name>maxActive</name>
|
||||
<value>10</value>
|
||||
</parameter>
|
||||
</ResourceParams>
|
||||
</Context>]]></programlisting>
|
||||
|
||||
<para>
|
||||
우리가 이 예제에서 구성하는 컨텍스트는 <literal>quickstart</literal>로 명명되고, 그것의 베이스는
|
||||
<literal>TOMCAT/webapp/quickstart</literal> 디렉토리이다. 임의의 서블릿들에 접근하기 위해,
|
||||
(물론 당신의 <literal>web.xml</literal> 속에 매핑된 서블릿의 이름을 추가하여) 당신의 브라우저에서
|
||||
<literal>http://localhost:8080/quickstart</literal> 경로를 호출하라. 당신은 또한 계속 진행하고
|
||||
이제 공백의 <literal>process()</literal> 메소드를 가진 간단한 서블릿을 생성시킬 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Tomcat은 이제 <literal>java:comp/env/jdbc/quickstart</literal>로 JNDI을 통해 커넥션들을 제공한다.
|
||||
만일 당신이 실행 중인 커넥션 풀을 얻는 것에 문제가 있다면 Tomcat 문서를 참조하라. 당신이 JDBC 드라이버 예외상황
|
||||
메시지를 얻을 경우, 먼저 Hibernate 없이 JDBC 커넥션 풀을 셋업하라. Tomcat & JDBC 튜토리얼들은
|
||||
그 웹 서이트에서 이용 가능하다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신의 다음 단계는 Hibernate를 구성하는 것이다. Hibernate는 그것이 JDBC 커넥션들을 얻는 방법을 알고 있어야 한다.
|
||||
우리는 Hibernate의 XML 기반 구성을 사용한다. properties 파일을 사용하는 다른 접근법은 거의 동일하지만 XML
|
||||
구문이 허용하는 몇몇 특징들을 누락하고 있다. XML 구성 파일은 <literal>hibernate.cfg.xml</literal>로서
|
||||
컨텍스트 classpath (<literal>WEB-INF/classes</literal>) 내에 위치해 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
|
||||
<!DOCTYPE hibernate-configuration PUBLIC
|
||||
"-//Hibernate/Hibernate Configuration DTD//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
|
||||
|
||||
<hibernate-configuration>
|
||||
|
||||
<session-factory>
|
||||
|
||||
<property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
|
||||
<property name="show_sql">false</property>
|
||||
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
|
||||
|
||||
<!-- Mapping files -->
|
||||
<mapping resource="Cat.hbm.xml"/>
|
||||
|
||||
</session-factory>
|
||||
|
||||
</hibernate-configuration>]]></programlisting>
|
||||
|
||||
<para>
|
||||
우리는 SQL 명령들에 대한 로깅을 사용하지 않고 Hibernate에게 사용되는 데이터베이스 SQL direct가 무엇인지
|
||||
그리고 (Tomcat 바인드된 풀의 JNDI 주소를 선언하여) JDBC 커넥션들을 얻는 곳을 알려준다. dialect는
|
||||
필수적인 설정이고, 데이터베이스들은 SQL "표준"에 대한 그것들의 해석을 달리한다. Hibernate는 차이점들을
|
||||
처리하고 모든 주요 상용 데이터베이스들 및 오픈 소스 데이터베이스들 용도의 direct들을 번들로 포함하고 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal>는 단일 데이터저장소에 관한 개념이고, 여러 데이터베이스들은 여러
|
||||
개의 XML 구성 파일들을 생성시키고 당신의 어플리케이션 속에서 여러 개의 <literal>Configuration</literal>
|
||||
및 <literal>SessionFactory</literal> 객체들을 생성시켜서 사용될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>hibernate.cfg.xml</literal>의 마지막 요소는 영속 클래스 <literal>Cat</literal>에 대한
|
||||
Hibernate XML 매핑 파일의 이름으로써 <literal>Cat.hbm.xml</literal>을 선언한다. 이 파일은 데이터베이스
|
||||
테이블(또는 테이블들)로 POJO 클래스 <literal>Cat</literal> 을 매핑시키는 메타데이터를 포함한다. 우리는
|
||||
곧 그 파일로 되돌아 갈 것이다. 먼저 POJO 클래스를 작성하고 그런 다음 그것을 위한 매핑 메타데이터를 선언하자.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="quickstart-persistentclass" revision="1">
|
||||
<title>첫 번째 영속 클래스</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 영속 클래스들에 대한 Plain Old Java Objects (POJOs, 종종 Plain Ordinary Java Objects로
|
||||
명명된다) 프로그래밍 모형으로 가장 잘 동작한다. POJO는 공용으로 가시적인 인터페이스로부터 내부적인 표상을 은폐시켜,
|
||||
getter와 setter 메소드들을 통해 접근가능한 클래스들의 프로퍼티들을 가진 자바빈과 꽤 유사하다(필요하다면 Hibernate는
|
||||
또한 필드들에 직접 접근할 수 있다):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package org.hibernate.examples.quickstart;
|
||||
|
||||
public class Cat {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private char sex;
|
||||
private float weight;
|
||||
|
||||
public Cat() {
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(char sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public void setWeight(float weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate는 그것의 프로퍼티 타입들의 사용에 제약되지 않고, 자바 콜렉션 프레임웍에서의 클래스들을 포함하여, 모든
|
||||
자바 JDK 타입들과 (<literal>String</literal>, <literal>char</literal>와 <literal>Date</literal>
|
||||
같은) 원시타입들이 매핑될 수 있다. 당신은 그것을 값들로서, 값들을 가진 콜렉션들로서, 또는 다른 엔티티들에 대한
|
||||
연관들로서 매핑시킬 수 있다. <literal>id</literal>는 그 클래스의 데이터베이스 식별자(프라이머리 키)를 표현하는
|
||||
특별한 프로퍼티이고, 그것은 <literal>Cat</literal>과 같은 엔티티들에 대해 매우 권장된다. Hibernate는 내부적으로만
|
||||
식별자들을 사용할 수 있지만, 우리는 우리의 어플리케이션 아키텍처에서 어떤 유연성을 상실하게 될 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
특정 인터페이스는 영속 클래스들에 대해 구현되지 말아야 하거나 특정 루트 영속 클래스로부터 서브 클래스로 만들지 말아야 한다.
|
||||
Hibernate는 또한 바이트 코드 처리와 같은, 어떤 빌드 시 처리를 필요로 하지 않고, 그것은 오직 자바 reflection과
|
||||
(CGLIB를 통한) 런타임 클래스 고양에만 의존한다. 따라서 Hibernate에 대한 POJO 클래스의 어떤 의존성 없이도, 우리는
|
||||
그것을 데이터베이스 테이블로 매핑할 수 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="quickstart-mapping" revision="1">
|
||||
<title>cat 매핑하기</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat.hbm.xml</literal> 매핑파일은 객체/관계형 매핑에 필요한 메타데이터를 포함한다. 메타데이터는 영속
|
||||
클래스들의 선언과 데이터베이스 테이블들에 대한 (컬럼들과 다른 엔티티들에 대한 foreign 키 관계들에 대한) 프로퍼티들의
|
||||
매핑을 포함한다.
|
||||
</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">
|
||||
|
||||
<hibernate-mapping>
|
||||
|
||||
<class name="org.hibernate.examples.quickstart.Cat" table="CAT">
|
||||
|
||||
<!-- A 32 hex character is our surrogate key. It's automatically
|
||||
generated by Hibernate with the UUID pattern. -->
|
||||
<id name="id" type="string" unsaved-value="null" >
|
||||
<column name="CAT_ID" sql-type="char(32)" not-null="true"/>
|
||||
<generator class="uuid.hex"/>
|
||||
</id>
|
||||
|
||||
<!-- A cat has to have a name, but it shouldn' be too long. -->
|
||||
<property name="name">
|
||||
<column name="NAME" length="16" not-null="true"/>
|
||||
</property>
|
||||
|
||||
<property name="sex"/>
|
||||
|
||||
<property name="weight"/>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
모든 영속 클래스는 식별자 속성을 가져야 한다(실제로 value-타입의 클래스들에 의존하지 않는, 엔티티들을 표현하는 유일한
|
||||
클래스들은 엔티티을 가진 컴포넌트들로 매핑된다). 이 프로퍼티는 영속 객체들을 구별짓는데 사용된다: 만일
|
||||
<literal>catA.getId().equals(catB.getId())</literal>가 true일 경우, 두 개의 cat들은 같고, 이 개념은
|
||||
<emphasis>database identity</emphasis>로 명명된다. Hibernate는 (데이터베이스 시퀀스, hi/lo 식별자 테이블들,
|
||||
그리고 어플리케이션 할당 식별자들에 대한 native 생성기들을 포함하는) 다른 시나리오들에 대해 여러 가지 식별자 생성기들을
|
||||
번들로 갖고 있다. 우리는 UUID 생성기(데이터이스에 의해 생성된 정수 대용 키들이 선호될 것이므로, 테스트용으로만 권장됨)를
|
||||
사용하고 또한 Hibernate 생성된 식별자 값을 위한 <literal>CAT</literal> 테이블의 <literal>CAT_ID</literal>
|
||||
컬럼을 (테이블의 프라이머리 키로서) 지정한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal>의 모든 다른 프로퍼티들은 동일한 테이블로 매핑된다. <literal>name</literal> 프로퍼티의 경우에,
|
||||
우리는 그것을 명시적인 데이터베이스 컬럼 선언으로 매핑시켰다. 데이터베이스 스키마가 Hibernate의 <emphasis>SchemaExport</emphasis>
|
||||
도구에 의해 매핑 선언으로부터 (SQL DDL 문장들로) 자동적으로 생성될 때 이것이 특별히 유용하다. 모든 다른 프로퍼티들은
|
||||
Hibernate의 디폴트 설정들을 사용하여 매핑되고, 디폴트 설정들은 당신이 가장 많은 시간을 필요로 하는 것이다. 데이터베이스
|
||||
내의 테이블 <literal>CAT</literal>은 다음과 같다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[ Column | Type | Modifiers
|
||||
--------+-----------------------+-----------
|
||||
cat_id | character(32) | not null
|
||||
name | character varying(16) | not null
|
||||
sex | character(1) |
|
||||
weight | real |
|
||||
Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 이제 수작업으로 당신의 데이터베이스 내에 이 테이블을 생성시킬 것이고, 만일 당신이 <literal>hbm2ddl</literal>
|
||||
도구로 이 단계를 자동화 시키고자 원할 경우 <xref linkend="toolsetguide"/>를 읽어라. 이 도구는 테이블 정의, 맞춤형
|
||||
컬럼 타입 컨스트레인트들, 유일 컨스트레인트들과 인덱스들을 포함하는, 전체 SQL DDL을 생성시킬 수 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="quickstart-playingwithcats" revision="2">
|
||||
<title>cat들에 작업하기</title>
|
||||
|
||||
<para>
|
||||
우리는 이제 Hibernate의 <literal>Session</literal>을 시작할 준비가 되어 있다. 그것은 <emphasis>persistence manager</emphasis>
|
||||
(영속 관리자)이고, 우리는 데이터베이스로 <literal>Cat</literal>들을 저장하고 데이터베이스로부터
|
||||
<literal>Cat</literal>들을 검색하는데 그것을 사용한다. 그러나 먼저 우리는 <literal>SessionFactory</literal>로부터
|
||||
<literal>Session</literal>(Hibernate의 작업 단위)를 얻어야 한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[SessionFactory sessionFactory =
|
||||
new Configuration().configure().buildSessionFactory();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>configure()</literal> 호출은 <literal>hibernate.cfg.xml</literal> 구성 파일을 로드시키고
|
||||
<literal>Configuration</literal> 인스턴스를 초기화 시킨다. 당신이 SessionFactory(불변적임)를 빌드하기
|
||||
<emphasis>이전에</emphasis> 당신은 <literal>Configuration</literal>에 접근함으로써 다른 프로퍼티들을
|
||||
설정할 수 있다(그리고 심지어 매핑 메타데이터를 변경시킬 수 있다). 우리는 어디서 <literal>SessionFactory</literal>를
|
||||
생성시키고 우리의 어플리케이션 속에서 어떻게 그것에 접근할 수 있나?
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal>는 대개 오직 한번만, 예를 들어 대개 <emphasis>load-on-startup</emphasis>
|
||||
서블릿으로 시작 시에 빌드된다. 이것은 또한 당신이 당신의 서블릿들 내에 있는 인스턴스 변수 속에 그것을 유지하지 않을 것이지만
|
||||
어떤 다른 위치에 유지시킬 것임을 의미한다. 더구나 우리는 어떤 종류의 <emphasis>Singleton</emphasis>을 필요로 하며,
|
||||
따라서 우리는 어플리케이션 코드로 쉽게 <literal>SessionFactory</literal>에 액세스 할 수 있다. 다음에 보여진 접근법은
|
||||
두 문제 모두를 해결한다: 시작 구성과 <literal>SessionFactory</literal>에 대한 쉬운 접근.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 <literal>HibernateUtil</literal> helper 클래스를 구현한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[import org.hibernate.*;
|
||||
import org.hibernate.cfg.*;
|
||||
|
||||
public class HibernateUtil {
|
||||
|
||||
private static Log log = LogFactory.getLog(HibernateUtil.class);
|
||||
|
||||
private static final SessionFactory sessionFactory;
|
||||
|
||||
static {
|
||||
try {
|
||||
// Create the SessionFactory
|
||||
sessionFactory = new Configuration().configure().buildSessionFactory();
|
||||
} catch (Throwable ex) {
|
||||
// Make sure you log the exception, as it might be swallowed
|
||||
log.error("Initial SessionFactory creation failed.", ex);
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static final ThreadLocal session = new ThreadLocal();
|
||||
|
||||
public static Session currentSession() {
|
||||
Session s = (Session) session.get();
|
||||
// Open a new Session, if this Thread has none yet
|
||||
if (s == null) {
|
||||
s = sessionFactory.openSession();
|
||||
session.set(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void closeSession() {
|
||||
Session s = (Session) session.get();
|
||||
if (s != null)
|
||||
s.close();
|
||||
session.set(null);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 클래스는 static 초기자를 가진 <literal>SessionFactory</literal>를 처리할 뿐만 아니라 또한 현재의 쓰레드를
|
||||
위한 <literal>Session</literal>을 소유하는 <literal>ThreadLocal</literal> 변수를 갖는다. 이 helper를
|
||||
사용하려고 시도하기 전에 thread-local 변수에 대한 자바 개념을 이해해야 한다. 보다 복잡하고 강력한 <literal>HibernateUtil</literal>
|
||||
클래스는 http://caveatemptor.hibernate.org/의 <literal>CaveatEmptor</literal>에서 찾을 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal>는 threadsafe이고, 많은 쓰레드들이 동시에 그것에 접근할 수 있고
|
||||
<literal>Session</literal>들을 요청할 수 있다. 하나의 <literal>Session</literal>은 데이터베이스에 대해
|
||||
한 개의 단위 작업을 나타내는 non-threadsafe 객체이다. <literal>Session</literal>들은 <literal>SessionFactory</literal>
|
||||
로부터 열려지고 모든 작업이 완료될 때 닫혀진다. 당신의 서블릿의 <literal>process()</literal> 메소드 내에 있는
|
||||
예제는 다음과 같을 수 있다(예외상황 처리 없이):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = HibernateUtil.currentSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
Cat princess = new Cat();
|
||||
princess.setName("Princess");
|
||||
princess.setSex('F');
|
||||
princess.setWeight(7.4f);
|
||||
|
||||
session.save(princess);
|
||||
|
||||
tx.commit();
|
||||
HibernateUtil.closeSession();]]></programlisting>
|
||||
|
||||
<para>
|
||||
하나의 <literal>Session</literal> 내에서 모든 데이터베이스 오퍼레이션은 데이터베이스 오퍼레이션들(심지어 읽기 전용
|
||||
오퍼레이션들 조차도)을 격리시키는 하나의 트랜잭션 내부에서 발생한다. 우리는 기본 트랜잭션 방도(우리의 경우, JDBC
|
||||
트랜잭션들)로부터 추상화시키는데 Hibernates <literal>Transaction</literal> API 를 사용한다. 이것은 우리의
|
||||
코드가 임의의 변경들 없이도 (JTA를 사용하는) 컨테이너-관리되는 트랜잭션들에 배치되는 것을 허용해준다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신이 원하는 만큼 당신이 <literal>HibernateUtil.currentSession();</literal>을 호출할 수 있고, 당신은
|
||||
이 쓰레드의 현재 <literal>Session</literal>을 항상 얻을 것임을 노트하라. 당신은 서블릿 코드 내에서든 또는 서블릿 필터
|
||||
내에서든 HTTP response가 전송되기 전에, 당신의 단위 작업이 완료된 후에 <literal>Session</literal>이 확실히
|
||||
닫혀지도록 해야 한다. 두 번째 옵션의 좋은 측면은 쉬운 lazy 초기화이다: 뷰가 렌더링 될 때 <literal>Session</literal>이
|
||||
여전히 열려져 있어서, Hibernate는 당신이 현재 객체 그래프를 네비게이트 하는 동안 초기화 되지 않은 객체들을 로드시킬 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 데이터베이스로부터 객체들을 검색하는데 사용될 수 있는 다양한 메소드들을 갖고 있다. 가장 유연한 방법은 Hibernate
|
||||
Query Language (HQL)을 사용하는 것이다. Hibernate Query Language (HQL)은 배우기가 쉽고 SQL에 대한 강력한 객체 지향
|
||||
확장이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Transaction tx = session.beginTransaction();
|
||||
|
||||
Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
|
||||
query.setCharacter("sex", 'F');
|
||||
for (Iterator it = query.iterate(); it.hasNext();) {
|
||||
Cat cat = (Cat) it.next();
|
||||
out.println("Female Cat: " + cat.getName() );
|
||||
}
|
||||
|
||||
tx.commit();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernate는 또한 type-safe 질의들을 공식화 시키는데 사용될 수 있는 객체-지향 <emphasis>query by criteria</emphasis>
|
||||
API을 제공한다. 물론 Hibernate는 데이터베이스와의 모든 SQL 통신을 위해 <literal>PreparedStatement</literal>들과
|
||||
파라미터 바인딩을 사용한다. 당신은 또한 Hibernate 직접적인 SQL 질의 특징을 사용할 수도 있거나 드문 경우에
|
||||
<literal>Session</literal>으로부터 plain JDBC 커넥션을 얻을 수도 있다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="quickstart-summary" revision="1">
|
||||
<title>마지막으로</title>
|
||||
|
||||
<para>
|
||||
우리는 이 작은 튜토리얼 내에서 단지 Hibernate의 표면을 훑기만 했다. 우리는 우리의 예제들 속에 어떤 서블릿 지정적 코드를
|
||||
포함하지 않음을 노트하라. 당신이 적합한지를 알려고 할 때 당신은 당신 자신의 서블릿을 생성시켜야 하고 Hibernate 코드를
|
||||
삽입해야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
데이터 접근 계층으로서 Hibernate는 당신의 어플리케이션에 강하게 통합됨을 염두에 두라. 대개 모든 다른 레이어들은 영속
|
||||
메커니즘에 의존했다. 당신은 이 설계의 함축을 확실히 이해하도록 하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
보다 복잡한 어플리케이션 예제는 http://caveatemptor.hibernate.org/ 를 보고 http://caveatemptor.hibernate.org/에
|
||||
있는 다른 튜토리얼들을 살펴보라.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
1115
reference/ko/modules/session_api.xml
Normal file
444
reference/ko/modules/toolset_guide.xml
Normal file
@ -0,0 +1,444 @@
|
||||
<chapter id="toolsetguide" revision="2">
|
||||
<title>도구셋 안내</title>
|
||||
|
||||
<para>
|
||||
Hibernate에 대한 라운드트립 엔지니어링은 Eclipse 플러그인 세트, 명령라인 도구들, 뿐만 아니라 Ant 태스크들을 사용하여 가능하다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Hibernate 도구들</emphasis>은 현재 기존 데이터베이스들에 대한 리버스 엔지니어링을 위해 Ant 태스크들 뿐만 아니라
|
||||
Eclipse IDE용 플러그인들을 포함하고 있다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>매핑 편집기:</emphasis> 자동 완성 기능과 구문 강조를 지원하는 Hibernate XML 매핑 파일들에 대한 편집기. 그것은 또한
|
||||
통상의 XML 편집기 보다 훨씬 더 융통성 있게 만들어서 클래스 이름들과 프로퍼티/필드 이름들에 대한 의미론적 자동 완성 기능을 지원한다.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>콘솔:</emphasis> 콘솔은 Eclipse에서 새로운 뷰이다. 당신의 콘솔 구성들에 대한 tree overview에 덧붙여, 당신은 또한
|
||||
당신의 영속 클래스들과 그것들의 관계들에 대한 상호작용 뷰를 얻는다. 콘솔은 당신의 데이터베이스에 대해 HQL 질의들을 실행하고 그 결과를
|
||||
Eclipse 내에서 직접 브라우징 하도록 당신에게 허용해준다.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>개발 마법사들:</emphasis> 몇몇 마법사들이 Hibernate Eclipse 도구들에 제공된다; 당신은 Hibernate 구성
|
||||
(cfg.xml) 파일들을 빠르게 생성시키는데 마법사를 사용하거나, 심지어 당신은 기존 데이터베이스 스키마를 POJO 소스 파일들과
|
||||
Hibernate 매핑 파일들로 완전하게 리버스 엔지니어링할 수도 있다. 리버스 엔지니어링 마법사는 맞춤 가능한 템플릿들을 제공한다.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Ant 태스크들:</emphasis>
|
||||
</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
추가 정보는 <emphasis>Hibernate Tools</emphasis> 패키지와 그것의 문서를 참조하길 바란다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하지만 Hibernate 메인 패키지는 통합 도구에 번들화 되어 있다(그것은 심지어 플라이 상에서 Hibernate "내에서" 사용될 수 있다):
|
||||
<emphasis>SchemaExport</emphasis> 별칭은 <literal>hbm2ddl</literal>.
|
||||
</para>
|
||||
|
||||
<sect1 id="toolsetguide-s1" revision="2">
|
||||
<title>자동적인 스키마 생성</title>
|
||||
|
||||
<para>
|
||||
DDL은 Hibernate 유틸리티에 의해 당신의 매핑 파일들로부터 생성될 수 있다. 생성된 스키마는 엔티티 테이블과 콜렉션 테이블에 대한
|
||||
참조 무결성 컨스트레인트들(프라이머리 키와 foreign 키들)을 포함한다. 테이블들과 시퀀스들은 또한 페칭된 식별자 생성기들에 대해
|
||||
생성된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
DDL이 매우 벤더에 특정하므로, 이 도구를 사용할 때 당신은 <literal>hibernate.dialect</literal> 프로퍼티를 통해 한 개의 SQL
|
||||
<literal>Dialect</literal>를 지정<emphasis>해야 한다</emphasis>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
먼저 생성된 스키마를 개선시키기 위해 당신의 매핑 파일들을 맞춤화 시켜라.
|
||||
</para>
|
||||
|
||||
<sect2 id="toolsetguide-s1-2" revision="1">
|
||||
<title>스키마 맞춤화 시키기</title>
|
||||
|
||||
<para>
|
||||
많은 Hibernate 매핑 요소들은 <literal>length</literal>로 명명된 옵션 속성을 정의한다. 당신은 이 속성으로 컬럼의 길이를
|
||||
설정할 수 있다.(또는 numeric/decimal 데이터 타입들, 배정도에 대해 ).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
몇몇 태그들은 또한 (테이블 컬럼들에 대한 <literal>NOT NULL</literal> 컨스트레인트를 생성시키는) <literal>not-null</literal>
|
||||
속성과 (테이블 컬럼들에 대한 <literal>UNIQUE</literal> 컨스트레인트를 생성시키는) <literal>unique</literal> 속성을 수용한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
몇몇 태그들은 그 컬럼에 대한 인덱스의 이름을 지정하는 <literal>index</literal> 속성을 허용한다. <literal>unique-key</literal>
|
||||
속성은 하나의 단위 키 컨스트레인트로 컬럼들을 그룹지우는데 사용될 수 있다. 현재 <literal>unique-key</literal> 속성의
|
||||
지정된 값은 컨스트레인트를 명명하는데 사용되지 <emphasis>않고</emphasis>, 오직 매핑 파일 내에서 컬럼들을 그룹 지우는데
|
||||
사용된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
예제들:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="foo" type="string" length="64" not-null="true"/>
|
||||
|
||||
<many-to-one name="bar" foreign-key="fk_foo_bar" not-null="true"/>
|
||||
|
||||
<element column="serial_number" type="long" not-null="true" unique="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
다른 방법으로, 이들 요소들은 또한 자식 <literal><column></literal> 요소를 수용한다. 이것은 다중 컬럼 타입들에
|
||||
특히 유용하다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="foo" type="string">
|
||||
<column name="foo" length="64" not-null="true" sql-type="text"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<property name="bar" type="my.customtypes.MultiColumnType"/>
|
||||
<column name="fee" not-null="true" index="bar_idx"/>
|
||||
<column name="fi" not-null="true" index="bar_idx"/>
|
||||
<column name="fo" not-null="true" index="bar_idx"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>sql-type</literal> 속성은 SQL 데이터타입에 대한 Hibernate 타입의 디폴트 매핑을 오버라이드 시키는 것을
|
||||
사용자에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>check</literal> 속성은 check 컨스트레인트를 지정하는 것을 당신에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="foo" type="integer">
|
||||
<column name="foo" check="foo > 10"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
|
||||
...
|
||||
<property name="bar" type="float"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
|
||||
<table frame="topbot" id="schemattributes-summary" revision="2">
|
||||
<title>요약</title>
|
||||
<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><literal>length</literal></entry>
|
||||
<entry>number</entry>
|
||||
<entry>컬럼 길이/decimal 배정도</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>not-null</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>컬럼이 null이 아니어야 함을 지정한다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>컬럼이 하나의 유일 컨스트레인트를 가져야함을 지정한다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>index</literal></entry>
|
||||
<entry><literal>index_name</literal></entry>
|
||||
<entry>(다중-컬럼) 인덱스의 이름을 지정한다 </entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique-key</literal></entry>
|
||||
<entry><literal>unique_key_name</literal></entry>
|
||||
<entry>다중-컬럼 유일 컨스트레인트의 이름을 지정한다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>foreign-key</literal></entry>
|
||||
<entry><literal>foreign_key_name</literal></entry>
|
||||
<entry>
|
||||
하나의 연관에 대해 생성된 foreign key 컨스트레인트의 이름을 지정하고,
|
||||
<one-to-one>, <many-to-one>, <key>, and <many-to-many>
|
||||
매핑 요소들 상에 그것을 사용한다. <literal>inverse="true"</literal> 측들은
|
||||
<literal>SchemaExport</literal>에 의해 고려되지 않을 것임을 노트하라.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>sql-type</literal></entry>
|
||||
<entry><literal>column_type</literal></entry>
|
||||
<entry>
|
||||
디폴트 컬럼 타입을 오버라이드 시킨다
|
||||
(<literal><column></literal> 요소의 속성에만)
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>check</literal></entry>
|
||||
<entry>SQL expression</entry>
|
||||
<entry>
|
||||
컬럼 또는 테이블에 대한 SQL check 컨스트레인트를 생성시킨다
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
<literal><comment></literal> 요소는 생성된 스키마에 대한 주석들을 지정하는 것을 당신에게 허용해준다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Customer" table="CurCust">
|
||||
<comment>Current customers only</comment>
|
||||
...
|
||||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<property name="balance">
|
||||
<column name="bal">
|
||||
<comment>Balance in USD</comment>
|
||||
</column>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이것은 (지원되는 경우) 생성된 DDL에서 <literal>comment on table</literal> 또는
|
||||
<literal>comment on column</literal> 문장으로 귀결된다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-3">
|
||||
<title>도구 실행하기</title>
|
||||
|
||||
<para>
|
||||
<literal>SchemaExport</literal> 도구는 DDL 스크립트를 표준 출력으로 기록 하고/하거나 DDL 문장들을 실행시킨다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
|
||||
<literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title><literal>SchemaExport</literal> 명령 라인 옵션들</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>옵션</entry>
|
||||
<entry>설명</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>--quiet</literal></entry>
|
||||
<entry>스크립트를 표준출력으로 출력하지 않는다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--drop</literal></entry>
|
||||
<entry>오직 테이블들을 드롭시킨다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--text</literal></entry>
|
||||
<entry>데이터베이스로 내보내기 하지 않는다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--output=my_schema.ddl</literal></entry>
|
||||
<entry>ddl 스크립트를 파일로 출력한다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
|
||||
<entry>XML 파일로부터 Hibernate 구성을 읽어들인다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
||||
<entry>파일로부터 데이터베이스 프로퍼티들을 읽어들인다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--format</literal></entry>
|
||||
<entry>생성된 SQL을 스크립트 내에 좋게 형식지운다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--delimiter=x</literal></entry>
|
||||
<entry>스크립트를 위한 라인 경계의 끝을 설정한다 </entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
당신은 당신의 어플리케이션 내에 <literal>SchemaExport</literal>를 삽입시킬 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
new SchemaExport(cfg).create(false, true);]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-4">
|
||||
<title>프로퍼티들</title>
|
||||
|
||||
<para>
|
||||
데이터베이스 프로퍼티들은 다음과 같이 지정될 수 있다
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>-D</literal><emphasis><property></emphasis>를 가진 시스템 프로퍼티로서</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>hibernate.properties</literal> 내에서</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>--properties</literal>를 가진 명명된 프로퍼티들 내에서</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
필요한 프로퍼티들은 다음과 같다:
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title>SchemaExport 커넥션 프로퍼티들</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>프로퍼티 이름</entry>
|
||||
<entry>설명</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.driver_class</literal></entry>
|
||||
<entry>jdbc 드라이버 클래스</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.url</literal></entry>
|
||||
<entry>jdbc url</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.username</literal></entry>
|
||||
<entry>데이터베이스 사용자</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.connection.password</literal></entry>
|
||||
<entry>사용자 패스워드</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>hibernate.dialect</literal></entry>
|
||||
<entry>dialect</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-5">
|
||||
<title>Ant 사용하기</title>
|
||||
|
||||
<para>
|
||||
당신은 당신의 Ant 빌드 스크립트에서 <literal>SchemaExport</literal>를 호출할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="schemaexport">
|
||||
<taskdef name="schemaexport"
|
||||
classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
|
||||
classpathref="class.path"/>
|
||||
|
||||
<schemaexport
|
||||
properties="hibernate.properties"
|
||||
quiet="no"
|
||||
text="no"
|
||||
drop="no"
|
||||
delimiter=";"
|
||||
output="schema-export.sql">
|
||||
<fileset dir="src">
|
||||
<include name="**/*.hbm.xml"/>
|
||||
</fileset>
|
||||
</schemaexport>
|
||||
</target>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-6">
|
||||
<title>점증하는 스키마 업데이트들</title>
|
||||
|
||||
<para>
|
||||
<literal>SchemaUpdate</literal> 도구는 "점증하는" 변경들을 가진 기존 스키마를 변경시킬 것이다. <literal>SchemaUpdate</literal>는
|
||||
JDBC 메타데이터 API에 무겁게 의존하여서, 그것은 모든 JDBC 드라이버들에 동작하지 않을 것임을 주목하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis>
|
||||
<literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title><literal>SchemaUpdate</literal> 명령 라인 옵션들</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>옵션</entry>
|
||||
<entry>설명</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>--quiet</literal></entry>
|
||||
<entry>스크립트를 표준출력으로 출력하지 않는다</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>--properties=hibernate.properties</literal></entry>
|
||||
<entry>파일로부터 데이터베이스 프로퍼티들을 읽어 들인다</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
당신은 당신의 어플리케이션 내에 <literal>SchemaUpdate</literal>를 삽입시킬 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
new SchemaUpdate(cfg).execute(false);]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-7">
|
||||
<title>점증하는 스키마 업데이트들에 Ant 사용하기</title>
|
||||
|
||||
<para>
|
||||
당신은 Ant 스크립트에서<literal>SchemaUpdate</literal>를 호출할 수 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="schemaupdate">
|
||||
<taskdef name="schemaupdate"
|
||||
classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
|
||||
classpathref="class.path"/>
|
||||
|
||||
<schemaupdate
|
||||
properties="hibernate.properties"
|
||||
quiet="no">
|
||||
<fileset dir="src">
|
||||
<include name="**/*.hbm.xml"/>
|
||||
</fileset>
|
||||
</schemaupdate>
|
||||
</target>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
816
reference/ko/modules/transactions.xml
Normal file
@ -0,0 +1,816 @@
|
||||
<chapter id="transactions" revision="1">
|
||||
<title>트랜잭션들과 동시성</title>
|
||||
|
||||
<para>
|
||||
Hibernate와 동시성 제어에 대한 가장 중요한 점은 이해하기가 매우 쉽다는 점이다. Hibernate는 어떤 추가적인 잠금 행위 없이
|
||||
JDBC 커넥션들과 JTA 리소스들을 직접 사용한다. 우리는 당신의 데이터베이스 관리 시스템의 JDBC, ANSI, 그리고 트랜잭션 격리 명세에
|
||||
약간의 시간을 할애할 것을 매우 권장한다. Hibernate는 단지 자동적인 버전화를 추가하지만 메모리 내에서 객체들을 잠그지 않거나 당신의
|
||||
데이터베이스 트랜잭션들의 격리 레벨을 변경시키지 않는다. 기본적으로, 당신이 당신의 데이터베이스 리소스들에 직접 JDBC(또는 JTA/CMT)를
|
||||
사용하는 것처럼 Hibernate를 사용하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하지만, 자동적인 버전화에 덧붙여, Hibernate는 또한 <literal>SELECT FOR UPDATE</literal> 구문을 사용하여,
|
||||
행들에 대한 pessimistic 잠금을 위한 (마이너) API를 제공한다. 이 API는 이 장의 뒷 부분에서 논의된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
우리는 <literal>Configuration</literal>, <literal>SessionFactory</literal>, <literal>Session</literal>,
|
||||
알갱이를 가진 Hibernate에서의 동시성 제어 뿐만 아니라 데이터베이스 트랜잭션과 긴 어플리케이션 트랜잭션에 대한 논의를 시작한다.
|
||||
</para>
|
||||
|
||||
<sect1 id="transactions-basics">
|
||||
<title>세션 영역과 트랜잭션 영역</title>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal>는 모든 어플리케이션 쓰레드들에 의해 공유되도록 고안된 생성에 비용이 드는,
|
||||
쓰레드안전(threadsafe) 객체이다. 그것은 대개 어플리케이션 시작 시에 <literal>Configuration</literal> 인스턴스로부터
|
||||
한번 생성된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal>은 단일 비지니스 프로세스, 하나의 작업 단위를 위해 한번만 사용되고 나서 폐기될 예정인,
|
||||
비용이 들지 않는, 쓰레드 안전하지 않은 객체이다. <literal>Session</literal>은 그것이 필요하지 않으면 JDBC
|
||||
<literal>Connection</literal>(또는 <literal>Datasource</literal>)를 얻지 않을 것이어서, 데이터 접근이
|
||||
특별한 요청에 서비스할 필요가 있을 것이라고 당신이 확신하지 않을 경우에 당신은 <literal>Session</literal>을 안전하게
|
||||
열고 닫을 수 있다. (이것은 당신이 요청 인터셉션을 사용하여 다음 패턴들 중 어떤 것을 구현하자마자 중요하게 된다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 그림을 완성하기 위해 당신은 또한 데이터베이스 트랜재션들에 대해 생각해야 한다. 데이터베이스 트랜잭션은 데이터베이스에서
|
||||
잠금 다툼을 줄이기 위해 가능한 짧아야 한다. 긴 데이터베이스 트랜잭션들은 당신의 어플리케이션이 고도의 동시성 로드로의 가용성을
|
||||
높이는 것을 방해할 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하나의 작업 단위의 영역은 무엇인가? 하나의 Hibernate <literal>Session</literal>은 몇몇 데이터베이스 트랜잭션들에
|
||||
걸칠 수 있는가 또는 이것은 영역들의 one-to-one 관계인가? 당신은 언제 <literal>Session</literal>을 열고 닫는가
|
||||
그리고 당신은 데이터베이스 트랜잭션 경계들을 어떻게 한정하는가?
|
||||
</para>
|
||||
|
||||
<sect2 id="transactions-basics-uow">
|
||||
<title>작업 단위</title>
|
||||
|
||||
<para>
|
||||
첫번째로, <emphasis>session-per-operation</emphasis> anti-패턴을 사용하지 말라. 즉, 단일 쓰레드 내에서
|
||||
모든 간단한 데이터베이스 호출에 대해 <literal>Session</literal>을 열고 닫지 말라! 물론 같은 것이 데이터베이스
|
||||
트랜잭션들에 대해서도 참이다. 어플리케이션 내의 데이터베이스 호출들은 계획된 순서를사용하여 행해지며, 그것들은 원자
|
||||
작업 단위 속으로 그룹지워진다. (이것은 또한 모든 하나의 SQL 문장 뒤의 auto-commit(자동-커밋)이 어플리케이션 내에서
|
||||
무용지물임을 의미하고, 이 모드가 SQL 콘솔 작업을 돕도록 고안되었음을 노트하라. Hibernate는
|
||||
의미하고, 이 모드는 Hibernate는 즉시 자동-커밋 모드를 사용 불가능하게 하거나, 어플리케이션 서버가 그렇게 행하고,
|
||||
즉시 자동-커밋시키는 것을 사용불가능하게 하거나 ,그렇게 행하는 것을 기대한다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
다중 사용자 클라이언트/서버 어플리케이션에서 가장 공통된 패턴은 <emphasis>session-per-request</emphasis>이다.
|
||||
이 모형에서, 클라이언트로부터의 요청은 (Hibernate 영속 계층이 실행되는) 서버로 전송되고, 새로운 Hibernate
|
||||
<literal>Session</literal>이 열려지고, 모든 데이터베이스 오퍼레이션들이 이 작업 단위 내에서 실행된다. 일단 그 작업이
|
||||
완료되었다면(그리고 클라이언트에 대한 응답이 준비되었다면), 그 세션은 flush 되고 닫혀진다. 당신은 또한 당신이
|
||||
<literal>Session</literal>을 열고 닫을 때 그것을 시작하고 커밋시켜서 클라이언트 요청에 서비스하는데 한 개의 데이터베이스
|
||||
트랜잭션을 사용하게 될 것이다. 둘 사이의 관계는 일대일 대응이고 이 모형은 많은 어플리케이션들에서 완전하게 적합하다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
도전점은 구현에 놓여있다: <literal>Session</literal>과 트랜잭션이 정확하게 시작되고 끝나야 할 뿐만 아니라, 그것들은
|
||||
또한 데이터 접근 오퍼레이션들에 대해 접근 가능해야 한다. 작업의 단위에 대한 경계 구분은 하나의 요청이 서버에 도착하고
|
||||
응답이 전송되기 전에 실행되는 인터셉터(예를 들면 <literal>ServletFilter</literal>)를 사용하여 이상적으로 구현된다.
|
||||
우리는 하나의 <literal>ThreadLocal</literal> 변수를 사용하여 그 <literal>Session</literal>을 요청에 서비스하는
|
||||
쓰레드에 바인드 시킬 것을 권장한다. 이것은 이 쓰레드 내에서 실행되는 모든 코드에서 (static 변수에 접근하는 것처럼) 쉽게
|
||||
접근을 허용해준다. 당신이 선택하는 데이터베이스 트랜잭션 경계 구분 메커니즘에 따라, 당신은 또한 <literal>ThreadLocal</literal>
|
||||
변수 내에 트랜잭션 컨텍스트를 유지할 수도 있다. 이것을 위한 구현 패턴들은<emphasis>ThreadLocal Session</emphasis>
|
||||
및 <emphasis> 뷰 내의 Open Session</emphasis>으로 알려져 있다. 당신은 이것을 구현하기 위해 이 문서의 앞 쪽에 보였던
|
||||
<literal>HibernateUtil</literal> helper 클래스를 쉽게 확장할 수 있다. 물론 당신은 당신의 환경에서 인터셉터를 구현하고 그것을
|
||||
설정하는 방법을 찾아야 한다. 팁들과 예제들은 Hibernate 웹 사이트를 보라.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-basics-apptx">
|
||||
<title>어플리케이션 트랜잭션들</title>
|
||||
|
||||
<para>
|
||||
session-per-request 패턴은 당신이 작업 단위들을 설계하는데 사용할 수 있는 유일한 유용한 개념이 아니다. 많은 비지니스
|
||||
프로세스들은 데이터베이스 접근들을 중재하는 사용자 사이의 전체 일련의 상호작용들을 필요로 한다. 웹과 엔터프라이즈
|
||||
어플리케이션에서 사용자 상호작용에 걸치는 것은 데이터베이스 트랜잭션에 허용되지 않는다. 다음 예제를 검토하자:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
대화상자의 첫 번째 화면이 열리고, 사용자에게 보여진 데이터는 특정 <literal>Session</literal>과 데이터베이스
|
||||
트랜잭션 속에 로드되었다. 사용자가 객체들을 변경시키는 것이 자유롭다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
|
||||
사용자는 5분 후에 "저장"을 클릭하고 그의 변경들이 영속화 되기를 기대한다; 그는 또한 그가 이 정보를 편집하는 유일한
|
||||
개인이고 변경 충돌이 발생하지 않기를 기대한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
우리는 사용자의 관점에서, 이것을 작업 단위, 장기간 실행되는 <emphasis>어플리케이션 트랜잭션</emphasis>이라고 명명한다.
|
||||
당신이 당신의 어플리케이션에서 이것을 어떻게 구현할 수 있는 많은 방법들이 존재한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
첫 번째 naive 구현은 동시성 변경을 방지하고, 격리와 atomicity(원자 단위성)을 보장하기 위해 데이터베이스에 의해
|
||||
소유된 잠금으로 사용자가 생각하는동안 <literal>Session</literal>과 데이터베이스 트랜잭션을 유지할 수도 있다.
|
||||
이것은 물론 anti-패턴이다. 왜냐하면 잠금 다툼은 어플리케이션이 동시 사용자들의 가용 숫자를 높이는 것을 허용하지
|
||||
않을 것이기 때문이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
명료하게, 우리는 어플리케이션 트랜잭션을 구현하는데 몇몇 데이터베이스 트랜잭션들을 사용해야 한다. 이 경우에,
|
||||
비지니스 프로세스들의 격리를 유지하는 것은 어플리케이션 티어의 부분적인 책임이 된다. 단일 어플리케이션 트랜잭션은
|
||||
대개 여러 개의 데이터베이스 트랜잭션들에 걸친다. 그것은 이들 데이터베이스 트랜잭션들 중 오직 한 개(마지막 트랜잭션)가
|
||||
업데이트된 데이터를 저장하고, 모든 다른 트랜잭션들이 단순히 데이터를 읽는 (예를 들면, 몇몇 요청/응답 주기에 걸치는
|
||||
마법사 스타일의 대화 상자에서) 경우에만 원자단위가 될 것이다. 특히 당신이 Hibernate의 특징들을 사용할 경우에 , 이것은
|
||||
들리는 것보다 구현하기가 더 쉽다:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>자동적인 버전화</emphasis> - Hibernate는 당신을 위해 자동적인 optimistic
|
||||
동시성 제어를 행할 수 있고, 그것은 사용자가 생각하는 시간 동안 동시적인 변경이 발생했는지를 자동적으로 검출할 수 있다..
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Detached 객체들</emphasis> - 만일 당신이 이미 논의된 <emphasis>session-per-request</emphasis>
|
||||
패턴을 사용하고자 결정하는 경우, 모든 로드된 인스턴스들은 사용자가 생각하는 시간 동안 detached 상태에 있을 것이다.
|
||||
Hibernate는 그 객체들을 재첨부시키고 변경들을 영속화 시키는 것을 허용해주며, 그 패턴은
|
||||
<emphasis>session-per-request-with-detached-objects(detached-객체들을 가진 요청 당 세션)</emphasis>으로 명명된다.
|
||||
자동적인 버전화는 동시성 변경들을 격리시키는데 사용된다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Long Session</emphasis> - Hibernate <emphasis>Session</emphasis>은 데이터베이스
|
||||
트랜잭션이 커밋된 후에 기본 JDBC 커넥션이 연결 해제될 수도 있고, 새로운 클라이언트 요청이 발생할 때 다시 연결될 수
|
||||
있다. 이 패턴은 <emphasis>session-per-application-transaction(어플리케이션 트랜잭션 당 세션)</emphasis>으로
|
||||
알려져 있고 재첨부를 불필요하게 만든다. 자동적인 버전화는 동시성 변경들을 격리시키는데 사용된다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>session-per-request-with-detached-objects</emphasis>과
|
||||
<emphasis>session-per-application-transaction</emphasis> 양자는 장점들과 단점들을 갖는데, 우리는 이 장의
|
||||
뒷 부분에서 optimistic 동시성 제어 단락에서 그것들을 논의한다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-basics-identity">
|
||||
<title>객체 identity 고려하기</title>
|
||||
|
||||
<para>
|
||||
어플리케이션은 두 개의 다른 <literal>Session</literal>들 내에 있는 동일한 영속 상태에 동시에 접근할 수도 있다.
|
||||
하지만 영속 클래스의 인스턴스는 두 개의 <literal>Session</literal> 인스턴스들 사이에 결코 공유되지 않는다.
|
||||
그러므로 identity에 대한 두 개의 다른 개념들이 존재한다:
|
||||
</para>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>데이터베이스 Identity</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>foo.getId().equals( bar.getId() )</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>JVM Identity</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>foo==bar</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
그때 (예를 들어 <literal>Session</literal> 영역에서) <emphasis>특정</emphasis> <literal>Session</literal>에
|
||||
첨부된 객체들의 경우 두 개의 개념들은 동등한 것이고, 데이터베이스 identity에 대한 JVM identity가 Hibernate에 의해 보장된다.
|
||||
하지만, 어플리케이션이 두 개의 다른 세션들에서 "동일한" (영속 identity) 비지니스 객체에 동시에 접근하는 동안, 두 개의 인스턴스들은
|
||||
실제로 "다르다"(JVM identity). 충돌들은 flush/커밋 시에 (자동적인 버전화)를 사용하여, optimistic 접근법을 사용하여 해결된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 접근법은 Hibernate와 데이터베이스가 동시성에 대해 걱정하지 않도록 해준다; 그것은 또한 최상의 scalability를 제공한다.
|
||||
왜냐하면 단일 쓰레드-작업 단위 내에서 identity 보장은 단지 비용이 드는 잠금이나 다른 동기화 수단들을 필요로 하지 않기 때문이다.
|
||||
어플리케이션은 그것이 <literal>Session</literal> 당 단일 쓰레드를 강제하는 한, 어떤 비지니스 객체에 대해 결코 동기화 시킬
|
||||
필요가 없다. 하나의 <literal>Session</literal> 내에서 어플리케이션은 객체들을 비교하는데 <literal>==</literal>를
|
||||
안전하게 사용할 수가 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하지만, 하나의 <literal>Session</literal> 외부에서 <literal>==</literal>를 사용하는 어플리케이션은 예기치 않은
|
||||
결과들을 보게 될 수도 있다. 이것은 어떤 예기치 않은 장소들에서, 예를 들어 당신이 두 개의 detached 인스턴스들을 동일한
|
||||
<literal>Set</literal> 내에 집어넣을 경우에 발생할 수도 있다. 둘 다 동일한 데이터베이스 identity를 가질 수 있지만
|
||||
(예를 들어 그것들은 동일한 행을 표현한다), JVM identity는 정의 상 detached 상태에 있는 인스턴스들을 보장하지 않는다.
|
||||
개발자는 영속 클래스들내에 <literal>equals()</literal> 메소드와 <literal>hashCode()</literal> 메소드를 오버라이드 시켜야 하고
|
||||
객체 equality에 대한 그 자신의 개념을 구현해야 한다. 하나의 경고가 존재한다: equality를 구현하는데 데이터베이스 identifier를 결코
|
||||
사용하지 말고, 하나의 비지니스 키, 유일한, 대개 불변인 속성들의 조합을 사용하라. 데이터베이스 식별자는 만일 transient 객체가 영속화되는
|
||||
경우에 변경될 것이다. 만일 transient 인스턴스가(대개 detached 인스턴스들과 함께) <literal>Set</literal> 내에 보관되는 경우에,
|
||||
hashcode 변경은 <literal>Set</literal>의 계약을 파기시킨다. 비지니스 키들에 대한 속성들은 데이터베이스 프라이머리 키들 만큼
|
||||
안정적이어서는 안되며, 당신은 오직 객체들이 동일한 <literal>Set</literal> 내에 있는 한에서 안정성을 보장해야만 한다.
|
||||
이 쟁점에 관한 논의에 대한 더 많은 것을 Hibernate 웹 사이트를 보라. 또한 이것이 Hibernate 쟁점이 아니며, 단지 자바 객체
|
||||
identity와 equality가 구현되어야 하는 방법임을 노트하라.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-basics-issues">
|
||||
<title>공통된 쟁점들</title>
|
||||
|
||||
<para>
|
||||
안티-패턴들 <emphasis>session-per-user-session</emphasis> 또는
|
||||
<emphasis>session-per-application</emphasis>을 결코 사용하지 말라(물론 이 규칙에 대한 드문 예외상황들이 존재한다).
|
||||
다음 쟁점들 중 몇몇이 또한 권장되는 패턴들로 나타날 수 있음을 노트하고, 당신이 설계 결정을 내리기 전에 내포된 의미들을
|
||||
확실히 이해하라:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session</literal>은 쓰레드-안전하지 않다. HTTP 요청들, 세션 빈즈, 또는 Swing worker들처럼
|
||||
동시에 작업하는 것으로 가정되는 것들은 하나의 <literal>Session</literal> 인스턴스가 공유될 경우에 경쟁 조건들을
|
||||
발생시킬 것이다. 만일 당신이 당신의 <literal>HttpSession</literal> 내에 Hibernate
|
||||
<literal>Session</literal>을 유지시키는 경우(나중에 논의됨), 당신은 당신의 Http 세션에 대한 접근을 동기화
|
||||
시키는 것을 고려해야 한다. 그 밖의 경우, 충분히 빠르게 reload를 클릭하는 사용자는 두 개의 동시적으로 실행되는
|
||||
쓰레드들 내에서 동일한 <literal>Session</literal>을 사용할 수도 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernate에 의해 던져진 예외상황은 당신이 당신의 데이터베이스 트랜잭션을 롤백 시키고 즉시 <literal>Session</literal>을
|
||||
닫아야 함을 의미한다(나중에 상세히 논의됨). 만일 당신의 <literal>Session</literal>이 어플리케이션에 바인드 되어 있는 경우,
|
||||
당신은 어플리케이션을 중지시켜야 한다. 데이터베이스 트랜잭션 롤백은 당신의 비지니스 객체들을 그것들이 트랜잭션의 시작 시에
|
||||
머물렀던 상태로 되돌리지는 않는다. 이것은 데이터베이스 상태와 비지니스 객체들이 동기화를 벗어남을 의미한다. 대개 이것은 문제가 아니다.
|
||||
왜냐하면 예외상황들은 회복가능한 것이 아니고 당신이 어떻게든 롤백 후에 시작해야 하기 때문이다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session</literal>은 (Hibernate에 의해 dirty 상태로 관찰되었거나 체크된) 영속 상태에 있는
|
||||
모든 객체를 캐시 시킨다. 이것은 당신이 오랜 시간 동안 <literal>Session</literal>을 열어둔 채로 유지하거나
|
||||
단순하게 너무 많은 데이터를 로드시킬 경우에, 당신이 OutOfMemoryException을 얻기 전까지, 그것이 끝없이
|
||||
성장한다는 점을 의미한다. 이것에 대한 하나의 해결책은 <literal>Session</literal> 캐시를 관리하기 위해
|
||||
<literal>clear()</literal>와 <literal>evict()</literal>를 호출하는 것이지만, 당신이 대용량 데이터
|
||||
오퍼레이션들을 필요로 하는 경우에 당신은 대개 내장 프로시저를 고려해야 할 것이다. 몇몇 해결책들이
|
||||
<xref linkend="batch"/>에 보여져 있다. 사용자 세션 동안에 <literal>Session</literal>을 열려진 채로
|
||||
유지하는 것은 또한 실효성이 떨어진 데이터에 대한 높은 확률을 의미한다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="transactions-demarcation">
|
||||
<title>데이터베이스 트랜잭션 경계 설정</title>
|
||||
|
||||
<para>
|
||||
데이터베이스 (또는 시스템) 트랜잭션 경계들은 항상 필수적이다. 데이터베이스와의 통신은 데이터베이스 트랜잭션의 외부에서 발생할 수
|
||||
없다(이것은 자동-커밋 모드로 사용되는 많은 개발자들에게는 혼동스러워 보인다). 항상 심지어 읽기 전용 오퍼레이션들에 대해서도 명료한
|
||||
트랜잭션 경계들을 사용하라. 당신의 격리 레벨과 데이터베이스 가용성들에 따라, 이것은 필요하지 않을 수 있지만, 만일 당신이 항상
|
||||
트랜잭션들을 명시적으로 경계 설정할 경우에는 하강하는 결점들이 존재하지 않는다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate 어플리케이션은 관리되지 않는 환경(예를 들면. 스탠드얼론, 간단히 웹 어플리케이션들 또는 Swing 어플리케이션들)과
|
||||
관리되는 J2EE 환경에서 실행될 수 있다. 관리되지 않는 환경에서, Hibernate는 대개 그것 자신의 데이터베이스 커넥션 풀에 대한
|
||||
책임이 있다. 어플리케이션 개발자는 트랜잭션 경계들을 손수 설정해야 한다. 달리 말해, 개발자 스스로 데이터베이스 트랜잭션들을
|
||||
시작하고, 커밋시키거나 롤백시켜야 한다. 관리되는 환경은 대개 예를 들어 EJB 세션 빈즈의 배치 디스크립터 속에 선언적으로 정의된
|
||||
트랜잭션 어셈블리를 가진, 컨테이너에 의해-관리되는 트랜잭션들을 제공한다. 그때 프로그램 상의 트랜잭션 경계 설정은 더 이상 필요하지
|
||||
않다. 심지어 <literal>Session</literal>을 flush 시키는 것이 자동적으로 행해진다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하지만, 당신의 영속 계층이 이식성을 유지하게끔 자주 희망된다. Hibernate는 당신의 배치 환경의 고유한 트랜잭션 시스템 속으로
|
||||
변환되는 <literal>Transaction</literal>이라 명명되는 wrapper API 를 제공한다. 이 API는 실제로 옵션이지만 우리는
|
||||
당신이 CMT session bean 속에 있지 않는 한 그것의 사용을 강력하게 권장한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
대개 <literal>Session</literal> 종료는 네 개의 구분되는 단계들을 수반한다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
세션을 flush 시킨다
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
트랜잭션을 커밋 시킨다
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
세션을 닫는다
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
예외상황들을 처리한다
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
세션을 flush 시키는 것은 앞서 논의되었고, 우리는 이제 관리되는 환경과 관리되지 않는 환경 양자에서 트랜잭션 경계 설정과 예외상황을
|
||||
더 자세히 살펴볼 것이다.
|
||||
</para>
|
||||
|
||||
|
||||
<sect2 id="transactions-demarcation-nonmanaged">
|
||||
<title>관리되지 않는 환경</title>
|
||||
|
||||
<para>
|
||||
만일 Hibernate 영속 계층이 관리되지 않는(non-managed) 환경에서 실행될 경우, 데이터베이스 커넥션들은 대개 Hibernate의
|
||||
풀링 메커니즘에 의해 처리된다. session/transaction 처리 관용구는 다음과 같이 보여진다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[//Non-managed environment idiom
|
||||
Session sess = factory.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = sess.beginTransaction();
|
||||
|
||||
// do some work
|
||||
...
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
if (tx != null) tx.rollback();
|
||||
throw e; // or display error message
|
||||
}
|
||||
finally {
|
||||
sess.close();
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
당신은 <literal>Session</literal>을 명시적으로 <literal>flush()</literal>시키지 말아야 한다 -
|
||||
<literal>commit()</literal> 호출은 동기화를 자동적으로 트리거 시킨다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>close()</literal> 호출은 세션의 종료를 마크한다. <literal>close()</literal>의 주된 의미는
|
||||
JDBC 커넥션이 그 세션에 의해 포기될 것이라는 점이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 자바 코드는 이식성이 있고 관리되지 않는 환경과 JTA 환경 양자에서 실행된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 통상의 어플리케이션에서 비지니스 코드 속에 이 관용구를 결코 보지 않을 것이다; 치명적인(시스템) 예외상황들은 항상
|
||||
"상단"에서 잡혀야 한다. 달리 말해, Hibernate를 실행하는 코드가 (영속 계층에서) 호출되고 <literal>RuntimeException</literal>을
|
||||
처리하는 (그리고 대개 오직 제거하고 빠져나갈 수 있는) 코드는 다른 계층들 속에 있다. 이것은 당신 자신이 설계하는 도전점일
|
||||
수 있고 당신은 J2EE/EJB 컨테이너 서비스들이 이용 가능할 때마다 J2EE/EJB 컨테이너 서비스들을 사용할 것이다. 예외상황
|
||||
처리는 이 장의 뒷부분에서 논의된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 (디폴트인) <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>를 선택해야 함을 노트하라.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-demarcation-jta">
|
||||
<title>JTA 사용하기</title>
|
||||
|
||||
<para>
|
||||
만일 당신의 영속 계층이 어플리케이션 서버에서(예를 들어, EJB 세션 빈즈 이면에서) 실행될 경우, Hibernate에 의해
|
||||
획득된 모든 데이터소스 커넥션은 자동적으로 전역 JTA 트랜잭션의 부분일 것이다. Hibernate는 이 통합을 위한 두 개의
|
||||
방도들을 제공한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 당신이 bean-managed transactions(BMT)를 사용할 경우 Hibernate는 당신이 <literal>Transaction</literal>
|
||||
API를 사용할 경우에 BMT 트랜잭션을 시작하고 종료하도록 어플리케이션 서버에게 알려줄 것이다. 따라서 트랜잭션 관리 코드는
|
||||
non-managed 환경과 동일하다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[// BMT idiom
|
||||
Session sess = factory.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = sess.beginTransaction();
|
||||
|
||||
// do some work
|
||||
...
|
||||
|
||||
tx.commit();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
if (tx != null) tx.rollback();
|
||||
throw e; // or display error message
|
||||
}
|
||||
finally {
|
||||
sess.close();
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
CMT의 경우, 트랜잭션 관할[경계 설정]은 프로그램 상이 아닌, session bean 배치 디스크립터들 속에서 행해진다. 당신이 스스로
|
||||
<literal>Session</literal>을 수작업으로 flush 시키고 닫고자 원하지 않을 경우, 단지
|
||||
<literal>hibernate.transaction.flush_before_completion</literal>을 <literal>true</literal>로 설정하고,
|
||||
<literal>hibernate.connection.release_mode</literal>를 <literal>after_statement</literal> 또는
|
||||
<literal>auto</literal>로 설정하고 <literal>hibernate.transaction.auto_close_session</literal>을
|
||||
<literal>true</literal>로 설정하라. Hibernate는 그때 자동적으로 flush 되고 당신을 위해 <literal>Session</literal>을
|
||||
닫을 것이다. 남아 있는 유일한 작업은 예외상황이 발생할 때 트랜잭션을 롤백시키는 것이다. 다행하게도 CMT bean에서, 이것이 자동적으로
|
||||
일어난다. 왜냐하면 session bean 메소드에 의해 던져진 처리되지 않은 <literal>RuntimeException</literal>은 전역 트랜잭션을
|
||||
롤백시키도록 컨테이너에게 통보하기 때문이다. <emphasis>이것은 당신이 CMT에서 Hibernate <literal>Transaction</literal> API를
|
||||
사용할 필요가 전혀 없음을 의미한다.</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신이 Hibernate의 트랜잭션 팩토리를 구성할 때, 당신이 BMT session bean에서
|
||||
<literal>org.hibernate.transaction.JTATransactionFactory</literal>를 선택해야하고, CMT session bean에서
|
||||
<literal>org.hibernate.transaction.CMTTransactionFactory</literal>를 선택해야 함을 노트하라. 또한
|
||||
<literal>org.hibernate.transaction.manager_lookup_class</literal>를 설정하는 것을 염두에 두라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 당신이 CMT 환경에서 작업하고 있고, 세션을 자동적으로 flushing하고 닫는 것을 사용할 경우, 당신은 또한 당신의 코드의 다른
|
||||
부분들에서 동일한 세션을 사용하고자 원할 수도 있다. 일반적으로 관리되지 않는 환경에서 당신은 세션을 소유하는데 하나의
|
||||
<literal>ThreadLocal</literal> 변수를 사용할 것이지만, 한 개의 EJB 요청은 다른 쓰레드들(예를 들면 또 다른 세션 빈을
|
||||
호출하는 세션 빈) 내에서 실행될 수도 있다. 만일 당신이 당신의 <literal>Session</literal> 인스턴스를 전달하는 것을
|
||||
고민하고 싶지 않다면, <literal>SessionFactory</literal>이 JTA 트랜잭션 컨텍스트에 바인드되어 있는 한 개의 세션을
|
||||
반환하는, <literal>getCurrentSession()</literal> 메소드를 제공한다. 이것은 Hibernate를 어플리케이션 속으로
|
||||
통합시키는 가장 손쉬운 방법이다! "현재" 세션은 (위의 프로퍼티 설정들에 관계없이) auto-flush와 auto-close, 그리고
|
||||
auto-connection-release를 항상 이용 가능하게 한다. 우리의 session/transaction 관리 idiom은 다음과 같이 감소된다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[// CMT idiom
|
||||
Session sess = factory.getCurrentSession();
|
||||
|
||||
// do some work
|
||||
...
|
||||
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
달리 말해, 당신이 관리 환경에서 행해야 하는 모든 것은 <literal>SessionFactory.getCurrentSession()</literal>을
|
||||
호출하고, 당신의 데이터 접근 작업을 행하고, 그리고 나머지를 컨테이너에게 남겨두는 것이다. 트랜잭션 경계들은 당신의
|
||||
session bean의 배치 디스크립터들 속에 선언적으로 설정된다. 그 세션의 생명주기는 Hibernate에 의해 완전하게 관리된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>after_statement</literal> 커넥션의 사용에는 한 가지 단서가 존재한다. JTA 명세서의 분별없는 제약성으로 인해,
|
||||
<literal>scroll()</literal> 또는 <literal>iterate()</literal>에 의해 반환된 어떤 닫혀지지 않은
|
||||
<literal>ScrollableResults</literal> 또는 <literal>Iterator</literal> 인스턴스들을 Hibernate가 자동적으로
|
||||
제거하는 것이 불가능하다. 당신은 <literal>finally</literal> 블록에서 <literal>ScrollableResults.close()</literal>
|
||||
또는 <literal>Hibernate.close(Iterator)</literal>를 명시적으로 호출하여 기본 데이터베이스 커서를
|
||||
해제<emphasis>시켜야 한다</emphasis>. (물론 대부분의 어플리케이션들은 CMT 코드에서 <literal>scroll()</literal>
|
||||
또는 <literal>iterate()</literal> 사용을 쉽게 피할 수 있다.)
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-demarcation-exceptions">
|
||||
<title>예외상황 처리</title>
|
||||
|
||||
<para>
|
||||
만일<literal>Session</literal>이 (어떤 <literal>SQLException</literal>을 포함하는) 예외상황을 던질 경우,
|
||||
당신은 데이터베이스 트랜잭션을 즉시 롤백시키고, <literal>Session.close()</literal>를 호출하고
|
||||
<literal>Session</literal> 인스턴스를 폐기시켜야한다. <literal>Session</literal>의 어떤 메소드들은
|
||||
그 세션을 일관된 상태로 남겨두지 <emphasis>않을</emphasis> 것이다. Hibernate에 의해 던져진 예외상황은 복구가능한
|
||||
것으로 취급될 수 없다. 그 <literal>Session</literal>이 <literal>finally</literal> 블록 내에서
|
||||
<literal>close()</literal>를 호출하여 닫혀지도록 확실히 하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate 영속 계층에서 발생할 수 있는 대부분의 오류들을 포장하는, <literal>HibernateException</literal>은
|
||||
체크되지 않은 예외상황이다(그것은 Hibernate의 이전 버전에는 없었다). 우리의 의견으로, 우리는 낮은 계층에서 복구불가능한
|
||||
예외상황을 붙잡도록 어플리케이션 개발자에게 강제하지 않을 것이다. 대부분의 시스템들에서, 체크되지 않은 치명적인 예외상황들은
|
||||
(예를 들어, 더 높은 계층에서) 메소드 호출 스택의 첫 번째 프레임들 중 하나 속에서 처리되고, 한 개의 오류 메시지가 어플리케이션
|
||||
사용자에게 표시된다(또는 어떤 다른 적절한 액션이 취해진다). Hibernate는 또한 <literal>HibernateException</literal>이
|
||||
아닌, 다른 체크되지 않은 예외상황들을 던질 수도 있음을 노트하라. 다시 이것들은 복구가능하지 않고 적절한 액션이 취해져야 한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 데이터베이스와 상호작용하는 동안에 던져진 <literal>SQLException</literal>들을 하나의
|
||||
<literal>JDBCException</literal> 속에 포장한다. 사실, Hibernate는 그 예외상황을
|
||||
<literal>JDBCException</literal>의 보다 의미있는 서브클래스로 변환하려고 시도할 것이다. 기본
|
||||
<literal>SQLException</literal>은 <literal>JDBCException.getCause()</literal>를 통해 항상 이용 가능하다.
|
||||
Hibernate는<literal>SessionFactory</literal>에 첨부된 <literal>SQLExceptionConverter</literal>를
|
||||
사용하여 <literal>SQLException</literal>을 적당한 하나의 <literal>JDBCException</literal> 서브클래스로
|
||||
변환시킨다. 디폴트로 <literal>SQLExceptionConverter</literal>는 구성된 dialect에 의해 정의된다; 하지만
|
||||
맞춤 구현 속에 플러그인 시키는 것이 또한 가능하다(상세한 것은 <literal>SQLExceptionConverterFactory</literal>
|
||||
클래스에 관한 javadocs를 보라). 표준 <literal>JDBCException</literal> 서브타입은 다음과 같다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>JDBCConnectionException</literal> - 기본 JDBC 통신에 대한 오류를 나타낸다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>SQLGrammarException</literal> - 생겨난 SQL에 대한 문법 또는 구문 문제점을 나타낸다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>ConstraintViolationException</literal> - 무결성 제약 위반에 관한 어떤 형식을 나타낸다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockAcquisitionException</literal> - 요청된 오퍼레이션을 실행하는데 필수적인 잠금 레벨을
|
||||
획득하는 오류를 나타낸다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>GenericJDBCException</literal> - 다른 카테고리들 중 어떤 것으로 분류되지 않았던 일반적인 예외상황.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="transactions-optimistic">
|
||||
<title>Optimistic 동시성 제어</title>
|
||||
|
||||
<para>
|
||||
고도의 동시성과 고도의 가용성을 일치시키는 유일한 접근법은 버전화를 가진 optimistic동시성 제어이다. 버전 체킹은 업데이트 충돌을
|
||||
검출하기 위해(그리고 업데이트 손실을 방지하기 위해) 버전 번호들 또는 timestamp들을 사용한다. Hibernate는 optimistic 동시성을
|
||||
사용하는 어플리케이션 코드 작성에 세 가지 가능한 접근법들을 제공한다. 우리가 보여주는 쓰임새들은 긴 어플리케이션 트랜잭션들의 상황
|
||||
속에 있지만 버전 체킹 또한 단일 데이터베이스 트랜잭션들에서 업데이트 손실을 방지하는 이점을 갖고 있다.
|
||||
</para>
|
||||
|
||||
<sect2 id="transactions-optimistic-manual">
|
||||
<title>어플리케이션 버전 체킹</title>
|
||||
|
||||
<para>
|
||||
하나의 구현에서 Hibernate로부터 많은 도움이 없이, 데이터베이스에 대한 각각의 상호작용은 새로운 <literal>Session</literal>
|
||||
내에서 일어나고, 개발자는 영속 인스턴스들을 처리하기 전에 데이터베이스로부터 모든 영속 인스턴스들을 다시 로드시킬 책임이 있다.
|
||||
이 접근법은 어플리케이션 트랜잭션을 확실히 격리시키기 위해 그것 자신의 버전 체킹을 수행하도록 어플리케이션에게 강제시킨다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[// foo is an instance loaded by a previous Session
|
||||
session = factory.openSession();
|
||||
Transaction t = session.beginTransaction();
|
||||
int oldVersion = foo.getVersion();
|
||||
session.load( foo, foo.getKey() ); // load the current state
|
||||
if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
|
||||
foo.setProperty("bar");
|
||||
t.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
version 프로퍼티는 <literal><version></literal>을 사용하여 매핑되고, Hibernate는 만일 엔티티가 dirty일 경우
|
||||
flush 동안에 그것을 자동적으로 증가시킬 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
물론, 당신이 낮은 데이터 동시성 환경에서 작업하고 있고 버전 체킹을 필요로 하지 않을 경우에, 당신은 이 접근법을 사용할 수 도 있고
|
||||
단지 버전 체크를 생략할 수도 있다. 그 경우에, <emphasis>마지막의 커밋 성공</emphasis>은 당신의 긴 어플리케이션 트랜잭션들에
|
||||
대한 디폴트 방도가 될 것이다. 이것이 어플리케이션의 사용자들을 혼동시킬 수 있음을 염두에 두라. 왜냐하면 사용자들은 오류 메시지들
|
||||
또는 충돌 변경들을 병합시킬 기회 없이 업데이트들 손실을 겪을 수도 있기 때문이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
명료하게 수작업 버전 체킹은 매우 사소한 환경들에서도 공포적이고 대부분의 어플리케이션들에 대해 실제적이지 않다. 흔히 단일
|
||||
인스턴스 뿐만 아니라 변경된 객체들의 전체 그래프들이 체크되어야 한다. Hibernate는 설계 패러다임으로서 긴 <literal>Session</literal>
|
||||
또는 detached 인스턴스들에 대해 자동적인 버전 체킹을 제공한다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-optimistic-longsession">
|
||||
<title>긴 세션과 자동적인 버전화</title>
|
||||
|
||||
<para>
|
||||
하나의 <literal>Session</literal> 인스턴스와 그것의 영속 인스턴스들은 전체 어플리케이션 트랜잭션에 사용된다. Hibernate는
|
||||
flush 할 때 인스턴스 버전들을 체크하고 만일 동시성 변경이 검출될 경우에 예외상황을 던진다. 이 예외상황을 잡아내고 처리하는 것을
|
||||
개발자의 몫이다(공통된 옵션들은 변경들을 병합시키거나 또는 쓸모가 없지 않은 데이터로 비지니스 프로세스를 다시 시작하는 기회를
|
||||
사용자에게 주는 것이다).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal>은 사용자 상호작용을 기다릴 때 어떤 기본 JDBC 커넥션으로부터 연결해제된다. 이 접근법은
|
||||
데이터베이스 접근의 관점에서 보면 가장 효율적이다. 어플리케이션은 버전 체킹 또는 detached 인스턴스들을 재첨부하는 것에
|
||||
그 자체 관계할 필요가 없거나 그것은 모든 데이터베이스 트랜잭션에서 인스턴스들을 다시 로드시킬 필요가 없다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[// foo is an instance loaded earlier by the Session
|
||||
session.reconnect(); // Obtain a new JDBC connection
|
||||
Transaction t = session.beginTransaction();
|
||||
foo.setProperty("bar");
|
||||
t.commit(); // End database transaction, flushing the change and checking the version
|
||||
session.disconnect(); // Return JDBC connection ]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>foo</literal> 객체는 그것이 로드되었던 <literal>Session</literal>이 어느 것인지를 여전히 알고 있다.
|
||||
<literal>Session.reconnect()</literal>은 새로운 커넥션을 획득하고(또는 당신이 커넥션을 제공할 수 있다) 그리고
|
||||
그 세션을 다시 시작시킨다. <literal>Session.disconnect()</literal> 메소드는 JDBC 커넥션으로부터 세션을
|
||||
연결 해제하고 (당신이 커넥션을 제공하지 않는 한) 그 커넥션을 풀(pool)로 반환할 것이다. 재연결 후에, 당신이 업데이트하고
|
||||
있는 데이터에 대한 버전 체킹을 강제시키기 위해, 당신은 또 다른 트랜잭션에 의해 업데이트 되었던 어떤 객체들에 대해
|
||||
<literal>LockMode.READ</literal>로서 <literal>Session.lock()</literal>을 호출할 수도 있다. 당신은 당신이
|
||||
업데이트 <emphasis>중인</emphasis> 어떤 데이터에 대한 잠금을 필요로 하지 않는다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
만일 <literal>disconnect()</literal>와 <literal>reconnect()</literal>에 대한 명시적인 호출들이 너무 번거러울 경우,
|
||||
당신은 대신에 <literal>hibernate.connection.release_mode</literal>를 사용할 수도 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 사용자가 생각하는시간 동안 <literal>Session</literal>이 저장되기에는 너무 큰 경우 이 패턴은 문제성이 있다. 예를 들어
|
||||
<literal>HttpSession</literal>은 가능한 작은 것으로 유지되어야 한다. 또한 <literal>Session</literal>은 (필수의)
|
||||
첫 번째 레벨 캐시이고 모든 로드된 객체들을 포함하기 때문에, 우리는 아마 적은 요청/응답 주기들에 대해서만 이 방도를 사용할 수 있다.
|
||||
<literal>Session</literal>이 곧 실효성이 없는 데이터를 갖게 될 것이므로 이것이 진정으로 권장된다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
또한 당신이 연결해제된 <literal>Session</literal>을 영속 계층에 가깝게 유지해야함을 노트하라. 달리말해,
|
||||
<literal>Session</literal>을 보관하는데 EJB stateful session bean을 사용하고 <literal>HttpSession</literal>
|
||||
내에 그것을 저장하기 위해서 그것을 웹 계층에 전송하지 말라(또는 그것을 별도의 티어에 직렬화 시키지도 말라).
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-optimistic-detached">
|
||||
<title>Detached 객체들과 자동적인 버전화</title>
|
||||
|
||||
<para>
|
||||
영속 저장소에 대한 각각의 상호작용은 새로운 <literal>Session</literal>에서 일어난다. 하지만 동일한 영속 인스턴스들은
|
||||
데이터베이스와의 각각의 상호작용에 재사용된다. 어플리케이션은 원래 로드되었던 detached 인스턴스들의 상태를 또 다른
|
||||
<literal>Session</literal> 내에서 처리하고 나서 <literal>Session.update()</literal>,
|
||||
<literal>Session.saveOrUpdate()</literal>, <literal>Session.merge()</literal>를 사용하여 그것들을
|
||||
다시 첨부시킨다.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[// foo is an instance loaded by a previous Session
|
||||
foo.setProperty("bar");
|
||||
session = factory.openSession();
|
||||
Transaction t = session.beginTransaction();
|
||||
session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
|
||||
t.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
다시, Hibernate는 flush 동안에 인스턴스 버전들을 체크할 것이고 업데이트 충돌이 발생할 경우에 예외상황을 던질 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 또한 <literal>update()</literal>대신에 <literal>lock()</literal>을 호출할 수도 있고 만일 그 객체가
|
||||
변경되지 않았음을 당신이 확신하는 경우에 (버전 체킹을 수행하고 모든 캐시들을 무시하는) <literal>LockMode.READ</literal>를
|
||||
사용할 수 있다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="transactions-optimistic-customizing">
|
||||
<title>자동적인 버전화를 맞춤화 시키기</title>
|
||||
|
||||
<para>
|
||||
당신은 <literal>optimistic-lock</literal> 매핑 속성을 <literal>false</literal>로 설정함으로써 특정 프로퍼티들과
|
||||
콜렉션들에 대한 Hibernate의 자동적인 버전 증가를 불가능하도록 할 수도 있다. 그때 Hibernate는 그 프로퍼티가 dirty 일 경우에
|
||||
더 이상 버전을 증가시키지 않을 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
리거시 데이터베이스 스키마들은 자주 static이고 변경될 수 없다. 또는 다른 어플리케이션들은 또한 동일한 데이터베이스에 접근하고
|
||||
버전 번호들 또는 심지어 timestamp들을 처리하는 방법을 모를 수도 있다. 두 경우들에서, 버전화는 테이블 내의 특정 컬럼에 의지할 수
|
||||
없다. version 또는 timestamp 프로퍼티 매핑 없이 행 내의 모든 필드들에 대한 상태를 비교하여 버전 체크를 강제시키기 위해서,
|
||||
<literal><class></literal> 매핑 속에 <literal>optimistic-lock="all"</literal>을 표시하라. 만일
|
||||
Hibernate가 이전 상태와 새로운 상태를 비교할 수 있을 경우에, 예를 들면 당신이 하나의 긴 <literal>Session</literal>을
|
||||
사용하고 session-per-request-with-detached-objects을 사용하지 않을 경우 이것은 개념적으로만 동작함을 노트하라.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
때때로 행해졌던 변경들이 중첩되지 않는 한 동시적인 변경이 허용될 수 있다. 만일 <literal><class></literal>를
|
||||
매핑할 때 당신이 <literal>optimistic-lock="dirty"</literal>를 설정하면, Hibernate는 flush 동안에 dirty 필드들을
|
||||
비교만 할 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
두 경우들에서, 전용 version/timestamp 컬럼의 경우 또는 full/dirty 필드 비교의 경우, Hibernate는 법전 체크를 실행하고
|
||||
정보를 업데이트하는데 엔티티 당 (적절한 <literal>WHERE</literal> 절을 가진) 한 개의<literal>UPDATE</literal>
|
||||
문장을 사용한다. 만일 당신이 연관된 엔티티들에 대한 재첨부를 케스케이드 하는데 transitive 영속을 사용할 경우,
|
||||
Hibernate는 불필요하게 업데이트들을 실행할 수도 있다. 이것은 대개 문제가 아니지만, 심지어 변경들이 detached 인스턴스들에
|
||||
대해 행해지지 않았을 때에도 데이터베이스 내에서 <emphasis>on update</emphasis> 트리거들이 실행될 수도 있다. 그 행을
|
||||
업데이트하기 전에 변경들이 실제로 일어났음을 확인하기 위해 인스턴스를 <literal>SELECT</literal>하는 것을 Hibernate에게
|
||||
강제시키는, <literal><class></literal> 매핑 속에 <literal>select-before-update="true"</literal>를
|
||||
설정함으로써 당신은 이 특징을 맞춤화 시킬 수 있다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="transactions-locking">
|
||||
<title>Pessimistic 잠금</title>
|
||||
|
||||
<para>
|
||||
사용자들은 잠금 방도에 대해 걱정하는데 많은 시간을 할애하하려고 생각하지 않는다. 대개 JDBC 커넥션들에 대한 격리 레벨을 지정하는
|
||||
것으로 충분하고 그런 다음 단순히 데이터베이스로 하여금 모든 작업을 행하도록 한다. 하지만 진일보한 사용자들은 때때로 배타적인
|
||||
pessimistic 잠금들을 얻거나 또는 새로운 트랜잭션의 시작 시에 잠금들을 다시 얻고자 원할 수도 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 결코 메모리 내에 있는 객체들이 아닌, 데이터베이스의 잠금 메커니즘을 항상 사용할 것이다!
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>LockMode</literal> 클래스는 Hibernate에 의해 획득될 수 있는 다른 잠금 레벨들을 정의한다. 잠금은 다음 메커니즘들에
|
||||
의해 얻어진다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode.WRITE</literal>는 Hibernate가 한 행을 업데이트 하거나 insert 할 때 자동적으로 획득된다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode.UPGRADE</literal>는 <literal>SELECT ... FOR UPDATE</literal> 구문을 지원하는
|
||||
데이터베이스 상에서 <literal>SELECT ... FOR UPDATE</literal>를 사용하여 명시적인 사용자 요청 상에서
|
||||
얻어질 수 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode.UPGRADE_NOWAIT</literal>는 오라클에서 <literal>SELECT ... FOR UPDATE NOWAIT</literal>를
|
||||
사용하여 명시적인 사용자 요청 상에서 얻어질 수도 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode.READ</literal>는 Hibernate가 반복 가능한 읽기(Repeatable Read) 또는 Serialization
|
||||
격리 레벨에서 데이터를 읽어들일 때 자동적으로 얻어질 수도 있다. 명시적인 사용자 요청에 의해 다시 얻어질 수도 있다.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode.NONE</literal>은 잠금이 없음을 나타낸다. 모든 객체들은 <literal>Transaction</literal>의 끝에서
|
||||
이 잠금 모드로 전환된다. <literal>update()</literal> 또는 <literal>saveOrUpdate()</literal>에 대한 호출을 통해
|
||||
세션과 연관된 객체들이 또한 이 잠금 모드로 시작된다.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
"명시적인 사용자 요청"은 다음 방법들 중 하나로 표현된다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>LockMode</literal>를 지정한 <literal>Session.load()</literal>에 대한 호출.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session.lock()</literal>에 대한 호출.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Query.setLockMode()</literal>에 대한 호출.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
만일 <literal>Session.load()</literal>가 <literal>UPGRADE</literal> 또는 <literal>UPGRADE_NOWAIT</literal>
|
||||
모드로 호출되고 ,요청된 객체가 아직 이 세션에 의해 로드되지 않았다면, 그 객체는 <literal>SELECT ... FOR UPDATE</literal>를
|
||||
사용하여 로드된다. 만일 요청된 것이 아닌 다소 제한적인 잠금으로 이미 로드되어 있는 객체에 대해 <literal>load()</literal>가
|
||||
호출될 경우, Hibernate는 그 객체에 대해 <literal>lock()</literal>을 호출한다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 지정된 잠금 모드가 <literal>READ</literal>, <literal>UPGRADE</literal> 또는
|
||||
<literal>UPGRADE_NOWAIT</literal> 일 경우에 <literal>Session.lock()</literal>은 버전 번호 체크를 수행한다.
|
||||
(<literal>UPGRADE</literal> 또는 <literal>UPGRADE_NOWAIT</literal> 인 경우에,
|
||||
<literal>SELECT ... FOR UPDATE</literal>가 사용된다.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
만일 데이터베이스가 요청된 잠금 모드를 지원하지 않을 경우, (예외상황을 던지는 대신에) Hibernate는 적절한 대체 모드를 사용할 것이다.
|
||||
이것은 어플리케이션이 이식 가능할 것임을 확실히 해준다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
1139
reference/ko/modules/tutorial.xml
Normal file
273
reference/ko/modules/xml.xml
Normal file
@ -0,0 +1,273 @@
|
||||
<chapter id="xml">
|
||||
<title>XML 매핑</title>
|
||||
|
||||
<para><emphasis>
|
||||
이것은 Hibernate3.0에서 실험적인 특징이고 매우 활동적으로 개발 중에 있음을 노트하라.
|
||||
</emphasis></para>
|
||||
|
||||
<sect1 id="xml-intro" revision="1">
|
||||
<title>XML 데이터로 작업하기</title>
|
||||
|
||||
<para>
|
||||
Hibernate는 당신이 영속 POJO들로 작업하는 것과 아주 동일한 방법으로 영속 XML 데이터에 작업하도록 해준다. 파싱된 XML 트리는
|
||||
단지 객체 레벨에서 관계형 데이터를 나타내는 또 다른 방법으로 간주될 수 있다. 하나의 파싱된 XML 트리는 POJO들 대신, 객체 레벨에서
|
||||
관계형 데이터를 표현하는 단지 또 다른 방법으로 간주될 수 있다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate는 XML 트리들을 처리하는 API로서 dom4j를 지원한다. 당신은 데이터베이스로부터 dom4j 트리들을 검색하고 당신이 그 트리를
|
||||
데이터베이스와 자동적으로 동기화시키기 위해 어떤 변경을 행하도록 하는 질의들을 작성할 수 있다. 당신은 심지어 XML 문서를 취하고,
|
||||
dom4j를 사용하여 그것을 파싱하고, Hibernate의 다음 기본적인 오퍼레이션들 중 어떤 것으로서 그것을 데이터베이스에 저장시킬 수 있다:
|
||||
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>(merging(병합)은 아직 지원되지
|
||||
않는다).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
이 특징은 데이터 가져오기/내보내기,JMS 또는 SOAP 그리고 XSLT-기반의 레포팅을 통한 엔티티 데이터의 구체화를 포함하는 많은
|
||||
어플리케이션들을 갖는다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
하나의 매핑은 클래스들의 프로퍼티들과 XML 문서의 노드들을 데이터베이스로 동시에 매핑시키는데 사용될 수 있거나, 만일 매핑할 클래스가
|
||||
존재하지 않을 경우, 그것은 단지 XML을 매핑시키는데 사용될 수도 있다.
|
||||
</para>
|
||||
|
||||
<sect2 id="xml-intro-mapping">
|
||||
<title>XML과 클래스 매핑을 함께 지정하기</title>
|
||||
|
||||
<para>
|
||||
다음은 POJO와 XML을 동시에 매핑시키는 예제이다 :
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Account"
|
||||
table="ACCOUNTS"
|
||||
node="account">
|
||||
|
||||
<id name="accountId"
|
||||
column="ACCOUNT_ID"
|
||||
node="@id"/>
|
||||
|
||||
<many-to-one name="customer"
|
||||
column="CUSTOMER_ID"
|
||||
node="customer/@id"
|
||||
embed-xml="false"/>
|
||||
|
||||
<property name="balance"
|
||||
column="BALANCE"
|
||||
node="balance"/>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="xml-onlyxml">
|
||||
<title>XML 매핑만을 지정하기</title>
|
||||
|
||||
<para>
|
||||
다음은 POJO 클래스가 존재하지 않는 예제이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class entity-name="Account"
|
||||
table="ACCOUNTS"
|
||||
node="account">
|
||||
|
||||
<id name="id"
|
||||
column="ACCOUNT_ID"
|
||||
node="@id"
|
||||
type="string"/>
|
||||
|
||||
<many-to-one name="customerId"
|
||||
column="CUSTOMER_ID"
|
||||
node="customer/@id"
|
||||
embed-xml="false"
|
||||
entity-name="Customer"/>
|
||||
|
||||
<property name="balance"
|
||||
column="BALANCE"
|
||||
node="balance"
|
||||
type="big_decimal"/>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 매핑은 dom4j 트리로서 또는 프로퍼티 name/value 쌍들(java <literal>Map</literal>들)의 그래프로서 데이터에
|
||||
접근하는 것을 당신에게 허용해준다. 프로퍼티 이름들은 HQL 질의들 내에서 참조될 수도 있는 순수하게 논리적인 구조체들이다.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="xml-mapping" revision="1">
|
||||
<title>XML 매핑 메타데이터</title>
|
||||
|
||||
<para>
|
||||
많은 Hibernate 매핑 요소들은 <literal>node</literal> 속성을 수용한다. 이것은 당신이 프로퍼티 또는 엔티티 데이터를 소유하는
|
||||
XML 속성이나 요소의 이름을 지정하도록 한다. <literal>node</literal> 속성의 포맷은 다음 중 하나이어야 한다:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>"element-name"</literal> - 명명된 XML 요소로 매핑시킨다</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>"@attribute-name"</literal> - 명명된 XML 속성으로 매핑시킨다 </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>"."</literal> - 부모 요소로 매핑 시킨다</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"element-name/@attribute-name"</literal> -
|
||||
명명된 요소의 명명된 속성으로 매핑시킨다
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
콜렉션들과 단일 값 콜렉션들의 경우, 추가적인 <literal>embed-xml</literal> 속성이 존재한다. 만일 <literal>embed-xml="true"</literal>
|
||||
일 경우, 연관된 엔티티(또는 value 타입을 가진 콜렉션)에 대한 디폴트 XML 트리는 그 연관을 소유하는 엔티티에 대한 XML 트리 속에
|
||||
직접 삽입될 것이다. 그 밖의 경우 <literal>embed-xml="false"</literal> 일 경우, 참조된 식별자 값 만이 단일 포인트 연관들에
|
||||
대해 나타날 것이고 콜렉션들은 단순히 전혀 나타나지 않을 것이다.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
당신은 너무 많은 연관들에 대해 <literal>embed-xml="true"</literal>로 남겨두지 말도록 주의해야 한다. 왜냐하면 XML이
|
||||
순환적으로 잘 처리하지 못하기 때문이다!
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Customer"
|
||||
table="CUSTOMER"
|
||||
node="customer">
|
||||
|
||||
<id name="id"
|
||||
column="CUST_ID"
|
||||
node="@id"/>
|
||||
|
||||
<map name="accounts"
|
||||
node="."
|
||||
embed-xml="true">
|
||||
<key column="CUSTOMER_ID"
|
||||
not-null="true"/>
|
||||
<map-key column="SHORT_DESC"
|
||||
node="@short-desc"
|
||||
type="string"/>
|
||||
<one-to-many entity-name="Account"
|
||||
embed-xml="false"
|
||||
node="account"/>
|
||||
</map>
|
||||
|
||||
<component name="name"
|
||||
node="name">
|
||||
<property name="firstName"
|
||||
node="first-name"/>
|
||||
<property name="initial"
|
||||
node="initial"/>
|
||||
<property name="lastName"
|
||||
node="last-name"/>
|
||||
</component>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
이 경우에, 우리는 실제 account 데이터가 아닌, account id들을 가진 콜렉션을 삽입시키기로 결정했다. 다음 HQL 질의:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
|
||||
|
||||
<para>
|
||||
는 다음과 같은 데이터셋들을 반환할 것이다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
<account short-desc="Savings">987632567</account>
|
||||
<account short-desc="Credit Card">985612323</account>
|
||||
<name>
|
||||
<first-name>Gavin</first-name>
|
||||
<initial>A</initial>
|
||||
<last-name>King</last-name>
|
||||
</name>
|
||||
...
|
||||
</customer>]]></programlisting>
|
||||
|
||||
<para>
|
||||
만일 당신이 <literal><one-to-many></literal> 매핑에 대해 <literal>embed-xml="true"</literal>를 설정할 경우,
|
||||
데이터는 다음과 같이 보일 수도 있다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
<account id="987632567" short-desc="Savings">
|
||||
<customer id="123456789"/>
|
||||
<balance>100.29</balance>
|
||||
</account>
|
||||
<account id="985612323" short-desc="Credit Card">
|
||||
<customer id="123456789"/>
|
||||
<balance>-2370.34</balance>
|
||||
</account>
|
||||
<name>
|
||||
<first-name>Gavin</first-name>
|
||||
<initial>A</initial>
|
||||
<last-name>King</last-name>
|
||||
</name>
|
||||
...
|
||||
</customer>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="xml-manipulation" revision="1">
|
||||
<title>XML 데이터 처리하기</title>
|
||||
|
||||
<para>
|
||||
우리의 어플리케이션 내에서 XML 문서들을 다시 읽어들이고 업데이트 시키자. 우리는 dom4j 세션을 얻어서 이것을 행한다:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Document doc = ....;
|
||||
|
||||
Session session = factory.openSession();
|
||||
Session dom4jSession = session.getSession(EntityMode.DOM4J);
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
List results = dom4jSession
|
||||
.createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
|
||||
.list();
|
||||
for ( int i=0; i<results.size(); i++ ) {
|
||||
//add the customer data to the XML document
|
||||
Element customer = (Element) results.get(i);
|
||||
doc.add(customer);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[Session session = factory.openSession();
|
||||
Session dom4jSession = session.getSession(EntityMode.DOM4J);
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
Element cust = (Element) dom4jSession.get("Customer", customerId);
|
||||
for ( int i=0; i<results.size(); i++ ) {
|
||||
Element customer = (Element) results.get(i);
|
||||
//change the customer name in the XML and database
|
||||
Element name = customer.element("name");
|
||||
name.element("first-name").setText(firstName);
|
||||
name.element("initial").setText(initial);
|
||||
name.element("last-name").setText(lastName);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
XML 기반의 데이터 가져오기/내보내기를 구현하는데 이 특징과 Hibernate의 <literal>replicate()</literal> 오퍼레이션을
|
||||
결합시키는 것이 매우 유용하다.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
526
reference/ko/styles/fopdf.xsl
Normal file
@ -0,0 +1,526 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL FO configuration file for the Hibernate
|
||||
Reference Documentation. It defines a custom titlepage and
|
||||
the parameters for the A4 sized PDF printable output.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
Custom Title Page
|
||||
################################################### -->
|
||||
|
||||
<xsl:template name="book.titlepage.recto">
|
||||
<fo:block>
|
||||
<fo:table table-layout="fixed" width="175mm">
|
||||
<fo:table-column column-width="175mm"/>
|
||||
<fo:table-body>
|
||||
<fo:table-row>
|
||||
<fo:table-cell text-align="center">
|
||||
<fo:block>
|
||||
<fo:external-graphic src="file:images/hibernate_logo_a.png"/>
|
||||
</fo:block>
|
||||
<fo:block font-family="가을체" font-size="24pt" padding-before="10mm">
|
||||
<xsl:value-of select="bookinfo/subtitle"/>
|
||||
</fo:block>
|
||||
<fo:block font-family="가을체" font-size="14pt" padding="10mm">
|
||||
버전:
|
||||
<xsl:value-of select="bookinfo/releaseinfo"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</fo:table-body>
|
||||
</fo:table>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Prevent blank pages in output -->
|
||||
<xsl:template name="book.titlepage.before.verso">
|
||||
</xsl:template>
|
||||
<xsl:template name="book.titlepage.verso">
|
||||
</xsl:template>
|
||||
<xsl:template name="book.titlepage.separator">
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Header
|
||||
################################################### -->
|
||||
|
||||
<!-- More space in the center header for long text -->
|
||||
<xsl:attribute-set name="header.content.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$title.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">-5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">-5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Custom Footer
|
||||
################################################### -->
|
||||
|
||||
<!-- This footer prints the Hibernate version number on the left side -->
|
||||
<xsl:template name="footer.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<xsl:variable name="Version">
|
||||
<xsl:choose>
|
||||
<xsl:when test="//releaseinfo">
|
||||
<xsl:text>하이버네이트 </xsl:text>
|
||||
<xsl:value-of select="//releaseinfo"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$double.sided != 0 and $position = 'left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position = 'center'">
|
||||
<!-- nop -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<fo:page-number/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$pageclass='titlepage'">
|
||||
<!-- nop: other titlepage sequences have no footer -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Custom Toc Line
|
||||
################################################### -->
|
||||
|
||||
<!-- Improve the TOC. -->
|
||||
<xsl:template name="toc.line">
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="object.id"/>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="label">
|
||||
<xsl:apply-templates select="." mode="label.markup"/>
|
||||
</xsl:variable>
|
||||
|
||||
<fo:block text-align-last="justify"
|
||||
end-indent="{$toc.indent.width}pt"
|
||||
last-line-end-indent="-{$toc.indent.width}pt">
|
||||
<fo:inline keep-with-next.within-line="always">
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
|
||||
<!-- Chapter titles should be bold. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="local-name(.) = 'chapter'">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:if test="$label != ''">
|
||||
<xsl:copy-of select="$label"/>
|
||||
<xsl:value-of select="$autotoc.label.separator"/>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="." mode="titleabbrev.markup"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
<fo:inline keep-together.within-line="always">
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:leader leader-pattern="dots"
|
||||
leader-pattern-width="3pt"
|
||||
leader-alignment="reference-area"
|
||||
keep-with-next.within-line="always"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
<fo:page-number-citation ref-id="{$id}"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Extensions
|
||||
################################################### -->
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<!-- FOP provide only PDF Bookmarks at the moment -->
|
||||
<xsl:param name="fop.extensions">1</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!-- Dot and Whitespace as separator in TOC between Label and Title-->
|
||||
<xsl:param name="autotoc.label.separator" select="'. '"/>
|
||||
|
||||
|
||||
<!--###################################################
|
||||
Paper & Page Size
|
||||
################################################### -->
|
||||
|
||||
<!-- Paper type, no headers on blank pages, no double sided printing -->
|
||||
<xsl:param name="paper.type" select="'A4'"/>
|
||||
<xsl:param name="double.sided">0</xsl:param>
|
||||
<xsl:param name="headers.on.blank.pages">0</xsl:param>
|
||||
<xsl:param name="footers.on.blank.pages">0</xsl:param>
|
||||
|
||||
<!-- Space between paper border and content (chaotic stuff, don't touch) -->
|
||||
<xsl:param name="page.margin.top">5mm</xsl:param>
|
||||
<xsl:param name="region.before.extent">10mm</xsl:param>
|
||||
<xsl:param name="body.margin.top">10mm</xsl:param>
|
||||
|
||||
<xsl:param name="body.margin.bottom">15mm</xsl:param>
|
||||
<xsl:param name="region.after.extent">10mm</xsl:param>
|
||||
<xsl:param name="page.margin.bottom">0mm</xsl:param>
|
||||
|
||||
<xsl:param name="page.margin.outer">18mm</xsl:param>
|
||||
<xsl:param name="page.margin.inner">18mm</xsl:param>
|
||||
|
||||
<!-- No intendation of Titles -->
|
||||
<xsl:param name="title.margin.left">0pc</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Fonts & Styles
|
||||
################################################### -->
|
||||
|
||||
<!-- Default Font size -->
|
||||
<xsl:param name="body.font.master">11</xsl:param>
|
||||
|
||||
<!-- Line height in body text -->
|
||||
<xsl:param name="line-height">1.4</xsl:param>
|
||||
|
||||
<!-- Monospaced fonts are smaller than regular text -->
|
||||
<xsl:attribute-set name="monospace.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$monospace.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="font-size">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Tables
|
||||
################################################### -->
|
||||
|
||||
<!-- The table width should be adapted to the paper size -->
|
||||
<xsl:param name="default.table.width">17.4cm</xsl:param>
|
||||
|
||||
<!-- Some padding inside tables -->
|
||||
<xsl:attribute-set name="table.cell.padding">
|
||||
<xsl:attribute name="padding-left">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">4pt</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Only hairlines as frame and cell borders in tables -->
|
||||
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
|
||||
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!-- Label only Sections up to level 2 -->
|
||||
<xsl:param name="local.l10n.xml" select="document('')"/>
|
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
|
||||
<l:l10n language="ko">
|
||||
<l:context name="title-numbered">
|
||||
<l:template name="sect3" text="%t"/>
|
||||
<l:template name="sect4" text="%t"/>
|
||||
<l:template name="sect5" text="%t"/>
|
||||
</l:context>
|
||||
<l:context name="section-xref-numbered">
|
||||
<l:template name="sect3" text="the section called %t"/>
|
||||
<l:template name="sect4" text="the section called %t"/>
|
||||
<l:template name="sect5" text="the section called %t"/>
|
||||
</l:context>
|
||||
|
||||
</l:l10n>
|
||||
</l:i18n>
|
||||
|
||||
<!--###################################################
|
||||
Titles
|
||||
################################################### -->
|
||||
|
||||
<!-- Chapter title size -->
|
||||
<xsl:attribute-set name="chapter.titlepage.recto.style">
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.8"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates?
|
||||
Let's remove it, so this sucker can use our attribute-set only... -->
|
||||
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xsl:use-attribute-sets="chapter.titlepage.recto.style">
|
||||
<xsl:call-template name="component.title">
|
||||
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.5"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.25"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level3.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Titles of formal objects (tables, examples, ...) -->
|
||||
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Programlistings
|
||||
################################################### -->
|
||||
|
||||
<!-- Verbatim text formatting (programlistings) -->
|
||||
<xsl:attribute-set name="verbatim.properties">
|
||||
<xsl:attribute name="space-before.minimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="border-color">#444444</xsl:attribute>
|
||||
<xsl:attribute name="border-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-width">0.1pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">0.5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Shade (background) programlistings -->
|
||||
<xsl:param name="shade.verbatim">1</xsl:param>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- We want to use callouts... -->
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
|
||||
<!-- Place callout bullets at this column in programmlisting.-->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--
|
||||
No, don't use crappy graphics for the callout bullets. This setting
|
||||
enables some weird Unicode rendering for some fancy bullet points
|
||||
in callouts. By default, this can only count to 10 and produces
|
||||
strange results if you ever have more than 10 callouts for one
|
||||
programlisting. We will fix that next.
|
||||
-->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!--
|
||||
Again, fun with DocBook XSL: The callout bullets are rendered in
|
||||
two places: In the programlisting itself and in the list below
|
||||
the listing, with the actual callout text. The rendering in the
|
||||
programlisting is some XSL transformer extension (e.g. a Saxon
|
||||
extension), so we can't change that without messing with the
|
||||
extensions. We only can turn it off by setting this limit to
|
||||
zero, then, a simple bracket style like "(3)" and "(4)" will
|
||||
be used in the programlisting.
|
||||
-->
|
||||
<xsl:param name="callout.unicode.number.limit" select="'0'"></xsl:param>
|
||||
|
||||
<!--
|
||||
The callout bullets in the actual callout list will be rendered
|
||||
with an XSL FO template. The default template is broken: limited to 10
|
||||
nice looking Unicode bullet points and then it doesn't print anything,
|
||||
the fallback doesn't work. We implement our own template, which is not
|
||||
as complicated, more ugly, but works. As always, function is more
|
||||
important than form.
|
||||
-->
|
||||
<xsl:template name="callout-bug">
|
||||
<xsl:param name="conum" select='1'/>
|
||||
<fo:inline
|
||||
color="black"
|
||||
padding-top="0.1em"
|
||||
padding-bottom="0.1em"
|
||||
padding-start="0.2em"
|
||||
padding-end="0.2em"
|
||||
baseline-shift="0.1em"
|
||||
font-family="{$monospace.font.family}"
|
||||
font-weight="bold"
|
||||
font-size="75%">
|
||||
<xsl:text>(</xsl:text>
|
||||
<xsl:value-of select="$conum"/>
|
||||
<xsl:text>)</xsl:text>
|
||||
</fo:inline>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Correct placement of titles for figures and examples. -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
<!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
|
||||
<xsl:param name="variablelist.as.blocks">1</xsl:param>
|
||||
|
||||
<!-- The horrible list spacing problems, this is much better. -->
|
||||
<xsl:attribute-set name="list.block.spacing">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Newer DocBook XSL apparently thinks that some sections are by
|
||||
default "draft" status, and this idiotic thing is by default
|
||||
also set to "maybe", so it spits out a lot of errors with the
|
||||
latest FOP as the XSL/FO styles have references to some draft
|
||||
watermarks, which you actually don't want in the first place.
|
||||
Turn this crap off. If you have to work with the "status"
|
||||
attribute, don't.
|
||||
-->
|
||||
<xsl:param name="draft.mode" select="'no'"/>
|
||||
|
||||
<!-- 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="saxon.character.representation" select="native"/>
|
||||
<xsl:param name="callout.unicode" select="1"/>
|
||||
<xsl:param name="callout.unicode.start.character" select="10102"/>
|
||||
<xsl:param name="l10n.gentext.default.language" select="ko"/>
|
||||
</xsl:stylesheet>
|
97
reference/ko/styles/html.css
Normal file
@ -0,0 +1,97 @@
|
||||
A {
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A:active {
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A:visited {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
TD, TH, SPAN {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
BLOCKQUOTE {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
|
||||
H1, H2, H3, H4, H5, H6 {
|
||||
color: #000000;
|
||||
font-weight:500;
|
||||
margin-top:10px;
|
||||
padding-top:15px;
|
||||
}
|
||||
|
||||
TABLE {
|
||||
border-collapse: collapse;
|
||||
border-spacing:0;
|
||||
border: 1px thin black;
|
||||
empty-cells: hide;
|
||||
}
|
||||
|
||||
TD {
|
||||
padding: 4pt;
|
||||
}
|
||||
|
||||
H1 { font-size: 150%; }
|
||||
H2 { font-size: 140%; }
|
||||
H3 { font-size: 110%; font-weight: bold; }
|
||||
H4 { font-size: 110%; font-weight: bold;}
|
||||
H5 { font-size: 100%; font-style: italic; }
|
||||
H6 { font-size: 100%; font-style: italic; }
|
||||
|
||||
TT {
|
||||
font-size: 90%;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
PRE {
|
||||
font-size: 100%;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #CCCCCC;
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
UL, OL, LI {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
HR {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #CCCCCC;
|
||||
border-width: 0px;
|
||||
padding: 0px;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.variablelist {
|
||||
padding-top: 10;
|
||||
padding-bottom:10;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.itemizedlist, UL {
|
||||
padding-top: 0;
|
||||
padding-bottom:0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.term {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
84
reference/ko/styles/html.xsl
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL HTML configuration file for the Hibernate
|
||||
Reference Documentation.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<xsl:param name="graphicsize.extension">0</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- Don't use graphics, use a simple number style -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
86
reference/ko/styles/html_chunk.xsl
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL HTML configuration file for the Hibernate
|
||||
Reference Documentation.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/html/chunk.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="chunk.section.depth">'5'</xsl:param>
|
||||
<xsl:param name="use.id.as.filename">'1'</xsl:param>
|
||||
<xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<xsl:param name="graphicsize.extension">0</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- Don't use graphics, use a simple number style -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|