Better Faster Lighter Java [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Better Faster Lighter Java [Electronic resources] - نسخه متنی

Justin Gehtland; Bruce A. Tate

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








7.3 Using Your Persistent Model


Within a Hibernate application,


there are at least two types of code.
You've already seen the model, which is completely
independent of Hibernate. You also have the client that uses that
model. This client can take a number of forms. It can be a J2EE
application that uses EJB session beans, a lightweight container like
Spring, a complex, non-EJB J2EE application that uses JTA to manage
transactions, or a simple Java application.

In the previous section, I showed how to build a persistent model and
map it to a relational database schema. That object model is
completely transparent with respect to persistence. In this section,
I show how to use that model. Of course, the code that accesses the
persistent model must use Hibernate classes to load and save data,
and possibly manage transactions.

Some simple persistence frameworks make each access to the database
independent. If you're using such a framework, you
can't manage transactions or cache in the
persistence layer, and it places a heavier burden on the application,
especially in a web environment. Like most of the more robust
persistence frameworks, Hibernate uses sessions. Think of a session
as a running conversation between your application and the persistent
model, and through it, the database. A session factory provides a
convenient attachment point for configuration options, and also
caches and metadata related to a single Hibernate configuration.


7.3.1 Configuring Hibernate


You're going to need another type of


configuration.
If you were using EJB, you'd use a deployment
descriptor to describe the configuration of your system. Hibernate
has some of the same requirements. You're going to
want to configure your JDBC drivers, connection pools, transaction
strategy, security, and the like. Break configuration tasks into your
configuration file and a few lines of code in order to load your
configuration through the Hibernate API.

Recall that you configure the mapping between each persistent class
and the database schema. The inventers of Hibernate had to decide how
to organize the rest of the configuration. The main question is this:
exactly what will the users be configuring: an application, a
Hibernate instance, or all Hibernate instances? Some of those
solutionssuch as configuring an instance or all Hibernate
instancesare simple, but they don't allow
enough flexibility, for instance, for accessing two databases (with
separate configurations) from the same application. One of the
options (configuring every session) is too expensive. Instead,
Hibernate lets you configure a session factory. Then, all of the
sessions that you get from a factory are configured the same way.

Here's the configuration file for the discussion
application, called hibernate.properties:

hibernate.connection.driver_class = com.mysql.jdbc.Driver
hibernate.connection.url = jdbc:mysql://localhost/disc
hibernate.connection.username = batate
hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.show_sql=true

In this simple configuration, I've configured only
the JDBC driver and one option that tells Hibernate to log all SQL
statements that Hibernate generates. You can see the JDBC
configuration parameters you'd expect, such as the
URL, the driver's class name, and the connection
credentials. The configuration file also has a
dialect, a pluggable API that tells Hibernate
the version of SQL to use. Very few SQL implementations actually meet
the ANSII standard. In addition, you often want your framework to
take advantage of extensions that aid performance or flexibility.

After you've built your model, mapped your model,
and built your configuration file, load your configuration with a
couple of lines of code at the beginning of each Hibernate client.
You'll need a separate session factory for each
configuration. Our discussion application only needs one session
factory. Here's the code that loads our
configuration:

class BoardManager {
SessionFactory factory;
Configuration cfg;
BoardManager( ) {
try {
cfg = new Configuration( )
.addClass(discussion.User.class)
.addClass(discussion.Topic.class)
.addClass(discussion.Post.class);
factory = cfg.buildSessionFactory( );
} catch (Exception e) {
System.out.println("Hibernate configuration failed:" + e);
}
}

Notice that this code performs three discrete steps. First, it loads
the configuration specified in the
hibernate.properties file. Second, it adds the
mapping for each class in your persistent model. If
you've ever coded Smalltalk, you might have seen
this coding style. All of the addClass( ) methods
are chained together. If you prefer, and your coding standards
permit, you can break out each addClass( ) method
into a separate statement, like this:

cfg.addClass(discussion.User.class);
cfg.addClass(discussion.Topic.class);
cfg.addClass(discussion.Post.class);

Finally, build the factory. Keep in mind that the configuration file
is very small; in a production environment, it's
likely to be much larger. You're probably going to
want to specify your own connection pool. You may want to configure a
different transaction strategy (such as JTA), a cache manager,
logging and debugging options, or even EJB sessions. A complete
description of the entire configuration is beyond the scope of this
book, but you can find out about each parameter in the excellent
Hibernate documentation.


7.3.2 Using Your Model


Now you've got a model that's




mapped
onto a relational database. You also have a fully configured
persistence framework in Hibernate to manage it. In keeping with our
five principles for better Java, the model is completely transparent
with respect to persistence. The concepts encapsulated by the
business model are fully separated from all other aspects of the
application. All that remains is to tell Hibernate how to move data
to and from your model.

I like to have a class named xManager that manages
persistence for a model. In this example, I've named
the class that manages persistence for the discussion application
BoardManager.


7.3.2.1 Loading data


The first task is to get Hibernate to



populate your business objects.
Like most persistence frameworks, you can ask Hibernate to populate
your model in two ways. First, you can specify the ID of the
root-level object that you wish to load. Second, you can issue a
query in Hibernate Query Language, which is similar to SQL. Look at
this code, which checks the password for a user:

public boolean checkPassword(String id, String password)
throws Exception {
User user = loadUser(id);
if (user == null) {
return false;
}
if (user.getPassword( ).equals(password)) {
return true;
}
return false;
}

In this example, the method loads the user, given the
user's identifier. Then, the method can access the
user object directly, checking the value of the password property. In
this method, exceptions bubble back up to the calling method. If you
know the identifiers of the objects that you need, this is a
convenient way to use the model.

Alternatively, you might need to use the SQL-like query language. For
example, you might need to load all posts for a user. This code
fragment does the trick:

List posts = session.find(
"from posts as p where p.userID = ?",
userID,
Hibernate.string
);

The query language is nearly identical to SQL. You can specify
parameters with the "?" character.
The parameter list for the method specifies the values and types of
the parameters. You don't see a SELECT statement,
because usually you don't need one.
You're usually going to return a list of objects of
the type identified in the from clause.

Hibernate also supports some advanced SQL notions, such as
aggregates. For example, to count the users in our table, issue the
query:

SELECT count(*)
FROM users

Most query language for object-oriented persistence frameworks work
only with true objects. SQL aggregate functions return a scalar type,
not an object. Hibernate opts to keep a richer, more flexible query
language by staying as close as possible to SQL. Other query
languages, such as those for EJB and JDO, have had more limited
success.


7.3.2.2 Updating the database


Now let's look at how


you
tell Hibernate to update the database. The discussion application
must save new users to the database:

public void saveUser(User user) throws Exception {
Session session = null;
try {
session = factory.openSession( );
session.save(user);
session.flush( );
session.connection( ).commit( );
return;
}
finally {
if(session.isOpen( ))
session.close( );
}
}

For all the work that it does, the meat of the method is remarkably
simple. I get a new session from the session factory and then call
the save method on the session, passing in a new
user. The rest of the method processes exceptions and cleans up the
connection. The flush makes sure the cache is
flushed, so the data will be in the database. The
commit method commits the transaction, and
we're done. In this case, User is a very simple
object, but it might have been a complex object, and if
I'd configured it to do so in the mapping, Hibernate
would save each related object without any additional intervention
from me.

Similarly, here's the code to delete a user from the database:

public User removeUser(String id) throws Exception {
Session session = null;
try {
session = factory.openSession( );
User user = new User( ); // object must first be loaded to be deleted
session.load(user, id);
session.delete(user);
session.flush( );
session.connection( ).commit( );
return user;
} catch (Exception e) {
return null; // not found condition should not force error
}
finally {
if(session.isOpen( )) {
session.close( );
}
}

This code is similar to the saveUser method, with
one difference: you must first load the User into the session in
order to delete it. Once again, if you need to remove an object with
relationships, such as a topic that contains other posts, you can
choose to cascade the delete to all related objects, if you configure
the mapping to do so. You can see that the persistence framework
takes care of the tedious details of integrating a relational
database and a persistent model. You didn't have to
work with the JDBC connection and you didn't have to
worry about coding the correct SQL. You simply tell Hibernate to
save, remove, or update the object, and you're off
to the races.


/ 111