Showing posts with label Hibernate3. Show all posts
Showing posts with label Hibernate3. Show all posts

Friday, January 15, 2010

Hibernate3 Tip#7: find(), merge(), getReference()

find() is for retrieving objects from the database - always generates SQL and loads into memory an object initialized according to the active fetch strategy. If you have newly created objects in a persistent context but have not called flush() or committed the transaction, find() will not find them and will return NULL (even if you have called persist()).

merge() is for retrieving a persistent version of a detached or transient object. If not found in the persistent context caches, an SQL statement is issued to retrieve the object from the database, and dirty checking is done to merge the objects. Because it uses non-NULL properties of the detached or transient object to overwrite the retrieved object, you want to be careful about how you use attribute defaults. So watch out when working with transient objects.

getReference() returns a proxy with only the identifier initialized, and does not hit the database. If you are not working directly on an object (such as when it is used only as a reference in queries or other objects), you want to use this strategy. Rule of thumb: if you have entity references in an object, this is likely how you refer to them. Note that the proxy has all other properties set to NULL. To fully initialize the proxies, you'd need to find() or merge().

Wednesday, January 06, 2010

Hibernate3 Tip#6: QL Parameters Are Objects

Consider an entity User that has a many-to-one reference to a Role entity. Each of these entities has an identifier field used to uniquely identify objects. The database schema would be such that the Users table has a column (usually of a numeric data type) with a foreign key constraint to a Role. Supposing you wanted to get all users with a specific role, plain SQL allows querying with a "where user.roleid=?" and providing a numeric type that matches the role's identifier type.

In Hibernate, however, this strategy fails with a "org.hibernate.PropertyAccessViolation: could not get a field value by reflection" exception. Hibernate expects you to provide actual objects as parameters. Thus the QL for the above scenario would require you to find the persistent Role object first, then pass it (or its proxy given by getReference()) as a parameter. Alternatively, you may choose to use native SQL queries. You may consider this a side effect of using an object-oriented persistent layer and query language. It is particularly useful in resolving object identity issues where perhaps more than one property is used to define the object's primary key.

Monday, January 04, 2010

Hibernate3 Tip#5: Initializing Entity Objects

When you create entity classes, it is NOT a good idea to initialize entity references with defaults. Only initialize class attributes that are not references to other entities, and leave references NULLed, except the collections. A new identifier is assigned when a transient object is persisted, overriding whatever default you might have assigned. Having defaults may cause dirty checking to consider them changes that should be propagated to the database when merging or reattaching objects. For newly created objects, the dynamic update feature (if enabled) prevents sql statements that consist of null values (see this tip), and the database uses whatever the default is. (It is better for defaults to be defined in the @Column annotation).

When modifying objects, you only need change what needs to be changed, and if you have dirty checking enabled, only those changes will be propagated to the database. Also note that if you want to use a specific identifier for an object, you should call merge() to obtain a persistent version with that identifier almost immediately after initializing it. Otherwise you'll get a "detached object passed to persist ..." exception sometime when you attempt to commit the transaction. This is one pesky annoyance you discover only with experience.

Friday, January 01, 2010

Hibernate3 Tip#4: One EntityManagerFactory Per Persistence Unit

If you use Hibernate3 for web applications, you must define a persistence unit (database connection and entity metadata from annotated classes or XML mappings). These are essentially the settings that describe how to connect to the database and describe the schema i.e. how tables are laid out and various relationships/constraints between the tables physically.

At runtime, you make persistence unit configuration available to the web application through an entity manager factory. Its main job is to instantiate entity managers for you that provide the persistence context in which you manipulate the database. Although you can create multiple factories based on a single persistence unit, it is not recommended. Instead, you ought to instantiate one statically-scoped entity manager factory and provide a thread-safe accessor that employs the singleton pattern to ensure there's always only one. That accessor initializes a new EMF if none exists and return EntityManager objects.

An example that uses a persistence unit called "puGeldzin":
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public final class DBUtil {
private static EntityManagerFactory emf;

public static synchronized EntityManager entityManager() {
if(emf == null) {
emf = Persistence
.createEntityManagerFactory("puGeldzin");
}
return emf.createEntityManager();
}
}

Wednesday, December 30, 2009

Hibernate3 Tip#3: Methods You Should Override

Just some general best practices that have saved me considerable development time as I've worked with Hibernate3:
  • Always override equals(). Objects that are equal as plain Java objects are often not equal in Hibernate3 because of the identity problem. Hibernate considers the object's persistent state, database identity, and other factors to determine if two objects are equal. By overriding equals(), you set a standard of equality both Hibernate and Java can use.
  • It is a bad idea to override equals() in subclasses. Hibernate does not behave well.
  • Always override hashCode() and provide your own implementation based on the class's attributes that are expected to change rarely. I use the class identifier commonly. Actually, overriding equals() almost always requires overriding hashCode().
  • When you implement equals() and hashCode(), always use property accessors - getXX()/setXX(), POJO style. Hibernate allows the use of proxy classes or references that may no contain actual data if you call their properties directly. Believe me, this is a pain to debug!
  • Always make classes Comparable in case objects of the class end up in collections that require this feature (such as SortedSet or other collections that use a class-dependent Comparator). This gives you the flexibility to switch collection types whenever (e.g. from List to Set) without further base code changes.
  • I also always override toString() because I hate seeing memory addresses as representations of objects. I use it for debug information that I can print out and understand, and that uniquely identifies the object for me.
Pretty much every OOP project I've worked on, these are some of the first tasks that get done. If developers would just get in the habit of these best practices, I wouldn't dread inheriting their projects so much.

Tuesday, December 29, 2009

Hibernate3 Tip#2: Enable Automatic Dirty Checking

In database parlance, when you read a record from a table and update some of its fields in memory, the record is considered dirty. Dirty checking avoids unnecessary database write actions by performing SQL updates only on the modified fields of persistent objects. Hibernate3 JPA can do automatic dirty-checking for you via an annotation to the entity:
@org.hibernate.annotations.Entity(
dynamicInsert=true, dynamicUpdate=true
)
The dynamicInsert property is really only necessary to prevent writing NULL values to database fields. But if the changes involve setting NULL values (bad practice), you should probably turn it off.
I can think of three possible implementations for dirty checking:
  1. Caching a clean copy of the record and maintaining an edit copy of the persistent object. When an SQL update is due, the copies are compared and changes extracted from the edit copy for update. Obviously memory-intensive as 2 copies of a record are maintained at all times.
  2. Keeping track of which fields changed.
  3. Doing a SQL query just before updating and doing the necessary reductions to determine what changed.
I do not know which strategy Hibernate3 uses. Either way, the performance hit is minimal compared to rewriting whole table rows in the database - depending on how many fields each record has. It is recommended when you have more than 50 fields where any given update affects less than 25% of the fields (if you want hard numbers).

Monday, December 28, 2009

Hibernate3 Tip#1: Persistent Lifecycles

For application developers that use the Hibernate3 JPA, it is crucial that you learn the different persistent states an object can be and what methods/functions cause them to transition to what other states. The states are: transient, persistent, detached, and removed. You must also know how a persistent context works, the ACID (atomicity, consistency, isolation, durability) principles for database transactions, and basics of object identity (Java's equality is NOT the same as database record equality).

You can find out more about Hibernate3 at https://www.hibernate.org/.