Author: caoxg
Date: 2006-11-07 00:58:20 -0500 (Tue, 07 Nov 2006)
New Revision: 10744
Modified:
trunk/Hibernate3/doc/reference/zh-cn/master.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/architecture.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/basic_mapping.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/batch.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/configuration.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/filters.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/performance.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/persistent_classes.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/query_hql.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/query_sql.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/session_api.xml
trunk/Hibernate3/doc/reference/zh-cn/modules/tutorial.xml
Log:
version 3.2 of Reference Chinese Version
Modified: trunk/Hibernate3/doc/reference/zh-cn/master.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/master.xml 2006-11-07 01:16:53 UTC (rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/master.xml 2006-11-07 05:58:20 UTC (rev 10744)
@@ -35,7 +35,7 @@
<title>HIBERNATE - 符合Java习惯的关系数据库持久化</title>
<subtitle>Hibernate参考文档</subtitle>
- <releaseinfo>3.1.2</releaseinfo>
+ <releaseinfo>3.2</releaseinfo>
</bookinfo>
<toc/>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/architecture.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/architecture.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/architecture.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -235,7 +235,7 @@
请注意,Hibernate对JCA的支持,仍处于实验性阶段。
</para>
</sect1>
- <sect1 id="architecture-current-session" revision="1">
+ <sect1 id="architecture-current-session" revision="2">
<title>上下文相关的(Contextual)Session</title>
<para>
使用Hibernate的大多数应用程序需要某种形式的“上下文相关的”
session,特定的session在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种“上下文”下一个定义通常是困难的;不同的上下文对“当前”这个概念定义了不同的范围。在3.0版本之前,使用Hibernate的程序要么采用自行编写的基于<literal>ThreadLocal</literal>的上下文session,要么采用<literal>HibernateUtil</literal>这样的辅助类,要么采用第三方框架(比如Spring或Pico),它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。
@@ -247,7 +247,7 @@
更好的是,从3.1开始,<literal>SessionFactory.getCurrentSession()</literal>的后台实现是可拔插的。因此,我们引入了新的扩展接口(<literal>org.hibernate.context.CurrentSessionContext</literal>)和新的配置参数(<literal>hibernate.current_session_context_class</literal>),以便对什么是“当前session”的范围和上下文(scope
and context)的定义进行拔插。
</para>
<para>
-
请参阅<literal>org.hibernate.context.CurrentSessionContext</literal>接口的Javadoc,那里有关于它的契约的详细讨论。它定义了单一的方法,<literal>currentSession()</literal>,特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的两种实现。
+
请参阅<literal>org.hibernate.context.CurrentSessionContext</literal>接口的Javadoc,那里有关于它的契约的详细讨论。它定义了单一的方法,<literal>currentSession()</literal>,特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的三种实现。
</para>
<itemizedlist>
@@ -261,14 +261,19 @@
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
当前session通过当前执行的线程来跟踪和界定。详情也请参阅Javadoc。
</para>
</listitem>
+ <listitem>
+ <para>
+
<literal>org.hibernate.context.ManagedSessionContext</literal> -
当前session通过当前执行的线程来跟踪和界定。但是,你需要负责使用这个类的静态方法将<literal>Session</literal>实例绑定、或者取消绑定,它并不会打开(open)、flush或者关闭(close)任何<literal>Session</literal>。
+ </para>
+ </listitem>
</itemizedlist>
<para>
-
这两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作<emphasis>每次请求一个session</emphasis>。Hibernate
session的起始和终结由数据库事务的生存来控制。假若你采用自行编写代码来管理事务(比如,在纯粹的J2SE,或者JTA/UserTransaction/BMT),建议你使用Hibernate
<literal>Transaction</literal>
API来把底层事务实现从你的代码中隐藏掉。如果你在支持CMT的EJB容器中执行,事务边界是声明式定义的,你不需要在代码中进行任何事务或session管理操作。请参阅<xref
linkend="transactions"/>一节来阅读更多的内容和示例代码。
+
前两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作<emphasis>每次请求一个session</emphasis>。Hibernate
session的起始和终结由数据库事务的生存来控制。假若你在纯粹的 Java SE之上采用自行编写代码来管理事务,而不使用JTA,建议你使用Hibernate
<literal>Transaction</literal>
API来把底层事务实现从你的代码中隐藏掉。如果你使用JTA,请使用JTA借口来管理Transaction。如果你在支持CMT的EJB容器中执行代码,事务边界是声明式定义的,你不需要在代码中进行任何事务或session管理操作。请参阅<xref
linkend="transactions"/>一节来阅读更多的内容和示例代码。
</para>
<para>
-
<literal>hibernate.current_session_context_class</literal>配置参数定义了应该采用哪个<literal>org.hibernate.context.CurrentSessionContext</literal>实现。注意,为了向下兼容,如果未配置此参数,但是存在<literal>org.hibernate.transaction.TransactionManagerLookup</literal>的配置,Hibernate会采用<literal>org.hibernate.context.JTASessionContext</literal>。一般而言,此参数的值指明了要使用的实现类的全名,但那两个内置的实现可以使用简写,即"jta"和"thread"。
+
<literal>hibernate.current_session_context_class</literal>配置参数定义了应该采用哪个<literal>org.hibernate.context.CurrentSessionContext</literal>实现。注意,为了向下兼容,如果未配置此参数,但是存在<literal>org.hibernate.transaction.TransactionManagerLookup</literal>的配置,Hibernate会采用<literal>org.hibernate.context.JTASessionContext</literal>。一般而言,此参数的值指明了要使用的实现类的全名,但那三种内置的实现可以使用简写,即"jta"、"thread"和"managed"。
</para>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/basic_mapping.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/basic_mapping.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/basic_mapping.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -93,7 +93,7 @@
- <sect2 id="mapping-declaration-doctype" revision="2">
+ <sect2 id="mapping-declaration-doctype" revision="3">
<title>Doctype</title>
<para>
@@ -102,6 +102,53 @@
或<literal>hibernate.jar</literal>文件中找到。Hibernate总是会首先在它的classptah中搜索DTD文件。
如果你发现它是通过连接Internet查找DTD文件,就对照你的classpath目录检查XML文件里的DTD声明。
</para>
+
+ <sect3 id="mapping-declaration-entity-resolution">
+ <title>EntityResolver</title>
+ <para>
+ As mentioned previously, Hibernate will first attempt to resolve DTDs
in its classpath. The
+ manner in which it does this is by registering a custom
<literal>org.xml.sax.EntityResolver</literal>
+ implementation with the SAXReader it uses to read in the xml files.
This custom
+ <literal>EntityResolver</literal> recognizes two
different systemId namespaces.
+
如前所述,Hibernate首先在其classpath中查找DTD。其行为是依靠在系统中注册的<literal>org.xml.sax.EntityResolver</literal>的一个具体实现,SAXReader依靠它来读取xml文件。这一
<literal>EntityResolver</literal> 实现能辨认两种不同的 systenId命名空间。
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+
若resolver遇到了一个以<literal>http://hibernate.sourceforge.net/</literal>为开头的systemId,它会辨认出是<literal>hibernate
namespace</literal>,resolver就试图通过加载Hibernate类的classloader来查找这些实体。
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+
+
若resolver遇到了一个使用<literal>classpath://</literal>URL协议的systemId,它会辨认出这是<literal>user
namespace</literal>,resolver试图通过(1)当前线程上下文的classloader和(2)加载Hibernate
class的classloader来查找这些实体。
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ 使用user namespace(用户命名空间)的例子:
+ </para>
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+ <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+]>
+
+<hibernate-mapping package="your.domain">
+ <class name="MyEntity">
+ <id name="id" type="my-custom-id-type">
+ ...
+ </id>
+ <class>
+ &types;
+</hibernate-mapping>]]></programlisting>
+ <para>
+
<literal>types.xml</literal>是<literal>your.domain</literal>包中的一个资源,它包含了一个定制的<xref
linkend="mapping-types-custom">typedef</xref>。
+ </para>
+
+ </sect3>
+
</sect2>
<sect2 id="mapping-declaration-mapping" revision="3">
@@ -693,6 +740,15 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+
<term><literal>sequence-identity</literal></term>
+ <listitem>
+ <para>
+
一种特别的序列生成策略,使用数据库序列来生成实际值,但将它和JDBC3的getGeneratedKeys结合在一起,使得在插入语句执行的时候就返回生成的值。目前为止只有面向JDK
1.4的Oracle 10g驱动支持这一策略。注意,因为Oracle驱动程序的一个bug,这些插入语句的注释被关闭了。(原文:Note comments on these
insert statements are disabled due to a bug in the Oracle drivers.)
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
@@ -2141,7 +2197,7 @@
<title>连接(join)</title>
<para>
- 使用 <literal><join></literal>
元素,可以将一个类的属性映射到多张表中。
+ 使用 <literal><join></literal>
元素,假若在表之间存在一对一关联,可以将一个类的属性映射到多张表中。
</para>
<programlistingco>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/batch.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/batch.xml 2006-11-07 01:16:53 UTC (rev
10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/batch.xml 2006-11-07 05:58:20 UTC (rev
10744)
@@ -26,6 +26,10 @@
<programlisting><![CDATA[hibernate.jdbc.batch_size
20]]></programlisting>
+ <para id="disablebatching" revision="1">
+
注意,假若你使用了<literal>identiy</literal>标识符生成器,Hibernate在JDBC级别透明的关闭插入语句的批量执行。
+ </para>
+
<para>
你也可能想在执行批量处理时关闭二级缓存:
</para>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/configuration.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/configuration.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/configuration.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -685,9 +685,15 @@
为JDBC事务策略选择<literal>after_transaction</literal>.
<para>
<emphasis
role="strong">取值</emphasis>
- <literal>on_close</literal> |
<literal>after_transaction</literal> |
- <literal>after_statement</literal> |
<literal>auto</literal>
+ <literal>auto</literal> (默认) |
<literal>on_close</literal> |
+ <literal>after_transaction</literal> |
<literal>after_statement</literal>
</para>
+ <para>
+
+
注意,这些设置仅对通过<literal>SessionFactory.openSession</literal>得到的<literal>Session</literal>起作用。对于通过<literal>SessionFactory.getCurrentSession</literal>得到的<literal>Session</literal>,所配置的<literal>CurrentSessionContext</literal>实现控制这些<literal>Session</literal>的连接释放模式。请参阅<xref
linkend="architecture-current-session"/>。
+ </para>
+
+
</entry>
</row>
<row>
@@ -902,7 +908,7 @@
</tgroup>
</table>
- <table frame="topbot" id="configuration-misc-properties"
revision="9">
+ <table frame="topbot" id="configuration-misc-properties"
revision="10">
<title>
其他属性
</title>
@@ -931,7 +937,7 @@
<para>
<emphasis
role="strong">eg.</emphasis>
<literal>jta</literal> |
<literal>thread</literal> |
- <literal>custom.Class</literal>
+ <literal>managed</literal> |
<literal>custom.Class</literal>
</para>
</entry>
</row>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/filters.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/filters.xml 2006-11-07 01:16:53 UTC (rev
10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/filters.xml 2006-11-07 05:58:20 UTC (rev
10744)
@@ -7,7 +7,7 @@
对于某个特定的Hibernate session您可以选择是否启用(或禁用)某个过滤器。
</para>
- <sect1 id="objectstate-filters">
+ <sect1 id="objectstate-filters" revision="1">
<title>Hibernate 过滤器(filters)</title>
<para>
@@ -122,7 +122,19 @@
最安全的方式是使用左外连接(left outer joining)。并且通常来说,先写参数,
然后是操作符,最后写数据库字段名。
</para>
+
+ <para>
+
在Filter定义之后,它可能被附加到多个实体和/或集合类,每个都有自己的条件。假若这些条件都是一样的,每次都要定义就显得很繁琐。因此,<literal><filter-def/></literal>被用来定义一个默认条件,它可能作为属性或者CDATA出现:
+ </para>
+ <programlisting><![CDATA[<filter-def name="myFilter"
condition="abc > xyz">...</filter-def>
+<filter-def
name="myOtherFilter">abc=xyz</filter-def>]]></programlisting>
+
+ <para>
+ 当这个filter被附加到任何目的地,而又没有指明条件时,这个条件就会被使用。注意,换句话说,你可以通过给filter附加特别的条件来重载默认条件。
+ </para>
+
+
</sect1>
</chapter>
\ No newline at end of file
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/performance.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/performance.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/performance.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -564,10 +564,8 @@
(即使可以将缓存数据设定为定期失效)。
</para>
- <para>
- 默认情况下,Hibernate使用EHCache进行JVM级别的缓存(目前,Hibernate已经废弃了对JCS的支持,未来版本中将会去掉它)。
- 你可以通过设置<literal>hibernate.cache.provider_class</literal>属性,指定其他的缓存策略,
- 该缓存策略必须实现<literal>org.hibernate.cache.CacheProvider</literal>接口。
+ <para revision="1">
+
通过在<literal>hibernate.cache.provider_class</literal>属性中指定<literal>org.hibernate.cache.CacheProvider</literal>的某个实现的类名,你可以选择让Hibernate使用哪个缓存实现。Hibernate打包一些开源缓存实现,提供对它们的内置支持(见下表)。除此之外,你也可以实现你自己的实现,将它们插入到系统中。注意,在3.2版本之前,默认使用EhCache
作为缓存实现,但从3.2起就不再这样了。
</para>
<table frame="topbot" id="cacheproviders"
revision="1">
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/persistent_classes.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/persistent_classes.xml 2006-11-07
01:16:53 UTC (rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/persistent_classes.xml 2006-11-07
05:58:20 UTC (rev 10744)
@@ -435,11 +435,11 @@
</para>
</sect1>
- <sect1 id="persistent-classes-tuplizers" revision="0">
+ <sect1 id="persistent-classes-tuplizers" revision="1">
<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.entity.EntityTuplizer</literal>
和<literal>org.hibernate.tuple.entity.ComponentTuplizer</literal>接口。<literal>EntityTuplizer</literal>负责管理上面提到的实体的契约,而<literal>ComponentTuplizer</literal>则是针对组件的。
</para>
<para>
@@ -466,7 +466,7 @@
public class CustomMapTuplizerImpl
- extends org.hibernate.tuple.DynamicMapEntityTuplizer {
+ extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
// override the buildInstantiator() method to plug in our custom map...
protected final Instantiator buildInstantiator(
org.hibernate.mapping.PersistentClass mappingInfo) {
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/query_hql.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/query_hql.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/query_hql.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -772,7 +772,7 @@
</para>
</sect1>
- <sect1 id="queryhql-grouping">
+ <sect1 id="queryhql-grouping" revision="1">
<title>group by子句</title>
<para>
@@ -804,13 +804,15 @@
<programlisting><![CDATA[select cat
from Cat cat
join cat.kittens kitten
-group by cat
+group by cat.id, cat.name, cat.other, cat.properties
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
<para>
注意<literal>group by</literal>子句与
<literal>order by</literal>子句中都不能包含算术表达式(arithmetic
expressions).
+
+ 也要注意Hibernate目前不会扩展group的实体,因此你不能写<literal>group by
cat</literal>,除非<literal>cat</literal>的所有属性都不是聚集的(non-aggregated)。你必须明确的列出所有的非聚集属性。
</para>
</sect1>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/query_sql.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/query_sql.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/query_sql.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -10,15 +10,36 @@
Hibernate3允许你使用手写的sql来完成所有的create,update,delete,和load操作(包括存储过程)
</para>
- <sect1 id="querysql-creating" revision="3">
+ <sect1 id="querysql-creating" revision="4">
<title>使用<literal>SQLQuery</literal></title>
-
<para>对原生SQL查询执行的控制是通过<literal>SQLQuery</literal>接口进行的,通过执行<literal>Session.createSQLQuery()</literal>获取这个接口。最简单的情况下,我们可以采用以下形式:</para>
+
<para>对原生SQL查询执行的控制是通过<literal>SQLQuery</literal>接口进行的,通过执行<literal>Session.createSQLQuery()</literal>获取这个接口。下面来描述如何使用这个API进行查询。</para>
- <programlisting><![CDATA[List cats = sess.createSQLQuery("select * from
cats")
- .addEntity(Cat.class)
- .list();]]></programlisting>
+ <sect2>
+ <title>标量查询(Scalar queries)</title>
+ <para>
+ 最基本的SQL查询就是获得一个标量(数值)的列表。 </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS").list();
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+]]></programlisting>
+
+ <para>
+
它们都将返回一个Object数组(Object[])组成的List,数组每个元素都是CATS表的一个字段值。Hibernate会使用ResultSetMetadata来判定返回的标量值的实际顺序和类型。
+ </para>
+
+ <para>
+
如果要避免过多的使用<literal>ResultSetMetadata</literal>,或者只是为了更加明确的指名返回值,可以使用<literal>addScalar()</literal>。
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+]]></programlisting>
+
+
<para>这个查询指定了:</para>
<itemizedlist>
@@ -27,89 +48,164 @@
</listitem>
<listitem>
- <para>查询返回的实体</para>
+ <para>要返回的字段和类型</para>
</listitem>
</itemizedlist>
-
<para>这里,结果集字段名被假设为与映射文件中指明的字段名相同。对于连接了多个表的查询,这就可能造成问题,因为可能在多个表中出现同样名字的字段。下面的方法就可以避免字段名重复的问题:</para>
+ <para>
+
它仍然会返回Object数组,但是此时不再使用<literal>ResultSetMetdata</literal>,而是明确的将ID,NAME和BIRTHDATE按照Long,String和Short类型从resultset中取出。同时,也指明了就算query是使用<literal>*</literal>来查询的,可能获得超过列出的这三个字段,也仅仅会返回这三个字段。
+ </para>
- <programlisting><![CDATA[List cats = sess.createSQLQuery("select
{cat.*} from cats cat")
- .addEntity("cat", Cat.class)
- .list();]]></programlisting>
+ <para>
+ 对全部或者部分的标量值不设置类型信息也是可以的。
+ </para>
- <para>
- 这个查询指定了:
- </para>
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+]]></programlisting>
- <itemizedlist>
+ <para>
+
基本上这和前面一个查询相同,只是此时使用<literal>ResultSetMetaData</literal>来决定NAME和BIRTHDATE的类型,而ID的类型是明确指出的。
+ </para>
+
+ <para>
+
关于从ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate类型,是由方言(Dialect)控制的。假若某个指定的类型没有被映射,或者不是你所预期的类型,你可以通过Dialet的<literal>registerHibernateType</literal>调用自行定义。
+ </para>
+
+ </sect2>
+
+ <sect2>
+ <title>实体查询(Entity queries)</title>
+
+ <para>
+
上面的查询都是返回标量值的,也就是从resultset中返回的“裸”数据。下面展示如何通过<literal>addEntity()</literal>让原生查询返回实体对象。
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS").addEntity(Cat.class);
+sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM
CATS").addEntity(Cat.class);
+]]></programlisting>
+
+ <para>这个查询指定:</para>
+
+ <itemizedlist>
<listitem>
- <para>
- SQL查询语句,它带一个占位符,可以让Hibernate使用字段的别名.
- </para>
+ <para>SQL查询字符串</para>
</listitem>
+
<listitem>
- <para>
- 查询返回的实体,和它的SQL表的别名.
- </para>
+ <para>要返回的实体</para>
</listitem>
- </itemizedlist>
-
- <para>
- <literal>addEntity()</literal>方法将SQL表的别名和实体类联系起来,并且确定查询结果集的形态。
- </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>
- 原生的SQL查询可能返回一个简单的标量值或者一个标量和实体的结合体。
- </para>
+ </itemizedlist>
- <programlisting><![CDATA[Double max = (Double)
sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
- .addScalar("maxWeight", Hibernate.DOUBLE);
- .uniqueResult();]]></programlisting>
-
- <para>除此之外,你还可以在你的hbm文件中描述结果集映射信息,在查询中使用。</para>
-
- <programlisting><![CDATA[List cats = sess.createSQLQuery(
- "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother =
cat.id"
- )
- .setResultSetMapping("catAndKitten")
- .list();]]></programlisting>
+ <para>
+ 假设Cat被映射为拥有ID,NAME和BIRTHDATE三个字段的类,以上的两个查询都返回一个List,每个元素都是一个Cat实体。
+ </para>
+ <para>
+
假若实体在映射时有一个<literal>many-to-one</literal>的关联指向另外一个实体,在查询时必须也返回那个实体,否则会导致发生一个"column
not
found"的数据库错误。这些附加的字段可以使用*标注来自动返回,但我们希望还是明确指明,看下面这个具有指向<literal>Dog</literal>的<literal>many-to-one</literal>的例子:
+ </para>
- </sect1>
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME,
BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+]]></programlisting>
- <sect1 id="querysql-aliasreferences">
- <title>别名和属性引用</title>
+ <para>
+ 这样cat.getDog()就能正常运作。
+ </para>
+ </sect2>
- <para>
- 上面使用的<literal>{cat.*}</literal>标记是 "所有属性"
的简写.你可以显式地列出需要的字段,但是你必须让Hibernate
- 为每一个属性注入字段的别名.这些字段的站位符是以字段别名为前导,再加上属性名.在下面的例子里,我们从一个其他的表(<literal>cat_log</literal>)
- 中获取<literal>Cat</literal>对象,而非Cat对象原本在映射元数据中声明的表.注意我们甚至在where子句中也可以使用属性别名.
- 对于命名查询,{}语法并不是必需的.你可以在<xref
linkend="querysql-namedqueries"/>得到更多的细节.
- </para>
+ <sect2>
+ <title>处理关联和集合类(Handling associations and collections)</title>
- <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"
-
+ <para>
+
通过提前抓取将<literal>Dog</literal>连接获得,而避免初始化proxy带来的额外开销也是可能的。这是通过<literal>addJoin()</literal>方法进行的,这个方法可以让你将关联或集合连接进来。
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME,
BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+]]></programlisting>
+
+ <para>
+
上面这个例子中,返回的<literal>Cat</literal>对象,其<literal>dog</literal>属性被完全初始化了,不再需要数据库的额外操作。注意,我们加了一个别名("cat"),以便指明join的目标属性路径。通过同样的提前连接也可以作用于集合类,例如,假若<literal>Cat</literal>有一个指向<literal>Dog</literal>的一对多关联。
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME,
BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+]]></programlisting>
+
+ <p>
+
到此为止,我们碰到了天花板:若不对SQL查询进行增强,这些已经是在Hibernate中使用原生SQL查询所能做到的最大可能了。下面的问题即将出现:返回多个同样类型的实体怎么办?或者默认的别名/字段不够又怎么办?
+
+ </p>
+ </sect2>
+
+ <sect2>
+ <title>返回多个实体(Returning multiple entities)</title>
+
+ <para>
+ 到目前为止,结果集字段名被假定为和映射文件中指定的的字段名是一致的。假若SQL查询连接了多个表,同一个字段名可能在多个表中出现多次,这就会造成问题。
+ </para>
+
+ <para>
+ 下面的查询中需要使用字段别名注射(这个例子本身会失败):
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM
CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+ <para>
+
这个查询的本意是希望每行返回两个Cat实例,一个是cat,另一个是它的妈妈。但是因为它们的字段名被映射为相同的,而且在某些数据库中,返回的字段别名是“c.ID”,"c.NAME"这样的形式,而它们和在映射文件中的名字("ID"和"NAME")不匹配,这就会造成失败。
+
+ </para>
+
+ <para>
+ 下面的形式可以解决字段名重复:
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*},
{mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+]]></programlisting>
+
+ <para>这个查询指明:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ SQL查询语句,其中包含占位附来让Hibernate注射字段别名</para>
+ </listitem>
+
+ <listitem>
+ <para>
+ 查询返回的实体
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+
上面使用的{cat.*}和{mother.*}标记是作为“所有属性”的简写形式出现的。当然你也可以明确地罗列出字段名,但在这个例子里面我们让Hibernate来为每个属性注射SQL字段别名。字段别名的占位符是属性名加上表别名的前缀。在下面的例子中,我们从另外一个表(cat_log)中通过映射元数据中的指定获取Cat和它的妈妈。注意,要是我们愿意,我们甚至可以在where子句中使用属性别名。
+
+ </para>
+
+ <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as
{c.name}, " +
+ "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+ "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
List loggedCats = sess.createSQLQuery(sql)
- .addEntity("cat", Cat.class)
- .setLong("catId", catId)
- .list();]]></programlisting>
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class).list()
+]]></programlisting>
+ <sect3 id="querysql-aliasreferences" revision="2">
+ <title>别名和属性引用(Alias and property references)</title>
+
<para>
-
<emphasis>注意:</emphasis>如果你明确地列出了每个属性,你必须包含<emphasis>这个类</emphasis>和<emphasis>它的子类</emphasis>的属性!
+
大多数情况下,都需要上面的属性注射,但在使用更加复杂的映射,比如复合属性、通过标识符构造继承树,以及集合类等等情况下,也有一些特别的别名,来允许Hibernate注射合适的别名。
</para>
<para>
@@ -119,7 +215,7 @@
<table frame="topbot" id="aliasinjection-summary">
<title>别名注射(alias injection names)</title>
- <tgroup cols="4">
+ <tgroup cols="3">
<colspec colwidth="1*" />
<colspec colwidth="1*" />
@@ -129,7 +225,9 @@
<thead>
<row>
<entry>描述</entry>
+
<entry>语法</entry>
+
<entry>示例</entry>
</row>
</thead>
@@ -190,8 +288,64 @@
</table>
- </sect1>
+ </sect3>
+ </sect2>
+
+ <sect2>
+ <title>返回非受管实体(Returning non-managed entities)</title>
+
+ <para>
+ 可以对原生sql 查询使用ResultTransformer。这会返回不受Hibernate管理的实体。
+
+ </para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE
FROM CATS")
+
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+
+ <para>这个查询指定:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>SQL查询字符串</para>
+ </listitem>
+
+ <listitem>
+ <para>结果转换器(result transformer)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+
上面的查询将会返回<literal>CatDTO</literal>的列表,它将被实例化并且将NAME和BIRTHDAY的值注射入对应的属性或者字段。
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>处理继承(Handling inheritance)</title>
+
+ <para>
+ 原生SQL查询假若其查询结果实体是继承树中的一部分,它必须包含基类和所有子类的所有属性。
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>参数(Parameters)</title>
+
+ <para>
+ 原生查询支持位置参数和命名参数:
+ </para>
+
+ <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT *
FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+List pusList = query.setString(0, "Pus%").list();
+
+query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like
:name").addEntity(Cat.class);
+List pusList = query.setString("name", "Pus%").list();
]]></programlisting>
+ </sect2>
+
+
+ </sect1>
+
+
<sect1 id="querysql-namedqueries" revision="3">
<title>命名SQL查询</title>
@@ -272,6 +426,16 @@
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
WHERE person.NAME LIKE :namePattern
</sql-query>]]></programlisting>
+
+ <para>
+ 另外,你可以在java代码中直接使用hbm文件中的结果集定义信息。
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createSQLQuery(
+ "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother =
cat.id"
+ )
+ .setResultSetMapping("catAndKitten")
+ .list();]]></programlisting>
<sect2 id="propertyresults">
<title>使用return-property来明确地指定字段/别名</title>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/session_api.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/session_api.xml 2006-11-07 01:16:53 UTC
(rev 10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/session_api.xml 2006-11-07 05:58:20 UTC
(rev 10744)
@@ -408,7 +408,7 @@
</sect3>
- <sect3 id="objectstate-querying-executing-named">
+ <sect3 id="objectstate-querying-executing-named"
revision="1">
<title>外置命名查询(Externalizing named queries)</title>
<para>
@@ -416,7 +416,7 @@
(如果你的查询串中包含可能被解释为XML标记(markup)的字符,别忘了用<literal>CDATA</literal>包裹起来。)
</para>
- <programlisting><![CDATA[<query
name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
+ <programlisting><![CDATA[<query
name="ByNameAndMaximumWeight"><![CDATA[
from eg.DomesticCat as cat
where cat.name = ?
and cat.weight > ?
@@ -427,7 +427,7 @@
参数绑定及执行以编程方式(programatically)完成:
</para>
- <programlisting><![CDATA[Query q =
sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
+ <programlisting><![CDATA[Query q =
sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name);
q.setInt(1, minWeight);
List cats = q.list();]]></programlisting>
@@ -438,6 +438,11 @@
或将原有的其他的查询语句放在配置文件中,这样就可以让Hibernate统一管理,达到迁移的目的。
</para>
+ <para>
+
+
也请注意在<literal><hibernate-mapping></literal>元素中声明的查询必须有一个全局唯一的名字,而在<literal><class></literal>元素中声明的查询自动具有全局名,是通过类的全名加以限定的。比如<literal>eg.Cat.ByNameAndMaximumWeight</literal>。
+ </para>
+
</sect3>
</sect2>
Modified: trunk/Hibernate3/doc/reference/zh-cn/modules/tutorial.xml
===================================================================
--- trunk/Hibernate3/doc/reference/zh-cn/modules/tutorial.xml 2006-11-07 01:16:53 UTC (rev
10743)
+++ trunk/Hibernate3/doc/reference/zh-cn/modules/tutorial.xml 2006-11-07 05:58:20 UTC (rev
10744)
@@ -258,7 +258,7 @@
</para>
<para>
- 在开发的根目录下创建一个<literal>data</literal>目录 - 这是HSQL
DB存储数据文件的地方。此时在data目录中运行<literal>java -classpath lib/hsqldb.jar
org.hsqldb.Server</literal>就可启动数据库。你可以在log中看到它的启动,及绑定到TCP/IP套结字,这正是我们的应用程序稍后会连接的地方。如果你希望在本例中运行一个全新的数据库,就在窗口中按下<literal>CTRL
+
C</literal>来关闭HSQL数据库,并删除<literal>data/</literal>目录下的所有文件,再重新启动HSQL数据库。
+ 在开发的根目录下创建一个<literal>data</literal>目录 - 这是HSQL
DB存储数据文件的地方。此时在data目录中运行<literal>java -classpath ../lib/hsqldb.jar
org.hsqldb.Server</literal>就可启动数据库。你可以在log中看到它的启动,及绑定到TCP/IP套结字,这正是我们的应用程序稍后会连接的地方。如果你希望在本例中运行一个全新的数据库,就在窗口中按下<literal>CTRL
+
C</literal>来关闭HSQL数据库,并删除<literal>data/</literal>目录下的所有文件,再重新启动HSQL数据库。
</para>
<para>
@@ -462,7 +462,7 @@
</sect2>
- <sect2 id="tutorial-firstapp-workingpersistence"
revision="4">
+ <sect2 id="tutorial-firstapp-workingpersistence"
revision="5">
<title>
加载并存储对象
</title>
@@ -518,10 +518,22 @@
</para>
<para>
-
<literal>sessionFactory.getCurrentSession()</literal>是干什么的呢?首先,只要你持有<literal>SessionFactory</literal>(幸亏我们有<literal>HibernateUtil</literal>,可以随时获得),大可在任何时候、任何地点调用这个方法。<literal>getCurrentSession()</literal>方法总会返回“当前的”工作单元。记得我们在<literal>hibernate.cfg.xml</literal>中把这一配置选项调整为"thread"了吗?因此,当前工作单元的范围就是当前执行我们应用程序的Java线程。但是,这并非总是正确的。
<literal>Session</literal>在第一次被使用的时候,或者第一次调用<literal>getCurrentSession()</literal>的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate也会把<literal>Session</literal>从当前线程剥离,并且关闭它。假若你再次调用<literal>getCurrentSession()</lit!
eral>,你会得到一个新的<literal>Session</literal>,并且开始一个新的工作单元。这种<emphasis>线程绑定(thread-bound)</emphasis>的编程模型(model)是使用Hibernate的最广泛的方式。
+
<literal>sessionFactory.getCurrentSession()</literal>是干什么的呢?首先,只要你持有<literal>SessionFactory</literal>(幸亏我们有<literal>HibernateUtil</literal>,可以随时获得),大可在任何时候、任何地点调用这个方法。<literal>getCurrentSession()</literal>方法总会返回“当前的”工作单元。记得我们在<literal>hibernate.cfg.xml</literal>中把这一配置选项调整为"thread"了吗?因此,因此,当前工作单元被绑定到当前执行我们应用程序的Java线程。但是,这并非是完全准确的,你还得考虑工作单元的生命周期范围
(scope),它何时开始,又何时结束.
+ </para>
+
+ <para>
+
<literal>Session</literal>在第一次被使用的时候,即第一次调用<literal>getCurrentSession()</literal>的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate会自动把<literal>Session</literal>从当前线程剥离,并且关闭它。假若你再次调用<literal>getCurrentSession()</literal>,你会得到一个新的<literal>Session</literal>,并且开始一个新的工作单元。这种<emphasis>线程绑定(thread-bound)</emphasis>的编程模型(model)是使用Hibernate的最广泛的方式,因为它支持对你的代码灵活分层(事务划分可以和你的数据访问代码分离开来,在本教程的后面部分就会这么做)。
+
</para>
<para>
+
+ 和工作单元的生命周期这个话题相关,Hibernate
<literal>Session</literal>是否被应该用来执行多次数据库操作?上面的例子对每一次操作使用了一个<literal>Session</literal>,这完全是巧合,这个例子不是很复杂,无法展示其他方式。Hibernate
<literal>Session</literal>的生命周期可以很灵活,但是你绝不要把你的应用程序设计成为<emphasis>每一次</emphasis>数据库操作都用一个新的Hibernate
<literal>Session</literal>。因此就算下面的例子(它们都很简单)中你可以看到这种用法,记住<emphasis>每次操作一个session</emphasis>是一个反模式。在本教程的后面会展示一个真正的(web)程序。
+ </para>
+
+
+
+ <para>
关于事务处理及事务边界界定的详细信息,请参看<xref
linkend="transactions"/>。在上面的例子中,我们也忽略了所有的错误与回滚的处理。
</para>
@@ -750,7 +762,7 @@
</sect2>
- <sect2 id="tutorial-associations-working"
revision="1">
+ <sect2 id="tutorial-associations-working"
revision="2">
<title>
使关联工作
</title>
@@ -820,7 +832,8 @@
Long eventId = mgr.createAndStoreEvent("My Event", new Date());
Long personId = mgr.createAndStorePerson("Foo", "Bar");
mgr.addPersonToEvent(personId, eventId);
- System.out.println("Added person " + personId + " to event " +
eventId);]]></programlisting>
+ System.out.println("Added person " + personId + " to event " +
eventId);
+}]]></programlisting>
<para>
上面是个关于两个同等重要的实体类间关联的例子。像前面所提到的那样,在特定的模型中也存在其它的类和类型,这些类和类型通常是“次要的”。你已看到过其中的一些,像<literal>int</literal>或<literal>String</literal>。我们称这些类为<emphasis>值类型(value
type)</emphasis>,它们的实例<emphasis>依赖(depend)</emphasis>在某个特定的实体上。这些类型的实例没有它们自己的标识(identity),也不能在实体间被共享(比如,两个person不能引用同一个<literal>firstname</literal>对象,即使他们有相同的first
name)。当然,值类型并不仅仅在JDK中存在(事实上,在一个Hibernate应用程序中,所有的JDK类都被视为值类型),而且你也可以编写你自己的依赖类,例如<literal>Address</literal>,<literal>MonetaryAmount</literal>。
@@ -1001,7 +1014,7 @@
Hibernate web应用程序使用<literal>Session</literal>
和<literal>Transaction</literal>的方式几乎和独立应用程序是一样的。但是,有一些常见的模式(pattern)非常有用。现在我们编写一个<literal>EventManagerServlet</literal>。这个servlet可以列出数据库中保存的所有的events,还提供一个HTML表单来增加新的events。
</para>
- <sect2 id="tutorial-webapp-servlet">
+ <sect2 id="tutorial-webapp-servlet" revision="2">
<title>编写基本的servlet</title>
<para>
@@ -1014,9 +1027,6 @@
public class EventManagerServlet extends HttpServlet {
- private final SimpleDateFormat dateFormatter =
- new SimpleDateFormat("dd.MM.yyyy");
-
// Servlet code
}]]></programlisting>
@@ -1032,6 +1042,8 @@
HttpServletResponse response)
throws ServletException, IOException {
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
try {
// Begin unit of work
HibernateUtil.getSessionFactory()
@@ -1050,11 +1062,15 @@
}
}]]></programlisting>
-
<para>
我们称这里应用的模式为每次请求一个session<emphasis>(session-per-request)</emphasis>。当有请求到达这个servlet的时候,通过对<literal>SessionFactory</literal>的第一次调用,打开一个新的Hibernate
<literal>Session</literal>。然后启动一个数据库事务—所有的数据访问都是在事务中进行,不管是读还是写(我们在应用程序中不使用auto-commit模式)。
</para>
+
+ <para>
+ <emphasis>不要</emphasis>为每次数据库操作都使用一个新的Hibernate
<literal>Session</literal>。将Hibernate
<literal>Session</literal>的范围设置为整个请求。要用<literal>getCurrentSession()</literal>,这样它自动会绑定到当前Java线程。
+ </para>
+
<para>
下一步,对请求的可能动作进行处理,渲染出反馈的HTML。我们很快就会涉及到那部分。
</para>
@@ -1065,7 +1081,7 @@
</sect2>
- <sect2 id="tutorial-webapp-processing">
+ <sect2 id="tutorial-webapp-processing" revision="1">
<title>处理与渲染</title>
<para>
@@ -1092,31 +1108,18 @@
// Print page
printEventForm(out);
-listEvents(out);
+listEvents(out, dateFormatter);
// Write HTML footer
out.println("</body></html>");
out.flush();
out.close();]]></programlisting>
-
<para>
-
必须承认,这种编码风格让Java与HTML混合在了一起,在更复杂的应用程序中不应大量地使用—记住我们在章中仅为了展示Hibernate的基本概念。这段代码打印出了HTML头和尾部。在页面中,打印出一个输入event条目的表单,并列出数据库中所有events。第一个方法微不足道,仅仅是输出HTML:
+ <literal>listEvents()</literal>方法使用绑定到当前线程的Hibernate
<literal>Session</literal>来执行查询:
</para>
- <programlisting><![CDATA[private void printEventForm(PrintWriter
out) {
- out.println("<h2>Add new event:</h2>");
- out.println("<form>");
- out.println("Title: <input name='eventTitle'
length='50'/><br/>");
- out.println("Date (e.g. 24.12.2009): <input name='eventDate'
length='10'/><br/>");
- out.println("<input type='submit' name='action'
value='store'/>");
- out.println("</form>");
-}]]></programlisting>
+ <programlisting><![CDATA[private void listEvents(PrintWriter out,
SimpleDateFormat dateFormatter) {
- <para>
- <literal>listEvents()</literal>方法使用绑定到当前线程的Hibernate
<literal>Session</literal>来执行查询:
- </para>
-
- <programlisting><![CDATA[private void listEvents(PrintWriter out) {
List result = HibernateUtil.getSessionFactory()
.getCurrentSession().createCriteria(Event.class).list();
if (result.size() > 0) {