Hibernate In Action
Retrieving objects
Retrieving persistent objects from the database is one of the most interesting (andcomplex) parts of working with Hibernate. Hibernate provides the following waysto get objects out of the database:
●Navigating the object graph, starting from an already loaded object,byaccessingtheassociatedobjectsthrough property accessor methods such as a User.getAddress().getCity().Hibernate will automatically load (or preload)nodes of the graph while you navigate the graph if the Session is open.
●Retrieving by identifier, which is the most convenient and performant method when the uniqueidentifier value of an object is known.
●Using the Hibernate Query Language (HQL), which is a full object-orientedquerylanguage.
●Using the, Hibernate Criteria API, which provides a type-safe and objectoriented way to perform queries without the need for string manipulation.This facility includes queries based on an example object.
●Using native SQL queries, where Hibernate takes care of mapping the JDBC result sets to graphs of persistent objects.In your Hibernateapplications, you’ll use a combination of these techniques.Each retrieval method may use a different fetching strategy—that is, a strategy that defines what part of the persistent object graph should be retrieved. The goal is to find the best retrieval method and fetching strategy for every use case in your application while at the same time minimizing the number of SQL queries for best performance. We won’t discuss each retrieval method in much detail in this section; instead we’ll focus on the basic fetching strategies and how to tune Hibernate mapping files for best default fetching for all methods. Before we look at the fetchingstrategies,we’ll give an overview of the retrieval methods. (We mention the Hibernate caching system but fully explore it in the next chapter.)Let’s start with the simplest case, retrieval of an object by giving its identifier value (navigating the object graph should self-explanatory). You saw a simple retrieval by identifier earlier in this chapter, but there is more to know about it.
Retrieving objects by identifier
The following Hibernate code snippet retrieves a User object from the database:
User user = (User) session.get(User.class, userID);The get() method is special because the identifier uniquely identifies a single;instance of a class. Hence it’s common for applications to use the identifier as aconvenient handle to a persistent object. Retrieval by identifier can use the cachewhen retrieving an object, avoiding a database hit if the object is already cached. Hibernate also provides a load() method:User user = (User) session.load(User.class, userID); The load() method is older; get() was added to Hibernate’s API due to userrequest. The difference is trivial:
●If load() can’t find the object in the cache or database, an exception isthrown. The load() method never returns null. The get() method returnsnull if the object can’t be found.
●The load() method may return a proxy instead of a real persistent instance.A proxy is a placeholder that triggers the loading of the real object when it’s accessed for the first time; we discuss proxies later in this section. On the other hand, get() never returns a proxy.Choosing between get() and load() is easy: If you’re certain the persistentobject exists, and nonexistence would be considered exceptional, load() is a good option. If you aren’t certain there is a persistent instance with the given identifier, use get() and test the return value to see if it’s null. Using load() has a further implication: The application may retrieve a valid reference (a proxy) to a persistent instance without hitting the database to retrieve its persistent state. So load() might not throw an exception when it doesn’t find the persistent object in the cache or database; the exception would be thrown later, when the proxy is accessed. Of course, retrieving an object by identifier isn’t as flexible as using arbitrary queries
Introducing HQL
The Hibernate Query Language is an object-oriented dialect of the familiar relational query language SQL. HQL bears close resemblances to ODMG OQL andEJB-QL; but unlike OQL, it’s adapted for use with SQL databases, and it’s much more powerful and elegant than EJB-QL (However, EJB-QL 3.0 will be very similar to HQL.) HQL is easy to learn with basic knowledge of SQL. HQL isn’t a data-manipulation language like SQL. It’s used only for object retrieval, not for updating, inserting, or deleting data. Object state synchronization is the job of the persistence manager, not the developer.
Most of the time, you’ll only need to retrieve objects of a particular class and restrict by the properties of that class. For example, the following query retrieves a user by first name:
Query q = session.createQuery("from User u where u.firstname = :fname"); q.setString("fname", "Max"); List result = q.list(); After preparing query q, we bind the identifier value to a named parameter, fname.The result is returned as a List of User objects.
HQL is powerful, and even though you may not use the advanced features all the time, you’ll need them for some difficult problems. For example, HQL supports the following:
●The ability to apply restrictions to properties of associated objects related by reference or held in collections (to navigate the object graph using query language).
●The ability to retrieve only properties of an entity or entities, without the overhead of loading the entity itself in a transactional scope. This is sometimes called a report query; it’s more correctly called projection.
●The ability to order the results of the query.
●The ability to paginate the results.
●Aggregation with group by, having, and aggregate functions like sum, min, and max.
●Outer joins when retrieving multiple objects per row.
●The ability to call user-defined SQL functions.
●Subqueries (nested queries).
Query by criteria
The Hibernate query by criteria (QBC) API lets you build a query by manipulating criteria objects at runtime. This approach lets you specify constraints dynamically without direct string manipulations, but it doesn’t lose much of the flexibility or power of HQL. On the other hand, queries expressed as criteria are often less readable than queries expressed in HQL.
Retrieving a user by first name is easy using a Criteria object: Criteria criteria = session.createCriteria(User.class); criteria.add( Expression.like("firstname", "Max") ); List result = criteria.list(); A Criteria is a tree of Criterion instances. The Expression class provides static factory methods that return Criterion instances. Once the desired criteria tree is built, it’s executed against the database.
Many developers prefer QBC, considering it a more object-oriented approach. They also like the fact that the query syntax may be parsed and validated at compile time, whereas HQL expressions aren’t parsed until runtime.
The nice thing about the Hibernate Criteria API is the Criterion framework. This framework allows extension by the user, which is difficult in the case of a query language like HQL
Query by example
As part of the QBC facility, Hibernate supports query by example (QBE). The idea behind QBE is that the application supplies an instance of the queried class with certain property values set (to nondefault values). The query returns all persistent instances with matching property values. QBE isn’t a particularly powerful approach, but it can be convenient for some applications. The following code snippet demonstrates a Hibernate QBE:
User exampleUser = new User(); exampleUser.setFirstname("Max"); Criteria criteria = session.createCriteria(User.class); criteria.add( Example.create(exampleUser) ); List result = criteria.list(); A typical use case for QBE is a search screen that allows users to specify a range of property values to be matched by the returned result set. This kind of functionality can be difficult to express cleanly in a query language; string manipulations would be required to specify a dynamic set of constraints.
Both the QBC API and the example query mechanism are discussed in more detail in chapter 7. You now know the basic retrieval options in Hibernate. We focus on the strategies for fetching object graphs in the rest of this section. A fetching strategy defines what part of the object graph (or, what subgraph) is retrieved with a query or load operation.
Fetching strategies
In traditional relational data access, you’d fetch all the data required for a particular with a single SQL query, taking advantage of inner and outer joins to retrieve related entities. Some primitive ORM implementations fetch data piecemeal, with many requests for small chunks of data in response to the application’s navigating a graph of persistent objects. This approach doesn’t make efficient use of the relational database’s join capabilities. In fact, this data access strategy scales poorly by nature. One of the most difficult problems in ORM—probably the most difficultis providing for efficient access to relational data, given an applicationthat prefers to treat the data as a graph of objects.
For the kinds of applications we’ve often worked with (multi-user, distributed, web, and enterprise applications), object retrieval using many round trips to/from the database is unacceptable. Hence we argue that tools should emphasize the R in ORM to a much greater extent than has been traditional.
The problem of fetching object graphs efficiently (with minimal access to the database) has often been addressed by providing association-level fetching strategies specified in metadata of the association mapping. The trouble with this approach is that each piece of code that uses an entity requires a different set of associated objects. Butthis isn’t enough. We argue that what is needed is support forfine-grained runtime association fetching strategies. Hibernate supports both, it lets you specify a default fetching strategy in the mappingfile and then override it at runtime in code.
Hibernate allows you to choose among four fetching strategies forany association, in association metadata and at runtime:
●Immediate fetching—The associated object is fetched immediately, using a sequential database read (or cache lookup).
●Lazy fetching—The associated object or collection is fetched “lazily,” when it’s first accessed. This results in a new request to the database (unless the associated object is cached).
●Eager fetching—The associated object or collection is fetched together with the owning object, using an SQL outer join, and no further database requestis required.
●Batch fetching—This approach may be used to improve the performance of lazy fetching by retrieving a batch of objects or collections when a lazy association is accessed. (Batch fetching may also be used to improve the performance of immediate fetching.)
Let’s look more closely at each fetching strategy.
Immediate fetching
Immediate association fetching occurs when you retrieve an entity from the database and then retrieve another associated entity or entities in a further request to the database or cache. Immediate fetching isn’t usually an efficient fetching strategy unless you expect the associated entities to almost always be cached already.
Lazy fetching
When a client requests an entity and its associated graph of objects from the database, it isn’t usually necessary to retrieve the whole graph of every (indirectly) associated object. You wouldn’t wantto load the whole database into memory at once; for example, loading a single Category shouldn’t trigger the loading of all Items inthat category.
Lazy fetching lets you decide how much of the object graph is loaded in the first database hit and which associations should be loaded only when they’re first accessed. Lazy fetching is a foundational concept in object persistence and the first step to attaining acceptable performance.
We recommend that, to start with, all associations be configured for lazy (or perhaps batched lazy) fetching in the mapping file. Thisstrategy may then be overridden at runtime by queries that force eager fetching to occur.
Eager (outer join) fetching
Lazy association fetching can help reduce database load and is often a good default strategy. However, it’s a bit like a blind guessas far as performance optimization goes.
Eager fetching lets you explicitly specify which associated objects should be loaded together with the referencing object.Hibernatecan then return the associated objects in a single database request,utilizing an SQL OUTER JOIN. Performance optimization in Hibernate often involves judicious use of eager fetching for particular transactions.Hence, even though default eager fetching may be declared in the mapping file, it’s more common to specify the use of this strategyat runtime for a particular HQL or criteria query.
Batch fetching
Batch fetching isn’t strictly an association fetching strategy; it’s a technique that mayhelp improve the performance of lazy (or immediate) fetching. Usually,when you load an object or collection, your SQL WHERE clause specifies the identifier of the object or object that owns the collection.If batch fetching is enabled, Hibernate looks to see what other proxied instances or uninitialized collections are referenced in the current session and tries to load them at the same time by specifying multiple identifier values in the WHERE clause.
We aren’t great fans of this approach; eager fetching is almostalways faster. Batch fetching is useful for inexperienced users who wish to achieve acceptable performance in Hibernate without having to think too hard about the SQL that will be executed. (Note that batch fetching may be familiar to you, since it’s used by many EJB2engines.)
We’ll now declare the fetching strategy for some associations inour mapping metadata.
Struts——An Open-source MVC Implementation
This article introduces Struts, a Model-View-Controller implementation that uses servlets and JavaServer Pages (JSP) technology. Struts can help you control change in your Web project and promote specialization. Even if you never implement a system with Struts, you may get some ideas for your future servlets and JSP page implementation
Introduction
Kids in grade school put HTML pages on the Internet. However, there is a monumental difference between a grade school page and a professionally developed Web site. The page designer (or HTML developer) must understand colors, the customer, product flow, page layout, browser compatibility, image creation, JavaScript, and more. Putting a great looking site together takes a lot of work, and most Java developers are more interested in creating a great looking object interface than a user interface. JavaServer Pages (JSP) technology provides the glue between the page designer and the Java developer.
If you have worked on a large-scale Web application, you understand the term change. Model-View-Controller (MVC) is a design pattern put together to help control change. MVC decouples interface from business logic and data. Struts is an MVC implementation that uses Servlets 2.2 and JSP 1.1 tags, from the J2EE specifications, as part of the implementation. You may never implement a system with Struts, but looking at Struts may give you some ideas on your future Servlets and JSP implementations.
Model-View-Controller (MVC)
JSP tags solved only part of our problem. We still have issues with validation, flow control, and updating the state of the application. This is where MVC comes to the rescue. MVC helps resolve some of the issues with the single module approach by dividing the problem into three categories:
Model
The model contains the core of the application's functionality. The model encapsulates the state of the application. Sometimes the only functionality it contains is state. It knows nothing about the view or controller.
View
The view provides the presentation of the model. It is the look of the
application. The view can access the model getters, but it has no knowledge of the setters. In addition, it knows nothing about the controller. The view should be notified when changes to the model occur.
Controller
The controller reacts to the user input. It creates and sets the model.
Struts details
Displayed in Figure 6 is a stripped-down UML diagram of the
org.apache.struts.action package. Figure 6 shows the minimal relationships among ActionServlet (Controller), ActionForm (Form State), and Action
(Model Wrapper).
The ActionServlet class
Do you remember the days of function mappings? You would map some input event to a pointer to a function. If you where slick, you would place the configurationinformation into a file and load the file at run time. Function pointer arrays were the good old days of structured programming in C.
Life is better now that we have Java technology, XML, J2EE, and all that. The Struts Controller is a servlet that maps events (an event generally being an HTTP post) to classes. And guess what -- the Controller uses a configuration file so you don_t have to hard-code the values. Life changes, but stays the same.
ActionServlet is the Command part of the MVC implementation and is the
core of the Framework. ActionServlet (Command) creates and uses Action, an ActionForm, and ActionForward. As mentioned earlier, the struts-config.xml file configures the Command. During the creation of the Web project, Action and ActionForm are extended to solve the specific problem space. The file struts-config.xml instructs ActionServlet on how to use the extended classes. There are several advantages to this approach:
The entire logical flow of the application is in a hierarchical text file. This makes it easier to view and understand, especially with large applications. The page designer does not have to wade through Java code to understand the flow of the application.
The Java developer does not need to recompile code when making flow changes.
Command functionality can be added by extending ActionServlet.