reviewed chapters
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@9197 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
53a910b83d
commit
9b5c1fc8c5
|
@ -1,18 +1,18 @@
|
|||
<chapter id="components">
|
||||
<title>组件(Component)映射</title>
|
||||
<title>组件(Component)映射</title>
|
||||
|
||||
<para>
|
||||
<emphasis>组件</emphasis>(Component)这个概念在Hibernate中几处不同的地方为了不同的目的被重复使用.
|
||||
</para>
|
||||
|
||||
<sect1 id="components-dependentobjects" revision="2">
|
||||
<title>依赖对象(Dependent objects)</title>
|
||||
|
||||
<para>
|
||||
<emphasis>Component</emphasis>这个概念在Hibernate中几处不同的地方为了不同的目的被重复使用.
|
||||
组件(Component)是一个被包含的对象,在持久化的过程中,它被当作值类型,而并非一个实体的引用。在这篇文档中,组件这一术语指的是面向对象的合成概念(而并不是系统构架层次上的组件的概念)。举个例子, 你对人(Person)这个概念可以像下面这样来建模:
|
||||
</para>
|
||||
|
||||
<sect1 id="components-dependentobjects" revision="2" >
|
||||
<title>依赖对象(Dependent objects)</title>
|
||||
|
||||
<para>
|
||||
Component是一个被包含的对象,它作为值类型被持久化,而非一个被引用的实体。“component(组件)”这一术语指的是面向对象的合成概念(而并不是系统构架层次上的组件的概念)举个例子, 你可以对人(Person)如以下这样来建模:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Person {
|
||||
<programlisting><![CDATA[public class Person {
|
||||
private java.util.Date birthday;
|
||||
private Name name;
|
||||
private String key;
|
||||
|
@ -38,7 +38,7 @@
|
|||
......
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public class Name {
|
||||
<programlisting><![CDATA[public class Name {
|
||||
char initial;
|
||||
String first;
|
||||
String last;
|
||||
|
@ -63,12 +63,11 @@
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
现在,<literal>姓名(Name)</literal>是作为<literal>人(Person)</literal>的一个组成部分。需要注意的是:需要对<literal>姓名</literal>
|
||||
的持久化属性定义getter和setter方法,但是不需要实现任何的接口或申明标识符字段。
|
||||
在持久化的过程中,<literal>姓名(Name)</literal>可以作为<literal>人(Person)</literal>的一个组件。需要注意的是:你应该为<literal>姓名</literal>的持久化属性定义getter和setter方法,但是你不需要实现任何的接口或申明标识符字段。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
以下是这个例子的Hibernate映射文件:
|
||||
以下是这个例子的Hibernate映射文件:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
|
@ -83,80 +82,82 @@
|
|||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
人员(Person)表中将包括<literal>pid</literal>,
|
||||
<literal>birthday</literal>,
|
||||
<literal>initial</literal>,
|
||||
<literal>first</literal>和
|
||||
<literal>last</literal>等字段。
|
||||
</para>
|
||||
<para>
|
||||
人员(Person)表中将包括<literal>pid</literal>,
|
||||
<literal>birthday</literal>,
|
||||
<literal>initial</literal>,
|
||||
<literal>first</literal>和
|
||||
<literal>last</literal>等字段。</para>
|
||||
|
||||
<para>
|
||||
就像所有的值类型一样, Component不支持共享引用。
|
||||
换句话说,两个人可能重名,但是两个person对象应该包含两个独立的name对象,只不过是具有“同样”的值。
|
||||
Component的值为空从语义学上来讲是<emphasis>专有的(ad hoc)</emphasis>。 每当
|
||||
重新加载一个包含组件的对象,如果component的所有字段为空,那么将Hibernate将假定整个component为
|
||||
空。对于绝大多数目的,这样假定是没有问题的。
|
||||
</para>
|
||||
<para>
|
||||
就像所有的值类型一样, 组件不支持共享引用。
|
||||
换句话说,两个人可能重名,但是两个Person对象应该包含两个独立的Name对象,只不过这两个Name对象具有“同样”的值。
|
||||
组件的值可以为空,其定义如下。
|
||||
每当Hibernate重新加载一个包含组件的对象,如果该组件的所有字段为空,Hibernate将假定整个组件为空。
|
||||
在大多数情况下,这样假定应该是没有问题的。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Component的属性可以是Hibernate类型(包括Collections, many-to-one 关联, 以及其它Component
|
||||
等等)。嵌套Component不应该作为特殊的应用被考虑(Nested components should not be considered
|
||||
an exotic usage)。 Hibernate趋向于支持设计细致(fine-grained)的对象模型。
|
||||
</para>
|
||||
<para>
|
||||
组件的属性可以是任意一种Hibernate类型(包括集合, 多对多关联,
|
||||
以及其它组件等等)。嵌套组件不应该被当作一种特殊的应用(Nested components should not be considered an
|
||||
exotic usage)。 Hibernate倾向于支持细致的(fine-grained)对象模型。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal><component></literal> 元素还允许有 <literal><parent></literal>子元素,用来表明component类中的一个属性是指向包含它的实体的引用。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal><component></literal> 元素还允许有 <literal><parent></literal>子元素 ,用来表明component类中的一个属性返回包含它的实体的引用。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<id name="Key" column="pid" type="string">
|
||||
<generator class="uuid"/>
|
||||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name" unique="true">>
|
||||
<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>
|
||||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-incollections" revision="1">
|
||||
<title>在集合中出现的依赖对象</title>
|
||||
<sect1 id="components-incollections" revision="1">
|
||||
<title>在集合中出现的依赖对象 (Collections of dependent objects)</title>
|
||||
|
||||
<para>
|
||||
Hibernate支持component的集合(例如: 一个元素是“姓名”这种类型的数组)。 你可以使用<literal><composite-element></literal>标签替代<literal><element></literal>标签来定义你的component集合。
|
||||
</para>
|
||||
<para>
|
||||
Hibernate支持组件的集合(例如: 一个元素是姓名(Name)这种类型的数组)。
|
||||
你可以使用<literal><composite-element></literal>标签替代<literal><element></literal>标签来定义你的组件集合。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
|
||||
<key column="id"/>
|
||||
<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"/>
|
||||
<property name="last"/>;
|
||||
</composite-element>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
注意,如果你决定定义一个元素是联合元素的<literal>Set</literal>,正确地实现<literal>equals()</literal>和<literal>hashCode()</literal>是非常重要的。
|
||||
</para>
|
||||
<para>
|
||||
注意,如果你定义的Set包含组合元素(composite-element),正确地实现<literal>equals()</literal>和<literal>hashCode()</literal>是非常重要的。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
组合元素可以包含component但是不能包含集合。如果你的组合元素自身包含component, 必须使用<literal><nested-composite-element></literal>标签。这是一个相当特殊的案例 - 组合元素的集合自身可以包含component。 这个时候你就应该考虑一下使用one-to-many关联是否会更恰当。 尝试对这个组合元素重新建模为一个实体-但是需要注意的是,虽然Java模型和重新建模前 是一样的,关系模型和持久性语义上仍然存在轻微的区别。
|
||||
</para>
|
||||
<para>
|
||||
组合元素可以包含组件,但是不能包含集合。如果你的组合元素自身包含组件, 你必须使用<literal><nested-composite-element></literal>标签。这是一个相当特殊的案例 - 在一个组件的集合里,那些组件本身又可以包含其他的组件。这个时候你就应该考虑一下使用one-to-many关联是否会更恰当。
|
||||
尝试对这个组合元素重新建模为一个实体-但是需要注意的是,虽然Java模型和重新建模前是一样的,关系模型和持久性语义会有细微的变化。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
请注意如果你使用<literal><set></literal>标签,一个组合元素的映射不支持可能为空的属性. 当删除对象时, Hibernate必须使用每一个字段的来确定一条记录(在组合元素表中,没有单个的关键字段), 如果有为null的字段,这样做就不可能了。你必须作出一个选择,要么在组合元素中使用不能为空的属性, 要么选择使用<literal><list></literal>, <literal><map></literal>,<literal><bag></literal> 或者 <literal><idbag></literal>而不是 <literal><set></literal>。
|
||||
</para>
|
||||
<para>
|
||||
请注意如果你使用<literal><set></literal>标签,一个组合元素的映射不支持可能为空的属性. 当删除对象时, Hibernate必须使用每一个字段的值来确定一条记录(在组合元素表中,没有单独的关键字段),
|
||||
如果有为null的字段,这样做就不可能了。你必须作出一个选择,要么在组合元素中使用不能为空的属性,要么选择使用<literal><list></literal>,<literal><map></literal>,<literal><bag></literal> 或者 <literal><idbag></literal>而不是 <literal><set></literal>。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
组合元素有个特别的案例,是组合元素可以包含一个<literal><many-to-one></literal> 元素。类似这样的映射允许你映射一个many-to-mang关联表作为组合元素额外的字段。(A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从<literal>Order</literal>到<literal>Item</literal>的一个多对多的关联关系,而 <literal>purchaseDate</literal>, <literal>price</literal> 和 <literal>quantity</literal> 是<literal>Item</literal>的关联属性。
|
||||
</para>
|
||||
<para>
|
||||
组合元素有个特别的用法是它可以包含一个<literal><many-to-one></literal>元素。类似这样的映射允许你将一个many-to-many关联表映射为组合元素的集合。(A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从<literal>Order</literal>到<literal>Item</literal>的一个多对多的关联关系, 关联属性是 <literal>purchaseDate</literal>, <literal>price</literal> 和 <literal>quantity</literal> 。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
|
@ -168,14 +169,13 @@
|
|||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
<para>
|
||||
当然,在另一方面,无法存在指向purchase的关联,因此不能实现双向关联查询。记住组建是值类型,并且不允许共享关联。单个<literal>Purchase</literal> 可以放在包含<literal>Order</literal>的集合中,但它不能同时被<literal>Item</literal>所关联。
|
||||
</para>
|
||||
<para>
|
||||
当然,当你定义Item时,你无法引用这些purchase,因此你无法实现双向关联查询。记住组件是值类型,并且不允许共享引用。某一个特定的<literal>Purchase</literal> 可以放在<literal>Order</literal>的集合中,但它不能同时被<literal>Item</literal>所引用。
|
||||
</para>
|
||||
|
||||
<para>其实组合元素的这个用法可以扩展到三重或多重关联:</para>
|
||||
|
||||
<para>即使三重或多重管理都是可能的:</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
|
@ -186,52 +186,51 @@
|
|||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
在查询中,表达组合元素的语法和关联到其他实体的语法是一样的。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-asmapindex">
|
||||
<title>组件作为Map的索引(Components as Map indices )</title>
|
||||
|
||||
<para>
|
||||
<literal><composite-map-key></literal>元素允许你映射一个组件类作为一个<literal>Map</literal>的key,前提是你必须正确的在这个类中重写了<literal>hashCode()</literal> 和 <literal>equals()</literal>方法。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-compositeid" revision="1">
|
||||
<title>组件作为联合标识符(Components as composite identifiers)</title>
|
||||
|
||||
<para>
|
||||
你可以使用一个组件作为一个实体类的标识符。 你的组件类必须满足以下要求:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
在查询中,组合元素使用的语法是和关联到其他实体的语法一样的。
|
||||
它必须实现<literal>java.io.Serializable</literal>接口
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-asmapindex">
|
||||
<title>组件作为Map的索引(Components as Map indices )</title>
|
||||
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal><composite-map-key></literal>元素允许你映射一个Component类作为<literal>Map</literal>的key, 但是你必须确定你正确的在这个类中重写了<literal>hashCode()</literal> 和 <literal>equals()</literal>方法。
|
||||
它必须重新实现<literal>equals()</literal>和<literal>hashCode()</literal>方法, 始终和组合关键字在数据库中的概念保持一致
|
||||
</para>
|
||||
</sect1>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<sect1 id="components-compositeid" revision="1">
|
||||
<title>组件作为联合标识符(Components as composite identifiers)</title>
|
||||
<para>
|
||||
<emphasis>注意:在Hibernate3中,第二个要求并非是Hibernate强制必须的。但最好这样做。</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
你可以使用一个component作为一个实体类的标识符。 你的component类必须满足以下要求:
|
||||
</para>
|
||||
<para>
|
||||
你不能使用一个<literal>IdentifierGenerator</literal>产生组合关键字。一个应用程序必须分配它自己的标识符。
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
它必须实现<literal>java.io.Serializable</literal>接口
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
它必须重新实现<literal>equals()</literal>和<literal>hashCode()</literal>方法, 始终和组合关键字在数据库中的概念保持一致
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>注意:在Hibernate3中,第二种要求并非是Hibernate强制必须的。但最好这样做。</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
你不能使用一个<literal>IdentifierGenerator</literal>产生组合关键字。作为替代应用程序必须分配它自己的标识符。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
使用<literal><composite-id></literal> 标签(并且内嵌<literal><key-property></literal>元素)代替通常的<literal><id></literal>标签。 比如,<literal>OrderLine</literal>类具有一个依赖<literal>Order</literal>的(联合)主键的主键。
|
||||
|
||||
</para>
|
||||
<para>
|
||||
使用<literal><composite-id></literal> 标签(并且内嵌<literal><key-property></literal>元素)代替通常的<literal><id></literal>标签。比如,<literal>OrderLine</literal>类具有一个主键,这个主键依赖于<literal>Order</literal>的(联合)主键。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
|
||||
|
@ -252,10 +251,9 @@
|
|||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
||||
现在,任何关联到<literal>OrderLine</literal> 的外键都是复合的。在你的映射文件中,必须为其他类也这样声明。指向<literal>OrderLine</literal>的关联可能被这样映射:
|
||||
</para>
|
||||
<para>
|
||||
现在,任何指向<literal>OrderLine</literal>的外键都是复合的。在你的映射文件中,必须为其他类也这样声明。例如,一个指向<literal>OrderLine</literal>的关联可能被这样映射:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
|
||||
<!-- the "class" attribute is optional, as usual -->
|
||||
|
@ -264,16 +262,14 @@
|
|||
<column name="customerId"/>
|
||||
</many-to-one>]]></programlisting>
|
||||
|
||||
<para>
|
||||
|
||||
(注意在各个地方<literal><column></literal>标签都是<literal>column</literal>属性的替代写法。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
指向<literal>OrderLine</literal>的<literal>多对多</literal>关联也使用联合外键:
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
(注意在各个地方<literal><column></literal>标签都是<literal>column</literal>属性的替代写法。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
指向<literal>OrderLine</literal>的<literal>多对多</literal>关联也使用联合外键:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="undeliveredOrderLines">
|
||||
<key column name="warehouseId"/>
|
||||
<many-to-many class="OrderLine">
|
||||
|
@ -283,9 +279,9 @@
|
|||
</many-to-many>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
在<literal>Order</literal>中, <literal>OrderLine</literal>的集合则是这样:
|
||||
</para>
|
||||
<para>
|
||||
在<literal>Order</literal>中,<literal>OrderLine</literal>的集合则是这样:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="orderLines" inverse="true">
|
||||
<key>
|
||||
|
@ -295,13 +291,13 @@
|
|||
<one-to-many class="OrderLine"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(与通常一样,<literal><one-to-many></literal>元素不声明任何列.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
假若<literal>OrderLine</literal>本身拥有一个集合,它也具有组合外键。
|
||||
</para>
|
||||
<para>
|
||||
(与通常一样,<literal><one-to-many></literal>元素不声明任何列.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
假若<literal>OrderLine</literal>本身拥有一个集合,它也具有组合外键。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
....
|
||||
|
@ -319,13 +315,14 @@
|
|||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-dynamic" revision="1">
|
||||
<title>动态组件 (Dynamic components)</title>
|
||||
<para>
|
||||
你甚至可以映射<literal>Map</literal>类型的属性:
|
||||
</para>
|
||||
<sect1 id="components-dynamic" revision="1">
|
||||
<title>动态组件 (Dynamic components)</title>
|
||||
|
||||
<para>
|
||||
你甚至可以映射<literal>Map</literal>类型的属性:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
||||
<property name="foo" column="FOO" type="string"/>
|
||||
|
@ -333,11 +330,10 @@
|
|||
<many-to-one name="baz" class="Baz" column="BAZ_ID"/>
|
||||
</dynamic-component>]]></programlisting>
|
||||
|
||||
<para>
|
||||
从<literal><dynamic-component></literal>映射的语义上来讲,它和<literal><component></literal>是相同的。
|
||||
这种映射类型的优点在于通过修改映射文件,就可以具有在部署时检测真实属性的能力.利用一个DOM解析器,是有可能在运行时刻操作映射文件的。
|
||||
更好的是,你可以通过<literal>Configuration</literal>对象来访问(或者修改)Hibernate的运行时元模型。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
<para>
|
||||
从<literal><dynamic-component></literal>映射的语义上来讲,它和<literal><component></literal>是相同的。
|
||||
这种映射类型的优点在于通过修改映射文件,就可以具有在部署时检测真实属性的能力。利用一个DOM解析器,也可以在程序运行时操作映射文件。
|
||||
更好的是,你可以通过<literal>Configuration</literal>对象来访问(或者修改)Hibernate的运行时元模型。
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
|
@ -8,7 +8,7 @@
|
|||
由于Hibernate是为了能在各种不同环境下工作而设计的, 因此存在着大量的配置参数. 幸运的是多数配置参数都
|
||||
有比较直观的默认值, 并有随Hibernate一同分发的配置样例<literal>hibernate.properties</literal>
|
||||
(位于<literal>etc/</literal>)来展示各种配置选项. 所需做的仅仅是将这个样例文件复制到类路径
|
||||
(classpath)下做一些自定义的修改.
|
||||
(classpath)下并做一些自定义的修改.
|
||||
</para>
|
||||
|
||||
<sect1 id="configuration-programmatic" revision="1">
|
||||
|
@ -90,11 +90,11 @@
|
|||
</orderedlist>
|
||||
|
||||
<para>
|
||||
如果想尽快体验Hbernate, <literal>hibernate.properties</literal>是最简单的方式.
|
||||
如果想尽快体验Hibernate, <literal>hibernate.properties</literal>是最简单的方式.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Configuration</literal>实例是一个启动期间(startup-time)的对象,
|
||||
<literal>Configuration</literal>实例被设计成启动期间(startup-time)对象,
|
||||
一旦<literal>SessionFactory</literal>创建完成它就被丢弃了.
|
||||
</para>
|
||||
|
||||
|
@ -211,9 +211,9 @@
|
|||
|
||||
<para>
|
||||
但Hibernate自带的连接池算法相当不成熟.
|
||||
它只是为了让你快些上手<emphasis>,不适合用于产品系统</emphasis>或性能测试中。
|
||||
出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要连接池的特定设置替换
|
||||
<literal>hibernate.connection.pool_size</literal>。这将关闭Hibernate自带的连接池.
|
||||
它只是为了让你快些上手<emphasis>,并不适合用于产品系统</emphasis>或性能测试中。
|
||||
出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要用特定连接池的设置替换
|
||||
<literal>hibernate.connection.pool_size</literal>即可。这将关闭Hibernate自带的连接池.
|
||||
例如, 你可能会想用C3P0.
|
||||
</para>
|
||||
|
||||
|
@ -239,8 +239,8 @@ hibernate.c3p0.max_statements=50
|
|||
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
||||
|
||||
<para>
|
||||
为了能在应用程序服务器(application server)中使用Hibernate, 你应当总是将Hibernate
|
||||
配置成注册在JNDI中的<literal>Datasource</literal>处获得连接,你至少需要设置下列属性中的一个:
|
||||
为了能在应用程序服务器(application server)中使用Hibernate, 应当总是将Hibernate
|
||||
配置成从注册在JNDI中的<literal>Datasource</literal>处获得连接,你至少需要设置下列属性中的一个:
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
|
@ -306,7 +306,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</table>
|
||||
|
||||
<para>
|
||||
这里有一个使用应用程序服务器JNDI数据源的<literal>hibernate.properties</literal>样例文件:
|
||||
这是一个使用应用程序服务器提供的JNDI数据源的<literal>hibernate.properties</literal>样例文件:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
|
||||
|
@ -317,12 +317,12 @@ hibernate.transaction.manager_lookup_class = \
|
|||
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
||||
|
||||
<para>
|
||||
从JNDI数据源获得的JDBC连接将自动参与应用程序服务器中容器管理的事务(container-managed transactions)中去.
|
||||
从JNDI数据源获得的JDBC连接将自动参与到应用程序服务器中容器管理的事务(container-managed transactions)中去.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
任何连接(connection)配置属性的属性名要以"<literal>hibernate.connnection</literal>"前缀开头.
|
||||
例如, 你可能会使用<literal>hibernate.connection.charSet</literal>来指定<literal>charSet</literal>.
|
||||
任何连接(connection)属性的属性名都要以"<literal>hibernate.connnection</literal>"开头.
|
||||
例如, 你可能会使用<literal>hibernate.connection.charSet</literal>来指定字符集<literal>charSet</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -344,7 +344,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
|
||||
<para>
|
||||
<emphasis>警告: 其中一些属性是"系统级(system-level)的".</emphasis>
|
||||
系统级属性可以通过<literal>java -Dproperty=value</literal>或
|
||||
系统级属性只能通过<literal>java -Dproperty=value</literal>或
|
||||
<literal>hibernate.properties</literal>来设置, 而<emphasis>不能</emphasis>用上面描述的其他方法来设置.
|
||||
</para>
|
||||
|
||||
|
@ -375,7 +375,8 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<para>
|
||||
<emphasis role="strong">取值</emphasis>
|
||||
<literal>full.classname.of.Dialect</literal>
|
||||
</para>
|
||||
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
|
@ -420,7 +421,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.default_catalog</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
在生成的SQL中, 将给定的catalog附加于没全限定名的表名上.
|
||||
在生成的SQL中, 将给定的catalog附加于非全限定名的表名上.
|
||||
<para>
|
||||
<emphasis role="strong">取值</emphasis>
|
||||
<literal>CATALOG_NAME</literal>
|
||||
|
@ -781,7 +782,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.cache.query_cache_factory</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
自定义的实现<literal>QueryCache</literal>接口的类名,
|
||||
自定义实现<literal>QueryCache</literal>接口的类名,
|
||||
默认为内建的<literal>StandardQueryCache</literal>.
|
||||
<para>
|
||||
<emphasis role="strong">取值</emphasis>
|
||||
|
@ -925,8 +926,8 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.current_session_context_class</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
为界定"当前"
|
||||
<literal>Session</literal>指定一个策略。关于内置策略的详情,请参见<xref linkend="architecture-current-session"/> 。
|
||||
为"当前"
|
||||
<literal>Session</literal>指定一个(自定义的)策略。关于内置策略的详情,请参见<xref linkend="architecture-current-session"/> 。
|
||||
<para>
|
||||
<emphasis role="strong">eg.</emphasis>
|
||||
<literal>jta</literal> | <literal>thread</literal> |
|
||||
|
@ -965,7 +966,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<literal>hibernate.hbm2ddl.auto</literal>
|
||||
</entry>
|
||||
<entry>
|
||||
在<literal>SessionFactory</literal>创建时,自动检查数据库机构,或者将数据库schema的DDL导出到数据库. 使用
|
||||
在<literal>SessionFactory</literal>创建时,自动检查数据库结构,或者将数据库schema的DDL导出到数据库. 使用
|
||||
<literal>create-drop</literal>时,在显式关闭<literal>SessionFactory</literal>时,将drop掉数据库schema.
|
||||
<para>
|
||||
<emphasis role="strong">取值</emphasis>
|
||||
|
@ -997,7 +998,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</title>
|
||||
|
||||
<para>
|
||||
你应当总是为你的数据库属性<literal>hibernate.dialect</literal>设置正确的
|
||||
你应当总是为你的数据库将<literal>hibernate.dialect</literal>属性设置成正确的
|
||||
<literal>org.hibernate.dialect.Dialect</literal>子类. 如果你指定一种方言,
|
||||
Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫.
|
||||
</para>
|
||||
|
@ -1096,8 +1097,8 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</title>
|
||||
|
||||
<para>
|
||||
如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, <emphasis>外连接抓取</emphasis>常能通过限制往返数据库次数
|
||||
(更多的工作交由数据库自己来完成)来提高效率. 外连接允许在单个<literal>SELECT</literal>SQL语句中,
|
||||
如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, <emphasis>外连接抓取</emphasis>通常能通过限制往返数据库次数
|
||||
(更多的工作交由数据库自己来完成)来提高效率. 外连接抓取允许在单个<literal>SELECT</literal>SQL语句中,
|
||||
通过many-to-one, one-to-many, many-to-many和one-to-one关联获取连接对象的整个对象图.
|
||||
</para>
|
||||
|
||||
|
@ -1283,7 +1284,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
|
||||
<para>
|
||||
在使用Hibernate开发应用程序时, 你应当总是为<literal>org.hibernate.SQL</literal>
|
||||
开启<literal>debug</literal>级别的日志记录,或者开启<literal>hibernate.show_sql</literal>属性来代替它。.
|
||||
开启<literal>debug</literal>级别的日志记录,或者开启<literal>hibernate.show_sql</literal>属性。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -1328,7 +1329,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
|
||||
<para>
|
||||
另一个配置方法是在<literal>hibernate.cfg.xml</literal>文件中指定一套完整的配置.
|
||||
这个文件可以当成<literal>hibernate.properties</literal>的替代。 若两个文件同时存在,它将重载前者的属性.
|
||||
这个文件可以当成<literal>hibernate.properties</literal>的替代。 若两个文件同时存在,它将覆盖前者的属性.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -1406,7 +1407,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<listitem>
|
||||
<para>
|
||||
<emphasis>容器管理的数据源(Container-managed datasources)</emphasis>:
|
||||
Hibernate能通过容器管理由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候,
|
||||
Hibernate能使用通过容器管理,并由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候,
|
||||
由一个JTA兼容的<literal>TransactionManager</literal>和一个
|
||||
<literal>ResourceManager</literal>来处理事务管理(CMT, 容器管理的事务). 当然你可以通过
|
||||
编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性,你也也许会想使用可选的
|
||||
|
@ -1430,7 +1431,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<emphasis>JTA Session绑定:</emphasis> Hibernate <literal>Session</literal>
|
||||
可以自动绑定到JTA事务作用的范围. 只需简单地从JNDI查找<literal>SessionFactory</literal>并获得当前的
|
||||
<literal>Session</literal>. 当JTA事务完成时, 让Hibernate来处理
|
||||
<literal>Session</literal>的清洗(flush)与关闭. 在EJB的部署描述符中事务边界是声明式的(CMT),或者自行编程(BMT/UserTransaction).
|
||||
<literal>Session</literal>的清洗(flush)与关闭. 事务的划分可以是声明式的(CMT),也可以是编程式的(BMT/UserTransaction).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -1440,7 +1441,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<para>
|
||||
<emphasis>JMX部署:</emphasis> 如果你使用支持JMX应用程序服务器(如, JBoss AS), 那么你可以选择将Hibernate部署成托管MBean.
|
||||
这将为你省去一行从<literal>Configuration</literal>构建<literal>SessionFactory</literal>的启动代码.
|
||||
容器将启动你的<literal>HibernateService</literal>, 并完美地处理好服务间的依赖关系 (在Hibernate启动前,数据源必须是可用的等等).
|
||||
容器将启动你的<literal>HibernateService</literal>, 并完美地处理好服务间的依赖关系 (在Hibernate启动前,数据源必须是可用的,等等).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
@ -1466,7 +1467,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</para>
|
||||
|
||||
<para>
|
||||
存在着三个标准(内建)的选择:
|
||||
有三个标准(内建)的选择:
|
||||
</para>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
|
@ -1610,7 +1611,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
<title>在JTA环境下使用Current Session context (当前session上下文)管理</title>
|
||||
|
||||
<para>
|
||||
在Hibernate中,管理<literal>Session</literal>和transaction最好的方法是自动的"当前"<literal>Session</literal>管理。请参见<xref linkend="architecture-current-session">current sessions</xref>一节的讨论。使用<literal>"jta"</literal>session上下文,假若在当前JTA事务中还没有Hibernate<literal>Session</literal>关联,第一次<literal>sessionFactory.getCurrentSession()</literal>调用会启动一个Session,并关联到当前的JTA事务。在<literal>"jta"</literal>上下文中用<literal>getCurrentSession()</literal>获得的<literal>Session</literal>,会被设置为在transaction关闭的时候自动flush(清洗)、在transaction关闭之后自动关闭,每句与句之后主动释放JDBC连接。这就可以根据JTA事务的生命周期来管理与之关联的<literal>Session</literal>,用户代码中就可以不再考虑这些管理。你的代码可以通过<literal>UserTransaction</literal>用编程方式使用JTA,或者(我们建议,为了便于移植代码)使用Hibernate的<literal>Transaction</literal> API来设置transaction边界。如果你的代码运行于EJB容器中,建议对CMT使用声明式事务声明。
|
||||
在Hibernate中,管理<literal>Session</literal>和transaction最好的方法是自动的"当前"<literal>Session</literal>管理。请参见<xref linkend="architecture-current-session">contextual sessions</xref>一节的讨论。使用<literal>"jta"</literal>session上下文,假若在当前JTA事务中还没有Hibernate<literal>Session</literal>关联,第一次<literal>sessionFactory.getCurrentSession()</literal>调用会启动一个Session,并关联到当前的JTA事务。在<literal>"jta"</literal>上下文中调用<literal>getCurrentSession()</literal>获得的<literal>Session</literal>,会被设置为在transaction关闭的时候自动flush(清洗)、在transaction关闭之后自动关闭,每句语句之后主动释放JDBC连接。这就可以根据JTA事务的生命周期来管理与之关联的<literal>Session</literal>,用户代码中就可以不再考虑这些管理。你的代码也可以通过<literal>UserTransaction</literal>用编程方式使用JTA,或者(我们建议,为了便于移植代码)使用Hibernate的<literal>Transaction</literal> API来设置transaction边界。如果你的代码运行在EJB容器中,建议对CMT使用声明式事务声明。
|
||||
|
||||
</para>
|
||||
</sect2>
|
||||
|
@ -1620,7 +1621,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
</title>
|
||||
|
||||
<para>
|
||||
为了将<literal>SessionFactory</literal>注册到JNDI中<literal>cfg.buildSessionFactory()</literal>这行代码仍需在某处被执行.
|
||||
为了将<literal>SessionFactory</literal>注册到JNDI中,<literal>cfg.buildSessionFactory()</literal>这行代码仍需在某处被执行.
|
||||
你可在一个<literal>static</literal>初始化块(像<literal>HibernateUtil</literal>中的那样)中执行它或将Hibernate部署为一个<emphasis>托管的服务</emphasis>.
|
||||
</para>
|
||||
|
||||
|
@ -1675,9 +1676,9 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
|
|||
|
||||
<para>
|
||||
这个文件是部署在<literal>META-INF</literal>目录下的, 并会被打包到以<literal>.sar</literal> (service archive)为扩展名的JAR文件中.
|
||||
同时,你需要打包Hibernate, 它所需要的第三方库, 你编译好的持久化类及你的映射定义文件打包进同一个文档.
|
||||
同时,你需要将Hibernate、它所需要的第三方库、你编译好的持久化类以及你的映射定义文件打包进同一个文档.
|
||||
你的企业Bean(一般为会话Bean)可能会被打包成它们自己的JAR文件, 但你也许会将EJB JAR文件一同包含进能独立(热)部署的主服务文档.
|
||||
咨询JBoss AS文档以了解更多的JMX服务与EJB部署的信息.
|
||||
参考JBoss AS文档以了解更多的JMX服务与EJB部署的信息.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
|
|
@ -51,9 +51,8 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
在不同的映射文件中定义 <literal>subclass</literal>, <literal>union-subclass</literal>,
|
||||
和 <literal>joined-subclass</literal>是被允许的,只需直接定义在<literal>hibernate-mapping</literal>之下 。也就是说,你可以仅加入一个新的映射文件就扩展类层次。你必须在subclass的映射中指明<literal>extends</literal>属性,给出一个之前定义的超类的名字。注意,以前,这一功能对映射文件的顺序有严格的要求。自从Hibernate 3开始,当使用extends关键字的时候,映射文件的顺序不再有影响。但在每个映射文件本身之中,顺序还是必须超类在前,子类在后。
|
||||
</para>
|
||||
在多个映射文件中,可以直接在<literal>hibernate-mapping</literal>根下定义<literal>subclass</literal>,<literal>union-subclass</literal>和<literal>joined-subclass</literal>。也就是说,你可以仅加入一个新的映射文件来扩展类层次。你必须在subclass的映射中指明<literal>extends</literal>属性,给出一个之前定义的超类的名字。注意,在以前,这一功能对映射文件的顺序有严格的要求,从Hibernate 3开始,使用extends关键字的时侯,对映射文件的顺序不再有要求;但在每个映射文件里,超类必须在子类之前定义。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<hibernate-mapping>
|
||||
|
@ -142,7 +141,7 @@
|
|||
注意,对“每个子类一张表”的映射策略,Hibernate的实现不需要辨别字段,而其他
|
||||
的对象/关系映射工具使用了一种不同于Hibernate的实现方法,该方法要求在超类
|
||||
表中有一个类型辨别字段(type discriminator column)。Hibernate采用的方法更
|
||||
难实现,但从关系(数据库)这点上来看,按理说它更正确。若你愿意使用带有辨别字
|
||||
难实现,但从关系(数据库)的角度来看,按理说它更正确。若你愿意使用带有辨别字
|
||||
段的“每个子类一张表”的策略,你可以结合使用<literal><subclass></literal>
|
||||
与<literal><join></literal>,如下所示:
|
||||
</para>
|
||||
|
@ -408,7 +407,7 @@
|
|||
<entry>多态 <literal>load()/get()</literal></entry>
|
||||
<entry>多态查询</entry>
|
||||
<entry>多态连接(join)</entry>
|
||||
<entry>外连接(Outer join)抓取</entry>
|
||||
<entry>外连接(Outer join)读取</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -465,4 +464,4 @@
|
|||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
|
||||
<para>
|
||||
如果这些持久化类遵循一些简单的规则,Hibernate能够工作得最好,这些规则被称作,
|
||||
简单传统Java对象(POJO:Plain Old Java Object)编程模型。但是这些规则没有一个是必需的。
|
||||
如果这些持久化类遵循一些简单的规则,Hibernate能够工作得更好,这些规则也被称作
|
||||
简单传统Java对象(POJO:Plain Old Java Object)编程模型。但是这些规则并不是必需的。
|
||||
实际上,Hibernate3对于你的持久化类几乎不做任何设想。你可以用其他的方法来表达领域模型:
|
||||
比如,使用<literal>Map</literal>实例的树型结构。
|
||||
</para>
|
||||
|
@ -115,7 +115,7 @@ public class Cat {
|
|||
<literal>Cat</literal>有一个无参数的构造方法。所有的持久化类都必须有一个
|
||||
默认的构造方法(可以不是public的),这样的话Hibernate就可以使用
|
||||
<literal>Constructor.newInstance()</literal>来实例化它们。
|
||||
我们建议,在Hibernate中,为了运行期代理的生成,构造方法至少是
|
||||
我们强烈建议,在Hibernate中,为了运行期代理的生成,构造方法至少是
|
||||
<emphasis>包(package)</emphasis>内可见的。
|
||||
</para>
|
||||
|
||||
|
@ -128,14 +128,14 @@ public class Cat {
|
|||
<literal>Cat</literal>有一个属性叫做<literal>id</literal>。这个属性映射数据库表的主
|
||||
键字段。这个属性可以叫任何名字,其类型可以是任何的原始类型、原始类型的包装类型、
|
||||
<literal>java.lang.String</literal> 或者是 <literal>java.util.Date</literal>。
|
||||
(如果你的老式数据库表有联合主键,你甚至可以用一个用户自定义的类,该类拥有这些类型
|
||||
(如果你的遗留数据库表有联合主键,你甚至可以用一个用户自定义的类,该类拥有这些类型
|
||||
的属性。参见后面的关于联合标识符的章节。)
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
标识符属性是可选的。可以不用管它,让Hibernate内部来追踪对象的识别。
|
||||
不推荐使用这个属性。
|
||||
但是我们并不推荐这样做。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -146,7 +146,7 @@ public class Cat {
|
|||
<listitem>
|
||||
|
||||
<para>
|
||||
托管对象的传播性重新(和session)关联(级联更新或级联合并)
|
||||
托管对象的传播性再连接(级联更新或级联合并)
|
||||
——参阅 <xref linkend="objectstate-transitive"/>
|
||||
</para>
|
||||
|
||||
|
@ -165,8 +165,8 @@ public class Cat {
|
|||
|
||||
|
||||
<para>
|
||||
我们建议你对持久化类声明命名一致的标识属性。我们还建议你使用一
|
||||
个可以为空(也就是说,不是原始类型)的类型。
|
||||
我们建议你对持久化类声明命名一致的标识属性。我们还建议你使用一
|
||||
个可以为空(也就是说,不是原始类型)的类型。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -185,28 +185,28 @@ public class Cat {
|
|||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
你也应该避免在非final类中声明 <literal>public final</literal>的方法。如果你想使用一
|
||||
个有<literal>public final</literal>方法的类,你必须通过设置<literal>lazy="false"</literal>
|
||||
来明确的禁用代理。
|
||||
</para>
|
||||
<para>
|
||||
你也应该避免在非final类中声明 <literal>public final</literal>的方法。如果你想使用一
|
||||
个有<literal>public final</literal>方法的类,你必须通过设置<literal>lazy="false"</literal>
|
||||
来明确地禁用代理。
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-accessors" revision="2">
|
||||
<title>为持久化字段声明访问器(accessors)和是否可变的标志(mutators)(可选)</title>
|
||||
<title>为持久化字段声明访问器(accessors)和是否可变的标志(mutators)(可选)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal>为它的所有持久化字段声明了访问方法。很多其他ORM工具直接对
|
||||
实例变量进行持久化。我们相信,在关系数据库schema和类的内部数据之间引入间接层(原文为"非直接",indirection)会好一些。默认情况下Hibernate持久化JavaBeans风格的属性,认可如下形式的方法名:
|
||||
<literal>getFoo</literal>, <literal>isFoo</literal> 和 <literal>setFoo</literal>。
|
||||
如果需要,你总是可以切换特定的属性的指示字段的访问方法。
|
||||
实例变量进行持久化。我们相信,在关系数据库schema和类的内部数据结构之间引入间接层(原文为"非直接",indirection)会好一些。默认情况下Hibernate持久化JavaBeans风格的属性,认可
|
||||
<literal>getFoo</literal>,<literal>isFoo</literal> 和 <literal>setFoo</literal>这种形式的方法名。
|
||||
如果需要,你可以对某些特定属性实行直接字段访问。
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
属性<emphasis>不需要</emphasis>要声明为public的。Hibernate默认使用
|
||||
<literal>protected</literal>或<literal>private</literal>的get/set方法对,
|
||||
对属性进行持久化。
|
||||
属性<emphasis>不需要</emphasis>要声明为public的。Hibernate可以持久化一个有
|
||||
<literal>default</literal>、<literal>protected</literal>或<literal>private</literal>的get/set方法对
|
||||
的属性进行持久化。
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
@ -254,8 +254,8 @@ public class DomesticCat extends Cat {
|
|||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Hibernate保证,持久化标识(数据库的行)和仅在特定会话范围内的Java标识是等值的。因此,一旦
|
||||
我们混合了从不同会话中获取的实例,如果我们希望<literal>Set</literal>有明确的语义,我们必
|
||||
Hibernate保证,仅在特定会话范围内,持久化标识(数据库的行)和Java标识是等价的。因此,一旦
|
||||
我们混合了从不同会话中获取的实例,如果希望<literal>Set</literal>有明确的语义,就必
|
||||
须实现<literal>equals()</literal> 和<literal>hashCode()</literal>。
|
||||
</para>
|
||||
|
||||
|
@ -264,16 +264,15 @@ public class DomesticCat extends Cat {
|
|||
标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此它们是相等的(如果都被添加到
|
||||
<literal>Set</literal>,则在<literal>Set</literal>中只有一个元素)。不幸的是,对生成的标识不能
|
||||
使用这种方法。Hibernate仅对那些持久化对象赋标识值,一个新创建的实例将不会有任何标识值。此外,
|
||||
如果一个实例没有被保存(unsaved),并且在一个<literal>Set</literal>中,保存它将会给这个对象
|
||||
如果一个实例没有被保存(unsaved),并且它当前正在一个<literal>Set</literal>中,保存它将会给这个对象
|
||||
赋一个标识值。如果<literal>equals()</literal> 和 <literal>hashCode()</literal>是基于标识值
|
||||
实现的,则其哈希码将会改变,违反<literal>Set</literal>的契约。建议去Hibernate的站点看关于这个
|
||||
问题的全部讨论。注意,这不是一个Hibernate问题,而是一般的Java对象标识和相等的语义问题。
|
||||
实现的,则其哈希码将会改变,这违反了<literal>Set</literal>的契约。建议去Hibernate的站点阅读关于这个
|
||||
问题的全部讨论。注意,这不是Hibernate的问题,而是一般的Java对象标识和Java对象等价的语义问题。
|
||||
</para>
|
||||
<para>
|
||||
我们建议使用<emphasis>业务键值相等(Business key equality)</emphasis>来实现<literal>equals()</literal>
|
||||
和 <literal>hashCode()</literal>。业务键值相等的意思是,<literal>equals()</literal>方法
|
||||
仅仅比较来自业务键的属性,一个业务键将标识在真实世界里(一个<emphasis>天生的</emphasis>候选键)
|
||||
的实例。
|
||||
仅仅比较形成业务键的属性,它能在现实世界里标识我们的实例(是一个<emphasis>自然的</emphasis>候选码)。
|
||||
</para>
|
||||
<programlisting><![CDATA[public class Cat {
|
||||
|
||||
|
@ -300,8 +299,8 @@ public class DomesticCat extends Cat {
|
|||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
注意,业务键不必是象数据库的主键那样是固定不变的(参见<xref linkend="transactions-basics-identity"/>)。
|
||||
对业务键而言,不可变或唯一的属性是好的候选。
|
||||
注意,业务键不必像数据库的主键那样固定不变(参见<xref linkend="transactions-basics-identity"/>)。
|
||||
对业务键而言,不可变或唯一的属性是不错的选择。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
@ -309,11 +308,11 @@ public class DomesticCat extends Cat {
|
|||
<sect1 id="persistent-classes-dynamicmodels">
|
||||
<title>动态模型(Dynamic models)</title>
|
||||
<para>
|
||||
<emphasis>注意,以下特性在当前是基于实验考虑的,可能会在将来改变。</emphasis>
|
||||
<emphasis>注意,以下特性在当前处于试验阶段,将来可能会有变化。</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
运行期的持久化实体没有必要象POJO类或JavaBean对象一样表示。Hibernate也支持动态模型
|
||||
运行期的持久化实体没有必要一定表示为像POJO类或JavaBean对象那样的形式。Hibernate也支持动态模型
|
||||
(在运行期使用<literal>Map</literal>的<literal>Map</literal>)和象DOM4J的树模型那
|
||||
样的实体表示。使用这种方法,你不用写持久化类,只写映射文件就行了。
|
||||
</para>
|
||||
|
@ -327,7 +326,7 @@ public class DomesticCat extends Cat {
|
|||
|
||||
<para>
|
||||
下面是用<literal>Map</literal>来表示的例子。首先,在映射文件中,要声明
|
||||
<literal>entity-name</literal>来代替(或外加)一个类名。
|
||||
<literal>entity-name</literal>来代替一个类名(或作为一种附属)。
|
||||
</para>
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
|
@ -397,9 +396,9 @@ tx.commit();
|
|||
s.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
动态映射的好处是,使原型在不需要实体类实现的情况下,快速转变时间。然而,你无法进行
|
||||
动态映射的好处是,变化所需要的时间少了,因为原型不需要实现实体类。然而,你无法进行
|
||||
编译期的类型检查,并可能由此会处理很多的运行期异常。幸亏有了Hibernate映射,它使得数
|
||||
据库的schema能容易的规格化和合理化,并允许稍后添加正确的领域模型的最新实现。
|
||||
据库的schema能容易的规格化和合理化,并允许稍后在此之上添加合适的领域模型实现。
|
||||
</para>
|
||||
|
||||
|
||||
|
@ -440,11 +439,11 @@ dynamicSession.close()
|
|||
<title>元组片断映射(Tuplizers)</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.tuple.Tuplizer</literal>, 以及其子接口,负责根据给定的<literal>org.hibernate.EntityMode</literal>,来复现片断数据。对于给定的片断数据来说,可以认为其是一种数据结构, "tuplizer"就是一种映射器,它知道如何创建这样的数据结构,以及如何给这个数据结构赋值。比如说,对于POJO这种Entity Mode,对应的tuplizer知道通过其构造器来创建一个POJO,再通过其属性访问器来访问POJO属性。有两大类Tuplizer,分别是<literal>org.hibernate.tuple.EntityTuplizer</literal> 和<literal>org.hibernate.tuple.ComponentTuplizer</literal>接口。如前所示,<literal>EntityTuplizer</literal>负责管理实体,而<literal>ComponentTuplizer</literal>则是针对组件。
|
||||
<literal>org.hibernate.tuple.Tuplizer</literal>,以及其子接口,负责根据给定的<literal>org.hibernate.EntityMode</literal>,来复现片断数据。如果给定的片断数据被认为其是一种数据结构,"tuplizer"就是一个知道如何创建这样的数据结构,以及如何给这个数据结构赋值的东西。比如说,对于POJO这种Entity Mode,对应的tuplizer知道通过其构造方法来创建一个POJO,再通过其属性访问器来访问POJO属性。有两大类高层Tuplizer,分别是<literal>org.hibernate.tuple.EntityTuplizer</literal> 和<literal>org.hibernate.tuple.ComponentTuplizer</literal>接口。<literal>EntityTuplizer</literal>负责管理上面提到的实体的契约,而<literal>ComponentTuplizer</literal>则是针对组件的。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
用户也可以插入其自定义的tuplizer。或许您需要一种特别的<literal>java.util.Map</literal>实现,它不是在dynamic-map entity-mode时使用的 <literal>java.util.HashMap</literal> ;或许您需要与众不同的特别代理生成策略(proxy generation strategy)。通过自定义tuplizer实现,这两个目标您都可以达到。Tuplizer定义被附加到它们期望管理的entity或者component映射。回到我们的customer entity例子:
|
||||
用户也可以插入其自定义的tuplizer。或许您需要一种不同于dynamic-map entity-mode中使用的<literal>java.util.HashMap</literal>的<literal>java.util.Map</literal>实现;或许您需要与默认策略不同的代理生成策略(proxy generation strategy)。通过自定义tuplizer实现,这两个目标您都可以达到。Tuplizer定义被附加到它们期望管理的entity或者component映射中。回到我们的customer entity例子:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
@ -487,7 +486,7 @@ public class CustomMapTuplizerImpl
|
|||
</sect1>
|
||||
|
||||
<para>
|
||||
TODO:在property和proxy的包里,用户扩展文件框架。
|
||||
TODO:property和proxy包里的用户扩展框架文档。
|
||||
</para>
|
||||
|
||||
</chapter>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<para>
|
||||
<emphasis>瞬时(Transient)</emphasis> - 由<literal>new</literal>操作符创建,且尚未与Hibernate <literal>Session</literal>
|
||||
关联的对象被认定为瞬时(Transient)的。瞬时(Transient)对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。
|
||||
如果程序中没有保持对瞬时(Transient)对象的引用,它会被垃圾回收器(garbage collector)销毁。
|
||||
如果瞬时(Transient)对象在程序中没有被引用,它会被垃圾回收器(garbage collector)销毁。
|
||||
使用Hibernate <literal>Session</literal>可以将其变为持久(Persistent)状态。(Hibernate会自动执行必要的SQL语句)
|
||||
</para>
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
<para>
|
||||
<emphasis>持久(Persistent)</emphasis> - 持久(Persistent)的实例在数据库中有对应的记录,并拥有一个持久化标识(identifier)。
|
||||
持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义对象都仅在相关联的<literal>Session</literal>生命周期内的保持这种状态。
|
||||
持久(Persistent)的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的<literal>Session</literal>作用范围内。
|
||||
Hibernate会检测到处于持久(Persistent)状态的对象的任何改动,在当前操作单元(unit of work)执行完毕时将对象数据(state)与数据库同步(synchronize)。
|
||||
开发者不需要手动执行<literal>UPDATE</literal>。将对象从持久(Persistent)状态变成瞬时(Transient)状态同样也不需要手动执行<literal>DELETE</literal>语句。
|
||||
</para>
|
||||
|
@ -46,7 +46,7 @@
|
|||
<para>
|
||||
<emphasis>脱管(Detached)</emphasis> - 与持久(Persistent)对象关联的<literal>Session</literal>被关闭后,对象就变为脱管(Detached)的。
|
||||
对脱管(Detached)对象的引用依然有效,对象可继续被修改。脱管(Detached)对象如果重新关联到某个新的<literal>Session</literal>上,
|
||||
会再次转变为持久(Persistent)的(Detached其间的改动将被持久化到数据库)。
|
||||
会再次转变为持久(Persistent)的(在Detached其间的改动将被持久化到数据库)。
|
||||
这个功能使得一种编程模型,即中间会给用户思考时间(user think-time)的长时间运行的操作单元(unit of work)的编程模型成为可能。
|
||||
我们称之为<emphasis>应用程序事务</emphasis>,即从用户观点看是一个操作单元(unit of work)。
|
||||
</para>
|
||||
|
@ -65,7 +65,7 @@
|
|||
|
||||
<para>
|
||||
Hibernate认为持久化类(persistent class)新实例化的对象是<emphasis>瞬时(Transient)</emphasis>的。
|
||||
我们可将瞬时(Transient)对象与session关联而变为<emphasis>持久(Persistent)</emphasis>的。
|
||||
我们可通过将瞬时(Transient)对象与session关联而把它变为<emphasis>持久(Persistent)</emphasis>的。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
|
||||
|
@ -100,13 +100,13 @@ sess.save( pk, new Long(1234) );]]></programlisting>
|
|||
如果你持久化的对象有关联的对象(associated objects)(例如上例中的<literal>kittens</literal>集合)
|
||||
那么对这些对象(译注:pk和kittens)进行持久化的顺序是任意的(也就是说可以先对kittens进行持久化也可以先对pk进行持久化),
|
||||
除非你在外键列上有<literal>NOT NULL</literal>约束。
|
||||
Hibernate不会违反外键约束,但是如果你用错误的顺序持久化对象(译注:在pk持久之前持久kitten),那么可能会违反<literal>NOT NULL</literal>约束。
|
||||
Hibernate不会违反外键约束,但是如果你用错误的顺序持久化对象(译注:在pk持久化之前持久化kitten),那么可能会违反<literal>NOT NULL</literal>约束。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
通常你不会为这些细节烦心,因为你很可能会使用Hibernate的
|
||||
<emphasis>传播性持久化(transitive persistence)</emphasis>功能自动保存相关联那些对象。
|
||||
这样连违反<literal>NOT NULL</literal>约束情况都不会出现了 - Hibernate会管好所有的事情。
|
||||
这样连违反<literal>NOT NULL</literal>约束的情况都不会出现了 - Hibernate会管好所有的事情。
|
||||
传播性持久化(transitive persistence)将在本章稍后讨论。
|
||||
</para>
|
||||
|
||||
|
@ -146,7 +146,7 @@ Set kittens = cat.getKittens();]]></programlisting>
|
|||
|
||||
|
||||
<para>
|
||||
如果你不确定是否有匹配的行存在,应该使用<literal>get()</literal>方法,它会立刻访问数据库,如果没有对应的行,会返回null。
|
||||
如果你不确定是否有匹配的行存在,应该使用<literal>get()</literal>方法,它会立刻访问数据库,如果没有对应的记录,会返回null。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
|
||||
|
@ -191,7 +191,7 @@ sess.refresh(cat); //re-read the state (after the trigger executes)]]></programl
|
|||
<para>
|
||||
如果不知道所要寻找的对象的持久化标识,那么你需要使用查询。Hibernate支持强大且易于使用的面向对象查询语言(HQL)。
|
||||
如果希望通过编程的方式创建查询,Hibernate提供了完善的按条件(Query By Criteria, QBC)以及按样例(Query By Example, QBE)进行查询的功能。
|
||||
你也可以用原生SQL(native SQL)描述查询,Hibernate提供了将结果集(result set)转化为对象的部分支持。
|
||||
你也可以用原生SQL(native SQL)描述查询,Hibernate额外提供了将结果集(result set)转化为对象的支持。
|
||||
</para>
|
||||
|
||||
<sect2 id="objectstate-querying-executing" revision="1">
|
||||
|
@ -507,7 +507,7 @@ List cats = crit.list();]]></programlisting>
|
|||
|
||||
|
||||
<para>
|
||||
你可以使用<literal>createSQLQuery()</literal>方法,用SQL来描述查询,并由Hibernate处理将结果集转换成对象的工作。
|
||||
你可以使用<literal>createSQLQuery()</literal>方法,用SQL来描述查询,并由Hibernate将结果集转换成对象。
|
||||
请注意,你可以在任何时候调用<literal>session.connection()</literal>来获得并使用JDBC <literal>Connection</literal>对象。
|
||||
如果你选择使用Hibernate的API, 你必须把SQL别名用大括号包围起来:
|
||||
</para>
|
||||
|
@ -577,7 +577,7 @@ sess.flush(); // changes to cat are automatically detected and persisted]]></pr
|
|||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate通过提供使用<literal>Session.update()</literal>或<literal>Session.merge()</literal>方法
|
||||
Hibernate通过提供<literal>Session.update()</literal>或<literal>Session.merge()</literal>
|
||||
重新关联脱管实例的办法来支持这种模型。
|
||||
</para>
|
||||
|
||||
|
@ -608,8 +608,8 @@ secondSession.update(mate); // update mate]]></programlisting>
|
|||
|
||||
|
||||
<para>
|
||||
希望相关联的脱管对象(通过引用“可到达”的脱管对象)的数据也要更新到数据库时(并且也<emphasis>仅仅</emphasis>在这种情况),
|
||||
应用程序需要对该相关联的脱管对象单独调用<literal>update()</literal>
|
||||
如果希望相关联的脱管对象(通过引用“可到达”的脱管对象)的数据也要更新到数据库时(并且也<emphasis>仅仅</emphasis>在这种情况),
|
||||
可以对该相关联的脱管对象单独调用<literal>update()</literal>
|
||||
当然这些可以自动完成,即通过使用<emphasis>传播性持久化(transitive persistence)</emphasis>,请看<xref linkend="objectstate-transitive"/>。
|
||||
</para>
|
||||
|
||||
|
@ -661,7 +661,7 @@ secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)
|
|||
|
||||
<para>
|
||||
<literal>saveOrUpdate()</literal>用途和语义可能会使新用户感到迷惑。
|
||||
首先,只要你没有尝试在某个session中使用来自另一session的实例,你应该就不需要使用<literal>update()</literal>,
|
||||
首先,只要你没有尝试在某个session中使用来自另一session的实例,你就应该不需要使用<literal>update()</literal>,
|
||||
<literal>saveOrUpdate()</literal>,或<literal>merge()</literal>。有些程序从来不用这些方法。
|
||||
</para>
|
||||
|
||||
|
@ -808,7 +808,7 @@ session2.close();]]></programlisting>
|
|||
|
||||
|
||||
<para>
|
||||
<literal>ReplicationMode</literal>决定数据库中已存在相同行时,<literal>replicate()</literal>如何处理。
|
||||
<literal>ReplicationMode</literal>决定在和数据库中已存在记录由冲突时,<literal>replicate()</literal>如何处理。
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
|
@ -1072,13 +1072,7 @@ sess.close();]]></programlisting>
|
|||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Finally, note that cascading of operations can be applied to an object graph at
|
||||
<emphasis>call time</emphasis> or at <emphasis>flush time</emphasis>. All operations,
|
||||
if enabled, are cascaded to associated entities reachable when the operation is
|
||||
executed. However, <literal>save-upate</literal> and <literal>delete-orphan</literal>
|
||||
are transitive for all associated entities reachable during flush of the
|
||||
<literal>Session</literal>.
|
||||
最后,注意操作的级联可能是在<emphasis>调用期(call time)</emphasis>或者<emphasis>写入期(flush time)</emphasis>作用到对象图上的。所有的操作,假若允许,都在操作被执行的时候级联到可触及的关联实体上。然而,<literal>save-upate</literal>和<literal>delete-orphan</literal>是在<literal>Session</literal> flush的时候才作用到所有可触及的被关联对象上的。
|
||||
最后,注意操作的级联可能是在<emphasis>调用期(call time)</emphasis>或者<emphasis>写入期(flush time)</emphasis>作用到对象图上的。所有的操作,如果允许,都在操作被执行的时候级联到可触及的关联实体上。然而,<literal>save-upate</literal>和<literal>delete-orphan</literal>是在<literal>Session</literal> flush的时候才作用到所有可触及的被关联对象上的。
|
||||
</para>
|
||||
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
|
||||
<para>
|
||||
Hibernate使得你可以用XML数据来进行工作,恰如你用持久化的POJO进行工作那样。解析过的XML树
|
||||
可以被认为是另外一种在对象层面上代替POJO来表示关系型数据的途径.
|
||||
可以被认为是代替POJO的另外一种在对象层面上表示关系型数据的途径.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate支持采用dom4j作为操作XML树的API。你可以写一个查询从数据库中检索出
|
||||
Hibernate支持采用dom4j作为操作XML树的API。你可以写一些查询从数据库中检索出
|
||||
dom4j树,随后你对这颗树做的任何修改都将自动同步回数据库。你甚至可以用dom4j解析
|
||||
一篇XML文档,然后使用Hibernate的任一基本操作将它写入数据库:
|
||||
<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</para>
|
||||
|
||||
<para>
|
||||
这一特性可以应用在很多场合,包括数据导入导出,通过JMS或SOAP表现实体数据以及
|
||||
这一特性可以应用在很多场合,包括数据导入导出,通过JMS或SOAP具体化实体数据以及
|
||||
基于XSLT的报表。
|
||||
</para>
|
||||
|
||||
|
@ -92,7 +92,7 @@
|
|||
|
||||
<para>
|
||||
这个映射使得你既可以把数据作为一棵dom4j树那样访问,又可以作为由属性键值对(java <literal>Map</literal>s)
|
||||
组成的图那样访问。属性名字是纯粹逻辑上的结构,你可以在HQL查询中引用它。
|
||||
组成的图那样访问。属性名字纯粹是逻辑上的结构,你可以在HQL查询中引用它。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -262,7 +262,7 @@ tx.commit();
|
|||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
将这一特色与Hibernate的<literal>replicate()</literal>操作结合起来而实现的基于XML的数据导入/导出将非常有用.
|
||||
将这一特色与Hibernate的<literal>replicate()</literal>操作结合起来对于实现的基于XML的数据导入/导出将非常有用.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
|
Loading…
Reference in New Issue