|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON EJB Avoiding Performance Pitfalls with Entity EJBs
Avoiding Performance Pitfalls with Entity EJBs
By: Rob Woollen
Jan. 7, 2002 12:00 AM
Entity Enterprise JavaBeans (EJBs) are a convenient means to map persistent data to Java components. Container-Managed persistence (CMP) provides rapid development since the EJB container automatically handles loading and storing the persistent data. However, along with their many advantages, Entity EJBs can lead to very slow performance when used incorrectly. This column details a few common pitfalls which trip up EJB programmers and hinder the performance of their Entity beans.
Primary Key Classes It's also possible to provide a custom primary key class. This is necessary for a compound primary key, one that maps to multiple entity bean fields. With a custom primary key class, the developer must implement the hashCode and equals methods. Since the EJB container often uses the primary key class in its internal data structures, this class must implement hashCode and equals correctly and efficiently (see Listing 1).
Implementing hashCode private int hash = -1; The hashCode implementation above computes the Exclusive OR (XOR) of the string's hashCode and the primitive fields. XOR should be preferred to other logical operators such as AND or OR since it gives a better distribution of hash values. This implementation also caches the hashCode value in a member variable to avoid recomputing this value.
Implementing Equals The first line of the optimized equals implementation compares the passed reference against this. While this appears strange at first, it is a common case when the EJB container checks whether a primary key already exists in its data structures. Next, we have replaced the getClass().equals with a much more efficient instance of check. The instance of operator returns true if the passed parameter's class is MyPk or one of its subclasses. Making the MyPk class final allows the create method to safely use the instance of operator since there cannot be a subclass. Finally, the hashCode and member variables are compared. And expressions are short-circuited in Java which means that if the first expression is false, the second is not evaluated. Our equals method takes advantage of this by ordering the and statement with the cheapest comparisons first. The hashCodes are compared first since our implementation caches this value, and it should be very rare for both objects to have the same hashCode but not be equal. Next, the primitive fields are compared, and finally the more expensive java.lang.String.equals is called.
Loading and Storing Entity Beans Entity beans are transactional objects, and it is important to understand the relationship between transactions and persistence. When an entity bean instance is first used in the transaction, its state is refreshed from the database. Any modification to the entity bean state is flushed to the database immediately before the transaction commits (in the beforeCompletion callback, for those of you familiar with the javax.transaction.Synchronization interface). Let's take a look at an example Employee entity bean that has the Required transaction attribute. You can assume that we created the bean in a separate transaction and currently have a reference to an Employee instance. Employee e = ... The key observation from the code snippet above is that the caller has not started a transaction. Since the bean is deployed with the Required transaction attribute, each method runs as an individual transaction and causes loads and stores to the database. In this example, every getXXX method forces a database read while every setXXX method produces a database read and a database update. This simple example has five separate transactions with five database reads (SELECTs) and two updates. Employee e = ... The code example above wraps the calls to the Employee entity bean within a single transaction. In this sample code we use a UserTransaction reference to manually begin and commit the transaction. This could also be done with a session bean with a container-managed transaction that then calls the entity beans within the container transaction. When all of the business methods run within a single transaction, there are only two database accesses. The first getName call produces a SELECT statement to load from the database. The subsequent getXXX and setXXX methods do not cause any database access because they are within the same transaction, and the data is already loaded. When the transaction commits, an UPDATE statement is issued to write the new salary and new level to the database.
Using the Mandatory Transaction Attribute Deploying entity beans with the Mandatory transaction attribute is an easy way to indicate that the operations should be grouped together in a calling transaction.
The CMP Advantage -- Finders Loading Beans Collection employees = This simple example executes a finder (database query) to return employees whose salary is greater than the passed parameter, in this case 30,000. It then iterates through this collection and retrieves the salary from each. In the case where N employees are returned from the finder, this example does N+1 database hits. The finder hits the database and each of the subsequent getSalary call-backs hits the database. By now, you've probably guessed that we'll try to execute the finder and the getSalary methods within a single transaction. Now, how many databases accesses will occur? The answers may surprise you. If Employee is a CMP entity bean and the finder and subsequent getSalary methods occur in the same transaction, there can be one database access. The finder executes a select query which loads the associated primary keys and the other Employee fields. These prefetched beans are entered into the EJB cache and the getSalary method calls read directly from the memory cache. This is the finders-load-bean option in the weblogic-ejb-jar.xml. It is enabled by default, and it allows finders to prefetch additional data into the EJB cache. In this common case, it reduces the database access from N+1 to just 1. What if the Employee is a BMP entity bean? It may surprise you, but there will still be N+1 database hits. The BMP entity bean will implement an ejbFindEmployeesWithSalariesGreaterThan method in the bean class to return a Collection of primary keys to the container, but it cannot prefetch into the cache. Each getSalary call then produces an ejbLoad call and another database hit. Finders prefetching beans is a big performance advantage of CMP, and in general CMP (especially EJB 2.0's CMP) entity beans outperform BMP entity beans.
Conclusion BEA WEBLOGIC LATEST STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK BREAKING NEWS FROM THE WIRES
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||