To integrate Hibernate with your Java application, you will need to use
several Java libraries. The first library is the Java Archive (JAR) file
for your JDBC driver, which you will need to find for your specific
relational database.
SessionFactory object is thread safe
The details of the join table that contains the links between the two classes in a many-to-many relationship go on the owner class. The Category class owns the relationship, so we add a @JoinTable annotation. The @JoinTable annotation indicates that the relationship requires the creation of an additional link table, so we specify the name of the table containing that information.
The @ManyToMany annotation indicates that the Category class has a many-to-many relationship with the Advert class. This many-to-many relationship is bidirectional, which means that the Advert class has a collection of Category objects, and the Category class has a collection of Advert objects. For many-to-many relationships, we need to tell Hibernate which class is the owner of the relationship. For bidirectional many-to-many relationships, either side can be designated as the owner. For this example, the Category class will be the owner.
Entities can contain references to other entities—either directly as a property or field, or indirectly via a collection of some sort (arrays, sets, lists, etc.). These associations are represented using foreign key relationships in the underlying tables.
You should not use a load() method unless you are sure that the object exists. If you are not certain, then use one of the get() methods. The load() methods will throw an exception if the unique id is not found in the database, whereas the get() methods will merely return a null reference.
You can also instruct Hibernate to use a flushing mode for the session with the setFlushMode() method. The getFlushMode() method returns the flush mode for the current session, as follows:
By default, Hibernate does not cascade any operations—the default behavior can be overridden at the entity level via the XML mapping files using the default-cascade attribute on the <hibernate-mapping> XML element or in the annotated source files.
SessionFactory object is thread safe
The details of the join table that contains the links between the two classes in a many-to-many relationship go on the owner class. The Category class owns the relationship, so we add a @JoinTable annotation. The @JoinTable annotation indicates that the relationship requires the creation of an additional link table, so we specify the name of the table containing that information.
The @ManyToMany annotation indicates that the Category class has a many-to-many relationship with the Advert class. This many-to-many relationship is bidirectional, which means that the Advert class has a collection of Category objects, and the Category class has a collection of Advert objects. For many-to-many relationships, we need to tell Hibernate which class is the owner of the relationship. For bidirectional many-to-many relationships, either side can be designated as the owner. For this example, the Category class will be the owner.
Entities can contain references to other entities—either directly as a property or field, or indirectly via a collection of some sort (arrays, sets, lists, etc.). These associations are represented using foreign key relationships in the underlying tables.
When only one of the pair of entities
contains a reference to the other, the association is unidirectional. If
the association is mutual, then it is referred to as bidirectional.
If both ends of the association managed the foreign keys, then we would encounter a problem when client code called the appropriate set method on both ends of the association. Should two foreign key columns be maintained—one in each direction (risking circular dependencies)—or only one? (And if only one, should altering either side affect it, o r only one?)
If both ends of the association managed the foreign keys, then we would encounter a problem when client code called the appropriate set method on both ends of the association. Should two foreign key columns be maintained—one in each direction (risking circular dependencies)—or only one? (And if only one, should altering either side affect it, o r only one?)
Ideally, we would like to dictate that only
changes to one end of the relationship will result in any updates to the
foreign key; and indeed, Hibernate
allows us to do this by marking one end of the association as being
managed by the other (in the XML mapping files, this is known as the "inverse" of the parent, whereas in the JPA terminology used by the annotation mappings, it is marked as being "mappedBy" the parent in the @OneToMany annotation).
Caution |
inverse and mappedBy
are purely about how the foreign key relationships between entities are
saved. They have nothing to do with saving the entities themselves.
Despite this, they are often confused with the entirely orthogonal
cascade functionality (described in the "Cascading Operations" section of this chapter).
|
While Hibernate lets us specify that changes to one association will result in changes to the database, it does not
allow us to cause changes to one end of the association to be
automatically reflected in the other end in the Java POJOs. For example,
in a one-to-one bidirectional association between an Email class and a Message class, the code in Listing 4-2 is incomplete even if the Message entity is the inverse of the Email entity:
You should not use a load() method unless you are sure that the object exists. If you are not certain, then use one of the get() methods. The load() methods will throw an exception if the unique id is not found in the database, whereas the get() methods will merely return a null reference.
You can also instruct Hibernate to use a flushing mode for the session with the setFlushMode() method. The getFlushMode() method returns the flush mode for the current session, as follows:
public void setFlushMode(FlushMode flushMode) public FlushMode getFlushMode()
The possible flush modes are the following:
-
ALWAYS: Every query flushes the session before the query is executed This is going to be very slow.
-
AUTO: Hibernate manages the query flushing to guarantee that the data returned by a query is up-to-date.
-
COMMIT: Hibernate flushes the session on transaction commits.
-
MANUAL: Your application needs to manage the session flushing with the flush() method. Hibernate never flushes the session itself.
By default, Hibernate uses the AUTO
flush mode. Generally, you should use transaction boundaries to ensure
that appropriate flushing is taking place, rather than trying to
"manually" flush at the appropriate times.
By default, Hibernate does not cascade any operations—the default behavior can be overridden at the entity level via the XML mapping files using the default-cascade attribute on the <hibernate-mapping> XML element or in the annotated source files.
The last possible cascading type is delete-orphan. Use delete-orphan
to remove a child object from the database when you remove the child
from the parent's collection. This cascading type only works on
one-to-many associations. The all cascading type does not include delete-orphan—you will have to use "all,delete-orphan", as in the following excerpt from a Hibernate mapping file:
Instead, we want only the catalog to load, possibly with the categories as well. Only when the user drills down into the categories should a subset of the products in that category be loaded from the database.
Instead, we want only the catalog to load, possibly with the categories as well. Only when the user drills down into the categories should a subset of the products in that category be loaded from the database.
To manage this problem, Hibernate
provides a facility called lazy loading. When enabled (this is the
default using XML mappings, but not when using annotations), an entity's
associated entities will only be loaded when they are directly
requested. For example, the following code loads only a single entity
from the database:
Lazy Loading
When you load classes into memory from the database, you don't necessarily want all the information to actually
be loaded. To take an extreme example, loading a list of e-mails should
not cause the full body text and attachments of every e-mail to be
loaded into memory. First, they might demand more memory than is
actually available. Second, even if they fit, it could take a long time
for all of this information to be obtained.
If you were to tackle this problem in SQL,
you would probably select a subset of the appropriate fields for the
query to obtain the list; for example:
SELECT from, to, date, subject FROM email WHERE username = 'dcminter';
Hibernate will allow you to fashion queries that are rather similar to this, but it also offers a more flexible approach, known as lazy loading. Certain relationships can be marked as being "lazy," and they will not be loaded from disk until they are actually required.
The default in Hibernate 3 is that classes (including collections like Set and Map) should be lazily loaded. For example, when an instance of the User class given in the next listing is loaded from the database, the only fields initialized will be userId and username.
public class User { int userId; String username; EmailAddress emailAddress; Set roles; }
However, as long as the object is still associated with Hibernate in the appropriate way (see Chapter 9), the appropriate objects for emailAddress and roles will be loaded from the database if they are accessed.
This is the default behavior only; the mapping file can be used to specify which classes and fields should behave in this way.
Required Libraries for Running Hibernate 3.5
Hibernate requires several libraries beyond hibernate3.jar. These libraries are included in the lib/required directory of your Hibernate 3.5 installation. Besides the libraries in lib/required, Hibernate also uses a JPA library, which is included in the lib/jpa directory.
Hibernate 3.5 also requires a bytecode library
to function. There are two bytecode libraries shipped with the
Hibernate distribution — javassist and CGLib. With Hibernate 3.5, you
need to use one or the other. In this book, we will use javassist, as it
is the default library.
Introduction to the Life Cycle
After adding Hibernate to your
application, you do not need to change your existing Java object model
to add persistence marker interfaces or any other type of hint for
Hibernate. Instead, Hibernate works with normal Java objects that your
application creates with the new operator, or
that other objects create. For Hibernate's purposes, these can be drawn
up into two categories: objects for which Hibernate has entity
mappings, and objects that are not directly recognized by Hibernate. A
correctly mapped entity object will consist of fields and properties
that are mapped, and that are themselves either references to correctly
mapped entities, references to collections of such entities, or "value"
types (primitives, primitive wrappers, strings, or arrays of these).
Given an instance of an object that is mapped
to Hibernate, it can be in any one of three different states:
transient, persistent, or detached.
Transient objects exist in memory, as illustrated in Figure 4-1. Hibernate does not manage transient objects or persist changes to transient objects.
To persist the changes to a transient object,
you would have to ask the session to save the transient object to the
database, at which point Hibernate assigns the object an identifier.
Persistent objects exist in the database, and
Hibernate manages the persistence for persistent objects. We show this
relationship between the objects and the database in Figure 4-2. If fields or properties change on a persistent object, Hibernate will keep the database representation up-to-date.
Detached objects have a representation in the
database, but changes to the object will not be reflected in the
database, and vice versa. This temporary separation of the object and
the database is shown in Figure 4-3.
A detached object can be created by closing the session that it was
associated with, or by evicting it from the session with a call to the
session's evict() method. One reason you
might consider doing this would be to read an object out of the
database, modify the properties of the object in memory, and then store
the results some place other than your database. This would be an
alternative to doing a deep copy of the object.
In order to persist changes made to a
detached object, the application must reattach it to a valid Hibernate
session. A detached instance can be associated with a new Hibernate
session when your application calls one of the load(), refresh(), merge(), update(), or save()
methods on the new session with a reference to the detached object.
After the call, the detached object would be a persistent object managed
by the new Hibernate session.
If you are already using hibernate.properties, hibernate.cfg.xml will override any settings in hibernate.properties. Both of these files should be located in the root of your application's classpath.
If you are already using hibernate.properties, hibernate.cfg.xml will override any settings in hibernate.properties. Both of these files should be located in the root of your application's classpath.
No comments:
Post a Comment