Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Designing Entity Beans for Improved Performance

 
 

Articles Index




If you've done any work with Enterprise JavaBeans components, and particularly if you have used entity beans to model persistent data in a database, then you are most likely aware of the network performance overhead that can come with entity bean usage.

This article will look at some of the design decisions an entity bean developer must make, and the tradeoffs associated with these decisions. Ultimately, the right method for you depends on the way your business uses entity beans.

Strategies for Optimizing Entity Bean Data Access

As review, remember that an entity bean exposes its methods through its remote interface, and these methods often access the underlying stored data, either getting values from the stored data or setting new values to the data store. Every entity bean client accesses the entity bean through the methods exposed in the entity bean's remote interface.

It's important to realize that every invocation of an entity bean method is potentially a remote call that requires using network resources. A client of an entity bean needs to be aware of this potential performance hit when using an entity bean. More importantly, entity bean developers should consider this when designing and developing an entity bean. You must look at how the bean's clients might use the methods in the bean's remote interface, and then design the bean to be used efficiently and effectively.

You can use one of three approaches when designing the entity bean's remote interface, particularly regarding the data access methods. These approaches are as follows:

  • Use separate methods to access each individual attribute. (This approach is generally not recommended unless required by the application.)
  • Use one value object to access all attributes
  • Use separate value objects to access groups of attributes

Each approach has its pluses and minuses. To illustrate the approaches and their trade-offs, consider an entity bean called CustomerAccountBean that models records in a customer account table stored in a relational database. The customer account record includes fields to identify the particular customer record (name and id), address fields (street, city, state, zip code, country), and order and credit-related fields (last_order_id, credit_limit, and payment_terms). For example, you might have the following SQL CREATE statement for this record.

CREATE TABLE CustomerAccount ( 
   customer_name VARCHAR(32),
   customer_id INT,
   customer_street VARCHAR(32),
   customer_city VARCHAR(32),
   customer_state VARCHAR(32),
   customer_zip INT,
   customer_country VARCHAR(32).
   last_order_id INT,
   credit_limit DECIMAL(8.2),
   payment_terms VARCHAR(32),
 )

Your next step is to carefully consider how clients may use this entity bean, and then to design the bean's remote interface accordingly.

Using Separate Methods to Access Individual Attributes

Let's assume that you think that most CustomerAccount clients will typically want access to only a few attributes of the bean (or fields in the database record), and that they will usually retrieve or set only one or two attributes per interaction. That is, in normal, day-to-day usage, a given client may only want to see the customer's credit limit and perhaps payment terms. Or, the client may want to see the customer's zip code, country, or just the city. Only in rare situations would a client want access to more than a few fields of the customer account record at a time, such as all the address fields, or even want to access the entire customer account record.

In this situation, you can design the entity bean to promote individual access to each persistent attribute. You define the bean's remote interface so that there is a separate method to access each individual attribute. Typically, you define two accessor methods--a get and a set method--for each attribute.

For example, you might define the CustomerAccount remote interface as follows:

public interface CustomerAccount extends EJBObject {
  // identification attributes
  String getCustomerName() throws RemoteException;
  void setCustomerName(String name) throws RemoteException;
  int getCustomerID() throws RemoteException;
  void setCustomerID(int id) throws RemoteException;
  
  // address attributes
  String getCustomerStreet() throws RemoteException;
  void setCustomerStreet(String street) throws RemoteException;
  String getCustomerCity() throws RemoteException;
  void setCustomerCity(String city) throws RemoteException;
  String getCustomerState() throws RemoteException;
  void setCustomerState(String state) throws RemoteException;
  int getCustomerZip() throws RemoteException;
  void setCustomerZip(int zipcode) throws RemoteException;
  String getCustomerCountry() throws RemoteException;
  void setCustomerCountry(String country) throws RemoteException;
  
  // credit/order history attributes
  int getLastOrder() throws RemoteException;
  void setLastOrder(int orderid) throws RemoteException;
  double getCreditLimit() throws RemoteException;
  void setCreditLimit(double limit) throws RemoteException;
  String getPaymentTerms() throws RemoteException;
  void setPaymentTerms(String terms) throws RemoteException;
}

Some of the Benefits

Designing an entity bean's remote interface to use individual accessor methods is useful when the entity bean has many attributes (admittedly, this example record could have many more attributes) and most clients require access to only a few attributes at a time. Also, because of the way these clients use this particular system, they do not usually access the same set of attributes every session. Instead, depending on the business at hand, the client will want access to any one of the record's fields. In this situation, it is best if the client can retrieve only the attributes or fields in which he is interested, and only must retrieve the one or two attributes of interest, rather than all the customer's attributes.

Only use this strategy when you are sure that the entity bean's clients are all also enterprise beans themselves. In addition, it is important that the clients and the bean all be part of the same application and reside on the same EJB container.

Figure # 1. illustrates the potential network overhead and transaction overhead that might occur when using this approach if the clients do not reside on the same container as the entity bean.

ejb-article-1.gif Figure 1 Using Individual Accessor Methods

Some of the Drawbacks

This approach has some significant drawbacks. For one, because it is difficult to limit a bean's clients to the local EJB container, there is the potential network overhead. Remember that entity beans are designed to be remote objects. As such, often an entity bean's remote interface is accessed by clients remotely situated from the bean, such as from within another EJB container or another server or platform. Unless you are sure that the clients reside within the same container, you must take into account the likelihood that each client invocation of an accessor method will be a remote method invocation, resulting in a network call and reducing application performance.

Notice, too, that each method invocation involves a separate transaction. By design, the EJB container handles transaction demarcation in this fashion. It's possible for the client to get around this if several attributes need to be updated within one transaction, but then the client must use client-side transaction demarcation. That is, the client developer must write transaction code, which makes more work for the client developer and negates some of the value of the EJB architecture.

In addition, if the client developer writes code to combine both method invocations within one transaction, then the transaction is open across several network calls. This could lead to a further performance reduction because there is an increase in lock contention on the underlying data, plus there would be the overhead of additional network trips for the transaction demarcation itself.

Lastly, using individual accessor methods may make it difficult for you to validate business logic in the entity bean's set methods. This occurs when the validation requires more than one attribute value. For example, suppose you are writing your entity bean to enforce some business logic that says that the payment terms can be net 10 only if the credit limit is greater than zero; otherwise the terms must be net 30 or net 45. Inside the setPaymentTerms method you have code to check the credit limit value whenever a client attempts to change the payment terms value.

Suppose a client later performs the following sequence of method invocations:


...
customeraccount.setPaymentTerms(net30);
customeraccount.setCreditLimit(0);
...
// client does some other processing
...
customeraccount.setPaymentTerms(net10);
customeraccount.setCreditLimit(2500.00);
...

When the client makes the second call to setPaymentTerms, to set its value to net10, the entity bean checks the credit limit and sees that this change to the payment terms violates the business logic. The entity bean has no way of knowing that the entity object's state is temporarily inconsistent, and that the client's next invocation will change the credit limit from zero to 2500.00. As a result, it is virtually impossible for the entity bean to properly check the business logic. Instead, the client has to know the business logic to invoke the individual methods in the proper order. This defeats much of the purpose for using entity beans.

Using a Value Object for All Attributes

Rather than accessing each entity attribute individually, you can set up your entity bean's remote interface to access all attributes in one call. Essentially, a client makes one request to either retrieve or set all the customer account values. All persistent attributes are accessed via one remote call and within one transaction, thus keeping to a minimum the network and transaction overhead. (On the negative side, there might be a large amount of data transmitted over the network with each such access, especially if the entity object is large.) Consider using this approach when the bean's applications generally require access to most or all of the attributes at the same time. Figure # 2. illustrates this approach.

ejb-article-2.gif Figure 2 Accessing All Attributes with a Value Object

Considering the CustomerAccount bean example, this is a good approach to use if the bean's clients always want to see the entire customer address, and very often want to see the payment terms and credit limit, every time they worked with a customer account.

How it Works

To access all persistent attributes in one method invocation, your entity bean uses a single value object. A value object is nothing more than a Java class with public get and set methods. You remove the individual get and set methods from the remote interface (and from the bean's implementation class) and place equivalent methods in the value object class. Then, you add methods to the bean's remote interface, one to retrieve the entire value object and the other to set new values. Of course, you include the implementation for these new methods in the bean's implementation class. You might also change the arguments for the create method in the bean's home interface to use the value object, in which case you would also change the corresponding ejbCreate method implementation.

Extending the CustomerAccount Example

For the CustomerAccount bean example, you might set up a Java class, called CustAcctVO, to be a value object. This CustAcctVO class is used to pass all the persistent attributes of the CustomerAccountBean between the client and the bean. The class declares the customer account attributes as private fields. It includes get and set methods, replacing the individual Extending get and set methods from the entity bean's remote interface.

Thus, you might have the following: (Note that for the sake of simplicity, this code snippet and the following snippets are not intended to show every line of code. Rather, they highlight how a value object is used.)

public class CustAcctVO {
   private String name;
   private int id;
   private String street;
   private String city;
   private String state;
   private int zip;
   private String country;
   private int order;
   private double creditlimit;
   private String paymentterms;
   
   public String getName() { return name; }
   public void setName(String s) { name = s; }
   public int getID() { return id; }
   public void setID(int i) { id = i; };
   public String getStreet() { return street; };
   public void setStreet(String s) { street = s; };
   public String getCity() { return city; }
   public void setCity(String s) { city = s;} 
   ...
}

You also modify the entity bean and its remote interface to use the CustAcctVO value object instead of the individual accessor methods. You replace the individual accessor methods in the CustomerAccount remote interface with two new methods, getCustAcct and updateCustAcct. The remote interface might look as follows:

public interface CustomerAccount extends EJBObject {
   CustAcctVO getCustAcct()
    throws RemoteException;
   void updateCustAcct(CustAcctVO custacct) 
    throws RemoteException;
   ...
}

Since the create method also uses the value object, you might modify the bean's home interface as follows:

public interface CustomerAccountHome extends EJBHome {
   CustomerAccount create (CustAcctVO cust)
       throws RemoteException, CreateException;
    ...
 }

The CustomerAccountBean class includes the implementation of the two new get and set methods, plus the modified ejbCreate method (modified to use the value object parameter). (Note that this code snippet does not show the complete bean implementation, but just highlights the value object usage.)

public class CustomerAccountBean implements EntityBean {
...
   // retrieve customer account values and return in 1 value object
   public CustAcctVO getCustAcct() {
	CustAcctVO cust = new CustAcctVO();
	// retrieve customer account values into value object
	cust.setName(name);
        cust.setID(id);
	cust.setStreet(street);
	cust.setCity(city);
	...
	
        // return value object with all values set
	return cust;
   }
   ...
   // update customer account from value object 
   public void updateCustAcct(CustAcctVO cust) {
	name = cust.getName();
	id = cust.getID();
	street = cust.getStreet();
	city = cust.getCity();
	...
	
        updatePaymentTerms(cust.getPaymentTerms())
	...
   }
   
   void updatePaymentTerms(paymentterms) {

	// apply business logic for setting payment terms
	...
   }
   
   public Integer ejbCreate(CustAcctVO cust)
	name = cust.getName();
	id = cust.getID();
	street = 
        cust.getStreet();
	city = cust.getCity();
	...
   }
}

Using Multiple Value Objects

It's also possible for you to design your entity bean to use multiple value objects. This approach gives you more fine-grained control for accessing attributes and still lets you retain the performance benefits that value objects provide. It works best for entity beans with many individual attributes, but where the bean's clients typically need access to only a small number of the attributes.

How it Works

In this approach, you group into subsets those individual accessor methods that clients would logically want to access together. You can have individual accessor methods in more than one subset. Then you set up separate value objects for each subset. That is, you define each value object to contain and handle the attributes required by a particular client's use of the entity bean. In the entity bean, you define methods to access each value object subset. Along with multiple value objects, the entity bean might also retain some individual accessor methods if it has clients who require access to single attributes only.

This approach has the advantage of modelling the client's business use of the entity bean, often referred to as use case analysis. The business methods you define for accessing the different value object subsets tend to reflect a client's use of that subset. As such, it is easier for the client programmer to learn to use the bean. This approach also optimizes the network traffic. Not only does the client get all data he needs in a single call, but the amount of data transferred is kept to just what the client needs. Figure # 3. shows how this might look:

ejb-article-3.gif

Figure 3 Accessing Subsets of Attributes with Multiple Value Objects

Extending the CustomerAccount Example

Let's suppose that you realize that CustomerAccount clients typically use this entity bean to access either the address attributes or the credit-related attributes, but rarely both sets of attributes together. In addition, clients frequently retrieve either the customer name or identifier for other business operations. As a result, you design the CustomerAccount bean to reflect its business use.

You set up the bean to use two value objects. The bean uses CustAddrVO to retrieve and update the customer name and identifier and address attributes, and it uses CustCreditVO to retrieve and update the customer name and identifier along with the credit and payment terms attributes. You also include individual accessor methods for the customer name and identifier, so clients can use these attributes without being encumbered with address or credit data.

Once you've completed the above business use analysis, you might design the CustomerAccount remote interface as follows:

public interface CustomerAccount extends EJBObject { 
   // Access all address attributes
   CustAddrVO getCustAddress() 
           throws RemoteException;
   void updateCustAddress(CustAddrVO newAddress) 
	   throws RemoteException;
	   
   // Access all credit attributes
   CustCreditVO getCredit() 
	    throws RemoteException;
   void updateCredit(CustCreditVO newCredit) 
	    throws RemoteException;
	    
   // individually access name, id
   String getCustomerName() 
	    throws RemoteException;
   void setCustomerName(String name) 
	    throws RemoteException;
   int getCustomerID() 
	    throws RemoteException;
   void setCustomerID(int id) 
	    throws RemoteException;
}

You write the code for the two value objects in a similar manner as for a single value object. Similar changes must be made to the entity bean implementation, and, if necessary, to the home interface create method.

Conclusion

This article demonstrates the importance of keeping performance considerations in mind when designing entity bean data access methods. It is important that bean developers design entity beans according to the data that they model and their clients' use of this data. Entity beans principally model data in an underlying data store, and they are intended to be used to access (retrieve and update) this data. Because of the nature of the EJB architecture, there is a certain amount of network overhead with such data access. You must do a careful analysis of the data modeled by the entity bean.

Also, you must understand how clients of an entity bean will use the data, and particularly what chunks of data they need in combination. Once you understand the data and the use of that data, you can design the entity bean's methods to efficiently move data between the data store and the client and to minimize both network and transactional overhead.

For More Information

Coffecup Logo

About the Author

Beth Stearns is the principal partner of ComputerEase Publishing, a computer consulting firm she founded in 1982. Her client list includes Sun Microsystems, Inc., Silicon Graphics, Inc., Oracle Corporation, and Xerox Corporation. Among her publications are the "Java Native Interface" chapter in "The Java Tutorial Continued" book in the Addison Wesley Java series, "The EJB Programming Guide" for Inprise Corporation, and "Understanding EDT", a guide to Digital Equipment Corporation's text editor. Most recently, she is co-author with Vlada Matena of the forthcoming Addison Wesley Java series book, "Applying Enterprise JavaBeans: Component-Based Development for the J2EE Platform".
 

Have a question about programming? Use Java Online Support.