+ All Categories
Home > Documents > Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many...

Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many...

Date post: 22-May-2020
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
14
Transcript
Page 1: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate
Dottie
Text Box
Excerpt from chapter 1: Using Direct JDBC
Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 2: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

vii

Brief contents

1 ❍ Why Hibernate? 1

2 ❍ Installing and building projects with Ant 26

3 ❍ Hibernate basics 50

4 ❍ Associations and components 88

5 ❍ Collections and custom types 123

6 ❍ Querying persistent objects 161

7 ❍ Organizing with Spring and data access objects 189

8 ❍ Web frameworks: WebWork, Struts, and Tapestry 217

9 ❍ Hibernating with XDoclet 274

10 ❍ Unit testing with JUnit and DBUnit 313

11 ❍ What’s new in Hibernate 3 346

Appendix ❍ The complete Hibernate mapping catalog 364

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 3: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 9

ORM is a good solution for legacy databases when the schema

❂ Is highly normalized❂ Has primary keys❂ Has foreign key relationships referring to primary keys, not col-

umns

Thankfully, the Hibernate developers have been responsive to develop-ers working with legacy database schemas. Hibernate 3, discussed inchapter 11, adds many new features to support legacy database schemas.

Before diving into what Hibernate offers, let’s take a brief look at whyusing JDBC is so painful for large applications. If you’re still clingingto direct JDBC for application persistence, the next section is for you.

The core drawback of JDBC is that it doesn’t allow you to storeobjects directly to the database—you must convert the objects to arelational format. For instance, if you want to persist a new instance ofthe Event class to the database, you must first convert the Event objectto a SQL statement that can be executed on the underlying database.Similarly, when rows are returned from the database, you must converteach result row into an instance of Event. Let’s look at some of the dif-ficulties presented when converting objects and graphs of objectsbetween the relational and object models.

When working with objects, you’re generally using a number of con-nected objects. This is called an object graph. An object graph repre-sents an internally consistent view of application data. Internallyconsistent means that a change made to one object is reflected through-out the graph. The objects within a graph are typically connected usingone-to-one or one-to-many associations.

Using direct JDBC for persistence presents distinct problems for eachof the persistence operations: creation, updating, retrieval, and dele-tion. Some of the problems we describe expand on the object/relational

1.2 Using direct JDBC

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Dottie
Text Box
Excerpt from chapter 1
Page 4: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

10 CHAPTER 1 Why Hibernate?

mismatch, discussed earlier. We examine those problems in detail in amoment, using an example application that will reappear throughoutthis book.

1.2.1 Example application

To address the drawbacks of traditional application persistence withJDBC, we must first introduce an example that we’ll use as the basis ofcomparison. The application that we use throughout the book is anevent-management application used to manage a conference withspeakers, attendees, and various locations, among other things. Todemonstrate the problems with JDBC, we’ll discuss persisting one ofthe central objects in the domain model, Event.

We use the term domain model frequently. A domain model is the col-lection of related objects describing the problem domain for an applica-tion. Each object in the domain model represents some significantcomponent in the application, such as an Event or Speaker.

Diagrams of the Event object and the relational table used to store theEvent are shown in figure 1.5.

The parallel between the Event object and the relational table is clear.Each property in the Event class is reflected as a column in the eventstable. The id column in the events table is the primary key for thetable. We’ve intentionally kept the Event object simple for the openingdiscussion. With the object and relational table defined, we can moveforward with examining the drawbacks of application persistence withdirect JDBC.

Event

id:Long

name:String

startDate:java.util.Date

duration:int

events

id

name

start _date

duration

bigint (pk)

varchar (255)

date

int

Figure 1.5 The Event object and the events table

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 5: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 11

1.2.2 Retrieving object graphs using JDBC

Looking at the diagram of the Event object in figure 1.5, it appears thatconverting between relational and object models presents little diffi-culty. Problems arise when we want to retrieve a complete object graphfrom a relational schema. Figure 1.6 presents a domain model for ourevent-management application.

The Event class has three associations: a one-to-one association to theLocation object and two one-to-many associations to the Speaker andAttendee objects. Figure 1.7 shows the relational tables for the domainmodel. (The speakers table is omitted since it’s identical to the attend-ees table.)

Let’s look at the one-to-one association of the events and locationstables. The tables can be joined to retrieve the data from the locationstable for a given row in the events table with the following SQL:

select e.id, e.name, e.start_date, e.duration, l.id, l.name from events e join locations l on e.location_id = l.id where e.id = 1000;

Executing this SQL returns a single row with columns containing datafrom both the events and locations tables.

The associations between the Event object and the Attendee andSpeaker objects can be more difficult to manage because they involve

Speaker Event Attendee

Location

* 1 1 *

1

1

Figure 1.6 A domain model for an Event

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 6: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

12 CHAPTER 1 Why Hibernate?

one-to-many associations. Object associations are directional, from oneobject to another object. To navigate from both ends of the association,you must define the association in both objects. Listing 1.1 illustratesthe one-to-many association between the Event and Speaker objects,using the following Java classes.

Listing 1.1 Creating a bidirectional association

package com.manning.hq.ch01;import java.util.List;

public class Event {

private String name; private List speakers; private Location location;

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public List getSpeakers() { return this.speakers; }

public void setSpeakers(List speakers) { this.speakers = speakers; }

public Location getLocation() { return location;

locations

idname

bigint (pk)varchar (255)

events

idlocation_ idnamestart _dateduration

bigint (pk)bigintvarchar (255)dateint

speakers

idnametitleevent _ id

bigint (pk)varchar (255)varchar( 50)bigint

Figure 1.7 The foreign keys for events and speakers

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 7: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 13

}

public void setLocation(Location location) { this.location = location; }}

package com.manning.hq.ch01;public class Speaker {

private Event event;

public Event getEvent() { return this.event; }

public void setEvent(Event event) { this.event = event; }}

package com.manning.hq.ch01;

public class Location {

private Long id = null; private String name = null; private Event event = null;

public Long getId() { return id; }

public void setId(Long id) { this.id = id; }

public String getName() { return name; }

public void setName(String name) { this.name = name; }

public Event getEvent() { return event;

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 8: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

14 CHAPTER 1 Why Hibernate?

}

public void setEvent(Event event) { this.event = event; }

}

By defining the association in both objects, you can navigate in eitherdirection: from the Speaker to the Event or from the Event to theSpeaker. When translating this association to the relational database,you’ll realize that whereas the database has the notion of the associa-tion through the use of foreign keys, it lacks the notion of associationmultiplicity. The database doesn’t know that there are multiple rows inthe speakers table linked to the events table. You must write the logicto retrieve relevant rows from the database to populate the one-to-many associations.

To retrieve associated rows from the speakers table for a row in theevents table, you must execute separate queries for each table. Whycan’t you use another table join to the speakers table to retrieve thedata for the object graph, as you did for the locations table?

Suppose you want to retrieve one row in both the events and loca-tions table, and they’re linked with a foreign key. The row in theevents table is linked to four rows in the speakers table, also with aforeign key. The SQL to retrieve all data associated to the event datais shown here:

select e.name, l.name, s.first_name, s.last_name from events e join locations l on e.location_id = l.id join speakers s on s.event_id = e.id where e.id = 1000;

Executing this SQL results in a Cartesian product of the data, asshown in figure 1.8. (If you’re unfamiliar with the term, a Cartesianproduct is the combination of all pairs of elements in two sets.)

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 9: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 15

Although all the data was retrieved with a single query, Cartesianproducts are generally inefficient. For this reason, to retrieve the datafor one-to-many associations, you should execute a separate query foreach object.

Remember that the domain model in figure 1.2 also has a one-to-manyassociation of Attendee instances. To retrieve the data for the Attendeeobjects, you must write operations similar to the Speaker association.Since an object graph often contains many objects, the amount of codeneeded to retrieve a full object graph for an Event can be quite large.

Usually you only need to retrieve a portion of the object graph for aspecific view that is presented to the user, such as displaying theAttendee instances assigned to an Event. Retrieving the extra objectsresults in needless calls to the database and overhead in converting theResultSet into the corresponding domain objects.

A direct JDBC persistence layer would need to provide the ability toreturn specific portions of the object graph, including the ability to pop-ulate collections of associations when required. These aren’t trivial tasksand require a significant investment for the developers and organization.

To this point, we have discussed retrieving objects. New problemsarise when you try to persist an object graph to a relational database.

1.2.3 Persisting object graphs to a relational model

If a new instance of Event needs to be persisted, you must first convertthe instance into a format for inclusion in a SQL statement. Assumingthat Speaker and Attendee instances have been associated with the

Opening Presentation

Opening Presentation

Opening Presentation

Opening Presentation

Amy Watkins

Marcus Smith

Mark Johannson

Diane Davies

Hilton Convention Center

Hilton Convention Center

Hilton Convention Center

Hilton Convention Center

e.name s.namel.name

Figure 1.8 Cartesian product result

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 10: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

16 CHAPTER 1 Why Hibernate?

Event, you must also convert and persist these associations, maintain-ing their link to the parent Event. Some of the objects in the graph mayalready exist in the database, but other new objects may have beenadded to the graph. How can you determine which objects in the graphshould be inserted and which should be updated?

You can usually determine the operation to execute by examining theobject’s id property. If the ID type is an object, such as a Long or Inte-ger, you can assume that the object is transient and hasn’t yet been per-sisted if the ID’s value is null. If the ID type is a primitive, such as intor long, a value of 0 indicates a transient object. (Recall that ints andlongs are initialized to 0.) In both cases, a SQL INSERT should beissued after converting the object to a relational format. Otherwise, anUPDATE would be issued for the object, keyed on the value of the ID.

At what point is the value of the id property assigned? If the databasesupports identity columns or sequences, you can let the database assignthe ID value. Alternatively, you can have the application assign the IDvalue, but this must be handled carefully. Application-managed iden-tity generators must ensure that the generator is thread-safe, is effi-cient, and won’t deadlock under heavy load. For the examples in thisbook, we use database-generated identifier values.

Let’s examine this process with an example of persisting an objectgraph. Start by creating a new graph, shown in listing 1.2.

Listing 1.2 Creating a new object graph

package com.manning.hq.ch01;

import java.util.ArrayList;import java.util.List;

public class Example2 {

private Event event = null; private List speakers = null;

public static void main(String[] args) { Example2 app = new Example2();

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 11: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 17

app.doMain(args); }

private void doMain(String[] args) { // Create the Event instance event = createEvent(); // Create two Speaker instances speakers = createSpeakers(); // and add them to the Event event.setSpeakers(speakers); }

private Event createEvent() { Event event = new Event(); event.setName("Opening Presentation"); // ... set date and duration return event; }

private List createSpeakers() { List speakers = new ArrayList(); Speaker speaker0 = new Speaker(); Speaker speaker1 = new Speaker(); // ... set properties for speakers speakers.add(speaker0); speakers.add(speaker1); return speakers; }}

When persisting the object graph, you first need to save the Eventinstance and retrieve the created ID value from the database. This newID value is used as the foreign key for each of the associated objects—the Speaker instances—when they’re persisted.

Although cumbersome, this method works as long as the object graphis persisted from the parent to the children. This is referred to as acascading save. If you add a new Location to the object graph, as inlisting 1.3, the direct JDBC persistence layer must specify that theLocation instance needs to be persisted before the Event to avoid a for-eign key violation when the row is inserted into the events table.

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 12: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

18 CHAPTER 1 Why Hibernate?

Listing 1.3 Setting a newly created Location for the Event

private Location location = null;

private void doMain(String[] args) { // Create location location = createLocation(); // Create Event instance event = createEvent(location); // Create two Speaker instances speakers = createSpeakers(); // and add them to the Event event.setSpeakers(speakers);}

private Location createLocation() { Location location = new Location(); location.setName("Grand Hyatt – Convention Room A"); return location;}

private Event createEvent(Location location) { Event event = new Event(); event.setName("Opening Presentation"); // Assign location to event event.setLocation(location); // Establish bi-directional association location.setEvent(event); // ... set date and duration return event;}

A persistence layer implemented with direct JDBC must be able topersist all or part of a complex object graph while avoiding foreign keyviolations. Similar behavior is required when deleting objects andobject graphs from a relational database.

1.2.4 Deleting object graphs

Suppose that an Event has been cancelled and the associated datashould be removed from the database. The direct JDBC persistence

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 13: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

Using direct JDBC 19

layer must handle deleting not only the Event, but also the objects asso-ciated to the Event, such as the Speakers and Attendees. The deleteoperation should not cascade to the Location, however, since multipleEvents can be held at a given Location. Assuming that a Locationneeds to be deleted, each of the corresponding Events held at the Loca-tion should also be deleted, being careful to cascade to the childobjects of the Event.

Deleting, or making a persistent object transient, is the easiest persis-tence operation when you’re using direct JDBC for application persis-tence. Still, you must be careful to delete only the relevant objects fromthe graph.

1.2.5 Querying object graphs

Although JDBC’s Statement and PreparedStatement classes providethe ability to query a database, you must still write the SQL statementand process the results. Most direct JDBC persistence layers havesome form of SQL generation for the objects in the domain model, butit’s often incomplete and lacks the flexibility needed for an enterpriseapplication. The SQL generation component must also be updated asthe application matures and requirements change.

Executing a query with the Statement or PreparedStatement classreturns a ResultSet object containing the query results. The Result-Set is essentially a list of key-value pairs. Each entry in the list repre-sents one result row: The key is the column name, and the value is thedata returned.

Now that you have the results, how should you return the data to theapplication? There are two options: You can convert the results eitherinto a list of Event objects or into a list of Map instances. The latter solu-tion may seem more appealing because it’s easier to code (you can addthe properties as Map.Entry objects), but this method also introducessome problems.

A plain old Java object (POJO), such as the Event object, supportprimitive type properties, such as int, char, and boolean, as well as

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak
Page 14: Excerpt from chapter 1: Using Direct JDBCFor more ...CHAPTER 1 Why Hibernate? one-to-many associations. Object associations are directional, from one object to another object. To navigate

20 CHAPTER 1 Why Hibernate?

objects, such as String and Date. The Java Collections classes onlysupport objects. To return a list of Map instances, you would need toconvert each primitive type into its object representation.

By using Map instances, you also forfeit any behavior that the Eventclass provides. Recall that a domain model contains both the data andthe behavior for the objects. Clearly, the benefit of the domain model islost if the Event instances aren’t used.

To return a list of Event instances from a ResultSet, you must converteach result row into a corresponding Event instance. Data returned forassociated objects, like Location, must also be converted and set for theEvent. While this may not seem like a huge chore, writing code to con-vert every object to and from a relational schema quickly becomestedious and error-prone.

There are clearly a number of open issues when persisting objects withdirect JDBC. You can certainly try to answer all of them, but thisresults in a large number of classes, repetitive and complicated code, aswell as a huge time commitment in maintenance and testing.

Next, we’ll look at how to use Hibernate to overcome some of theproblems that JDBC presents.

After examining the shortcomings in our persistence techniques usingdirect JDBC, let’s discuss the benefits of using Hibernate for applica-tion persistence. Hibernate addresses all the shortcomings of the previ-ous persistence methods and offers a number of additional features.The core benefits of Hibernate are simplicity, flexibility, completeness,and performance.

1.3.1 Simplicity and flexibility

Rather than the handful of classes and configuration propertiesrequired by some persistence solutions, such as EJBs, Hibernate

1.3 Persistence with Hibernate

Dottie
Text Box
For more information or to place an order, visit www.manning.com/peak

Recommended