612 lines
26 KiB
XML
612 lines
26 KiB
XML
<chapter id="quickstart">
|
|
<title>Quickstart with Tomcat</title>
|
|
|
|
<sect1 id="quickstart-intro" revision="1">
|
|
<title>Getting started with Hibernate</title>
|
|
|
|
<para>
|
|
This tutorial explains a setup of Hibernate 3.0 with the Apache Tomcat
|
|
servlet container for a web-based application. Hibernate works
|
|
well in a managed environment with all major J2EE application servers, or
|
|
even in standalone Java applications. The database system used in this
|
|
tutorial is PostgreSQL 7.4, support for other database is only a matter
|
|
of changing the Hibernate SQL dialect configuration.
|
|
</para>
|
|
|
|
<para>
|
|
First, we have to copy all required libraries to the Tomcat installation.
|
|
We use a separate web context (<literal>webapps/quickstart</literal>) for
|
|
this tutorial, so we've to consider both the global library search path
|
|
(<literal>TOMCAT/common/lib</literal>) and the classloader at the context level in
|
|
<literal>webapps/quickstart/WEB-INF/lib</literal> (for JAR files) and
|
|
<literal>webapps/quickstart/WEB-INF/classes</literal>. We refer to both classloader
|
|
levels as the global classpath and the context classpath.
|
|
</para>
|
|
|
|
<para>
|
|
Now, copy the libraries to the two classpaths:
|
|
</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>
|
|
Copy the JDBC driver for the database to the global classpath. This is
|
|
required for the DBCP connection pool software which comes bundled with Tomcat.
|
|
Hibernate uses JDBC connections to execute SQL on the database, so you
|
|
either have to provide pooled JDBC connections or configure Hibernate to
|
|
use one of the directly supported pools (C3P0, Proxool). For this tutorial,
|
|
copy the <literal>pg74jdbc3.jar</literal> library (for PostgreSQL 7.4 and JDK 1.4)
|
|
to the global classloaders path. If you'd like to use a different database, simply
|
|
copy its appropriate JDBC driver.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Never copy anything else into the global classloader path in Tomcat, or you
|
|
will get problems with various tools, including Log4j, commons-logging and
|
|
others. Always use the context classpath for each web application, that is,
|
|
copy libraries to <literal>WEB-INF/lib</literal> and your own classes and
|
|
configuration/property files to <literal>WEB-INF/classes</literal>. Both
|
|
directories are in the context level classpath by default.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Hibernate is packaged as a JAR library. The <literal>hibernate3.jar</literal>
|
|
file should be copied in the context classpath together with other classes of
|
|
the application. Hibernate requires some 3rd party libraries at runtime, these
|
|
come bundled with the Hibernate distribution in the <literal>lib/</literal>
|
|
directory; see <xref linkend="3rdpartylibs"/>. Copy the required 3rd party
|
|
libraries to the context classpath.
|
|
</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<table frame="topbot" id="3rdpartylibs">
|
|
<title>
|
|
Hibernate 3rd party libraries
|
|
</title>
|
|
<tgroup cols="2" rowsep="1" colsep="1">
|
|
<colspec colname="c1" colwidth="1*"/>
|
|
<colspec colname="c2" colwidth="2*"/>
|
|
<thead>
|
|
<row>
|
|
<entry align="center">
|
|
Library
|
|
</entry>
|
|
<entry align="center">
|
|
Description
|
|
</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
dom4j (required)
|
|
</entry>
|
|
<entry>
|
|
Hibernate uses dom4j to parse XML configuration and XML mapping
|
|
metadata files.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
CGLIB (required)
|
|
</entry>
|
|
<entry>
|
|
Hibernate uses the code generation library to enhance classes
|
|
at runtime (in combination with Java reflection).
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Commons Collections, Commons Logging (required)
|
|
</entry>
|
|
<entry>
|
|
Hibernate uses various utility libraries from the Apache Jakarta
|
|
Commons project.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
EHCache (required)
|
|
</entry>
|
|
<entry>
|
|
Hibernate can use various cache providers for the second-level
|
|
cache. EHCache is the default cache provider if not changed in
|
|
the configuration.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Log4j (optional)
|
|
</entry>
|
|
<entry>
|
|
Hibernate uses the Commons Logging API, which in turn can use
|
|
Log4j as the underlying logging mechanism. If the Log4j library is
|
|
available in the context library directory, Commons Logging will use
|
|
Log4j and the <literal>log4j.properties</literal> configuration in the
|
|
context classpath. An example properties file for Log4j is bundled
|
|
with the Hibernate distribution. So, copy log4j.jar and the configuration
|
|
file (from <literal>src/</literal>) to your context classpath if
|
|
you want to see whats going on behind the scenes.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Required or not?
|
|
</entry>
|
|
<entry>
|
|
Have a look at the file <literal>lib/README.txt</literal> in the
|
|
Hibernate distribution. This is an up-to-date list of 3rd party
|
|
libraries distributed with Hibernate. You will find all required
|
|
and optional libraries listed there.
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>
|
|
We now set up the database connection pooling and sharing in both Tomcat and
|
|
Hibernate. This means Tomcat will provide pooled JDBC connections (using its
|
|
builtin DBCP pooling feature), Hibernate requests theses connections through
|
|
JNDI. Tomcat binds the connection pool to JNDI, we add a resource declaration
|
|
to Tomcats main configuration file, <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>
|
|
The context we configure in this example is named <literal>quickstart</literal>,
|
|
its base is the <literal>TOMCAT/webapp/quickstart</literal> directory. To access
|
|
any servlets, call the path <literal>http://localhost:8080/quickstart</literal>
|
|
in your browser (of course, adding the name of the servlet as mapped in your
|
|
<literal>web.xml</literal>). You may also go ahead and create a simple servlet
|
|
now that has an empty <literal>process()</literal> method.
|
|
</para>
|
|
|
|
<para>
|
|
Tomcat provides connections now through JNDI at
|
|
<literal>java:comp/env/jdbc/quickstart</literal>. If you have trouble getting the
|
|
connection pool running, refer to the Tomcat documentation. If you get JDBC driver
|
|
exception messages, try to setup JDBC connection pool without Hibernate first.
|
|
Tomcat & JDBC tutorials are available on the Web.
|
|
</para>
|
|
|
|
<para>
|
|
Your next step is to configure Hibernate. Hibernate has to know how it should obtain
|
|
JDBC connections We use Hibernates XML-based configuration. The other approach, using
|
|
a properties file, is equivalent in features, but doesn't offer any advantages. We use
|
|
the XML configuration because it is usually more convenient. The XML configuration file
|
|
is placed in the context classpath (<literal>WEB-INF/classes</literal>), as
|
|
<literal>hibernate.cfg.xml</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>
|
|
We turn logging of SQL commands off and tell Hibernate what database SQL
|
|
dialect is used and where to get the JDBC connections (by declaring the JNDI
|
|
address of the Tomcat bound pool). The dialect is a required setting,
|
|
databases differ in their interpretation of the SQL "standard". Hibernate will take
|
|
care of the differences and comes bundled with dialects for all major
|
|
commercial and open source databases.
|
|
</para>
|
|
|
|
<para>
|
|
A <literal>SessionFactory</literal> is Hibernate's concept of a single
|
|
datastore, multiple databases can be used by creating multiple XML
|
|
configuration files and creating multiple <literal>Configuration</literal>
|
|
and <literal>SessionFactory</literal> objects in your application.
|
|
</para>
|
|
|
|
<para>
|
|
The last element of the <literal>hibernate.cfg.xml</literal> declares
|
|
<literal>Cat.hbm.xml</literal> as the name of a Hibernate XML mapping
|
|
file for the persistent class <literal>Cat</literal>. This file contains
|
|
the metadata for the mapping of the POJO class <literal>Cat</literal> to
|
|
a datbase table (or tables). We'll come back to that file soon. Let's write
|
|
the POJO class first and then declare the mapping metadata for it.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-persistentclass" revision="1">
|
|
<title>First persistent class</title>
|
|
|
|
<para>
|
|
Hibernate works best with the Plain Old Java Objects (POJOs, sometimes
|
|
called Plain Ordinary Java Objects) programming model for persistent classes.
|
|
A POJO is much like a JavaBean, with properties of the class accessible via getter
|
|
and setter methods, shielding the internal representation from the publicly
|
|
visible interface (Hibernate can also access fields directly, if needed):
|
|
</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 is not restricted in its usage of property types, all Java JDK
|
|
types and primitives (like <literal>String</literal>, <literal>char</literal>
|
|
and <literal>Date</literal>) can be mapped, including classes from the Java
|
|
collections framework. You can map them as values, collections of values, or
|
|
associations to other entities. The <literal>id</literal> is a special property
|
|
that represents the database identifer (primary key) of that class, it is
|
|
highly recommended for entities like a <literal>Cat</literal>. Hibernate can
|
|
use identifiers only internally, but we would lose some of the flexibility in our
|
|
application architecture.
|
|
</para>
|
|
|
|
<para>
|
|
No special interface has to be implemented for persistent classes nor do you have
|
|
to subclass from a special root persistent class. Hibernate also doesn't require
|
|
any build time processing, such as byte-code manipulation, it relies solely on
|
|
Java reflection and runtime class enhancement (through CGLIB). So, without any
|
|
dependency of the POJO class on Hibernate, we can map it to a database table.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-mapping" revision="1">
|
|
<title>Mapping the cat</title>
|
|
|
|
<para>
|
|
The <literal>Cat.hbm.xml</literal> mapping file contains the metadata
|
|
required for the object/relational mapping. The metadata includes declaration
|
|
of persistent classes and the mapping of properties (to columns and
|
|
foreign key relationships to other entities) to database tables.
|
|
</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>
|
|
Every persistent class should have an identifer attribute (actually, only
|
|
classes representing entities, not dependent value-typed classes, which
|
|
are mapped as components of an entity). This property is used to distinguish
|
|
persistent objects: Two cats are equal if
|
|
<literal>catA.getId().equals(catB.getId())</literal> is true, this concept is
|
|
called <emphasis>database identity</emphasis>. Hibernate comes bundled with
|
|
various identifer generators for different scenarios (including native generators
|
|
for database sequences, hi/lo identifier tables, and application assigned
|
|
identifiers). We use the UUID generator (only recommended for testing, as integer
|
|
surrogate keys generated by the database should be prefered) and also specify the
|
|
column <literal>CAT_ID</literal> of the table <literal>CAT</literal> for the
|
|
Hibernate generated identifier value (as a primary key of the table).
|
|
</para>
|
|
|
|
<para>
|
|
All other properties of <literal>Cat</literal> are mapped to the same table. In
|
|
the case of the <literal>name</literal> property, we mapped it with an explicit
|
|
database column declaration. This is especially useful when the database
|
|
schema is automatically generated (as SQL DDL statements) from the mapping
|
|
declaration with Hibernate's <emphasis>SchemaExport</emphasis> tool. All other
|
|
properties are mapped using Hibernate's default settings, which is what you
|
|
need most of the time. The table <literal>CAT</literal> in the database looks
|
|
like this:
|
|
</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>
|
|
You should now create this table in your database manually, and later read
|
|
<xref linkend="toolsetguide"/> if you want to automate this step with the
|
|
<literal>hbm2ddl</literal> tool. This tool can create a full SQL DDL, including
|
|
table definition, custom column type constraints, unique constraints and indexes.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-playingwithcats" revision="2">
|
|
<title>Playing with cats</title>
|
|
|
|
<para>
|
|
We're now ready to start Hibernate's <literal>Session</literal>. It is the
|
|
<emphasis>persistence manager</emphasis>, we use it to store and retrieve
|
|
<literal>Cat</literal>s to and from the database. But first, we've to get a
|
|
<literal>Session</literal> (Hibernate's unit-of-work) from the
|
|
<literal>SessionFactory</literal>:
|
|
</para>
|
|
|
|
<programlisting><![CDATA[SessionFactory sessionFactory =
|
|
new Configuration().configure().buildSessionFactory();]]></programlisting>
|
|
|
|
<para>
|
|
The call to <literal>configure()</literal> loads the <literal>hibernate.cfg.xml</literal>
|
|
configuration file and initializes the <literal>Configuration</literal> instance.
|
|
You can set other properties (and even change the mapping metadata) by
|
|
accessing the <literal>Configuration</literal> <emphasis>before</emphasis>
|
|
you build the <literal>SessionFactory</literal> (it is immutable). Where
|
|
do we create the <literal>SessionFactory</literal> and how can we access
|
|
it in our application?
|
|
</para>
|
|
|
|
<para>
|
|
A <literal>SessionFactory</literal> is usually only build once,
|
|
e.g. at startup with a <emphasis>load-on-startup</emphasis> servlet.
|
|
This also means you should not keep it in an instance variable in your
|
|
servlets, but in some other location. Furthermore, we need some kind of
|
|
<emphasis>Singleton</emphasis>, so we can access the
|
|
<literal>SessionFactory</literal> easily in application code. The approach
|
|
shown next solves both problems: startup configuration and easy access to a
|
|
<literal>SessionFactory</literal>.
|
|
</para>
|
|
|
|
<para>
|
|
We implement a <literal>HibernateUtil</literal> helper class:
|
|
</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() throws HibernateException {
|
|
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() throws HibernateException {
|
|
Session s = (Session) session.get();
|
|
session.set(null);
|
|
if (s != null)
|
|
s.close();
|
|
}
|
|
}]]></programlisting>
|
|
|
|
<para>
|
|
This class does not only take care of the <literal>SessionFactory</literal>
|
|
with its static initializer, but also has a <literal>ThreadLocal</literal>
|
|
variable which holds the <literal>Session</literal> for the current thread.
|
|
Make sure you understand the Java concept of a thread-local variable before you
|
|
try to use this helper. A more complex and powerful <literal>HibernateUtil</literal>
|
|
class can be found in <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/
|
|
</para>
|
|
|
|
<para>
|
|
A <literal>SessionFactory</literal> is threadsafe, many threads can access
|
|
it concurrently and request <literal>Session</literal>s. A <literal>Session</literal>
|
|
is a non-threadsafe object that represents a single unit-of-work with the database.
|
|
<literal>Session</literal>s are opened by a <literal>SessionFactory</literal> and
|
|
are closed when all work is completed. An example in your servlet's
|
|
<literal>process()</literal> method might look like this (sans exception handling):
|
|
</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>
|
|
In a <literal>Session</literal>, every database operation occurs inside a
|
|
transaction that isolates the database operations (even read-only operations).
|
|
We use Hibernates <literal>Transaction</literal> API to abstract from the underlying
|
|
transaction strategy (in our case, JDBC transactions). This allows our code
|
|
to be deployed with container-managed transactions (using JTA) without any changes.
|
|
</para>
|
|
|
|
<para>
|
|
Note that you may call <literal>HibernateUtil.currentSession();</literal>
|
|
as many times as you like, you will always get the current <literal>Session</literal>
|
|
of this thread. You have to make sure the <literal>Session</literal> is closed
|
|
after your unit-of-work completes, either in your servlet code or in a servlet filter
|
|
before the HTTP response is send. The nice side effect of the second option is easy
|
|
lazy initialization: the <literal>Session</literal> is still open when the view is
|
|
rendered, so Hibernate can load unitialized objects while you navigate the current
|
|
object graph.
|
|
</para>
|
|
|
|
<para>
|
|
Hibernate has various methods that can be used to retrieve objects from the
|
|
database. The most flexible way is using the Hibernate Query Language (HQL),
|
|
which is an easy to learn and powerful object-oriented extension to 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 also offers an object-oriented <emphasis>query by criteria</emphasis> API
|
|
that can be used to formulate type-safe queries. Hibernate of course uses
|
|
<literal>PreparedStatement</literal>s and parameter binding for all SQL communication
|
|
with the database. You may also use Hibernate's direct SQL query feature or
|
|
get a plain JDBC connection from a <literal>Session</literal> in rare cases.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="quickstart-summary" revision="1">
|
|
<title>Finally</title>
|
|
|
|
<para>
|
|
We only scratched the surface of Hibernate in this small tutorial. Please note that
|
|
we don't include any servlet specific code in our examples. You have to create a
|
|
servlet yourself and insert the Hibernate code as you see fit.
|
|
</para>
|
|
|
|
<para>
|
|
Keep in mind that Hibernate, as a data access layer, is tightly integrated into
|
|
your application. Usually, all other layers depent on the persistence mechanism.
|
|
Make sure you understand the implications of this design.
|
|
</para>
|
|
|
|
<para>
|
|
For a more complex application design, see http://caveatemptor.hibernate.org/
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|