Connection Strategies in EntityBeans

In this article, I examine the different ways to obtain database connections when developing Enterprise JavaBeans (EJBs), primarily focusing on EntityBeans with Bean Managed Persistence (BMP). I also discuss the life cycle (i.e., State Diagram) of EntityBeans. Various strategies for obtaining and releasing connections at various points in the EntityBean's life cycle are explored. Finally, I look at the advantages, as well as the disadvantages of various strategies.

Getting Connected
The Enterprise JavaBean Specification discusses two major types of EJBs: "SessionBeans" and "EntityBeans." There are two types of EntityBeans:

  • EntityBeans with Container Managed Persistence (CMP)
  • EntityBeans with BMP

In EntityBeans with CMP, the EJB container is responsible for providing database functionality, such as create, read, update, and delete to the beans. In EntityBeans with BMP, you typically hand-code database function-ality using the Java DataBase Connectivity (JDBC) Application Programming Interface (API). When writing programs with the JDBC API, you need to obtain a java.sql.Connection to the database. You can typically obtain a connection object by using the getConnection () method of the java.sql.DriverManager, and can execute Structured Query Language (SQL) using java.sql.Statement and java.sql.PreparedStatement. You can also invoke stored procedures using java.sql.CallableStatement. Once done using the connection, you can close the connection to the database (see Listing 1). However, obtaining and closing connections is fairly expensive. Plus, connections are a scarce resource. Connections can have a huge impact as far as performance and scalability of the application are concerned.

Connection Pooling
Because creating and closing connections is expensive, you can create connection pools. In a connection pool, several database connections are created before they are needed and stored in a collection as a pool. When you need a connection, you do not create the connection, but rather obtain a connection from the pool. You can execute the statements on the obtained connection. When you are done using the connection, instead of closing the connection, you return the connection back to the pool. Thus, another part of the program is free to use the same connection. For example:


DataBase aDB = DataBase.getInstance();
Connection c = aDB.getConnection();
try {
    ...
} catch (SQLException e) {
    e.printStackTrace();
}
aDB.freeConnection(c);
Before the J2EE spec, developers had the following options for the connection pooling software, such as:
  • They could write their own connection pooling software.
  • They could obtain a third-party connection pooling software.
  • They could use proprietary connection pooling software available with some application servers.

Standard Connection Pooling. The J2EE specification specifies a standard way of connection pooling. J2EE-compliant application server vendors provide an implementation of Java extension javax.sql.DataSource interface. The implementation of DataSource provides the connection pooling. When obtaining a DataSource connection, you are actually getting a database connection from the connection pool. When closing the DataSource connection, you are actually returning the database connection back to the connection pool. Here is an example of getting and closing a Connection:


Connection c = aDS.getConnection();
try {
    aReturn = doMethod (c);
} finally {
    c.close();
}
Obtaining DataSource Implementation
The javax.sql.DataSource is just an interface. How do you obtain an instance of javax.sql.DataSource? It is a two-step process: configuration and usage. Using configuration property files or GUI configuration tools, configure the application server with the DataSource. The configuration involves setting parameters such as the driver, URL, username, password, minimum connections, and maximum connections. When the application server starts up, it will create the DataSource instance, and make it available via the Java Naming and Directory Interface (JNDI). During runtime, you obtain an instance of javax.sql.DataSource by using the JNDI API. Here is an example of Lookup:


InitialContext aIC = new InitialContext ();
Object o = aIC.lookup(DATA_SOURCE_NAME);
DataSource aDS = (DataSource) PortableRemoteObject.narrow (
    o,
    DataSource.class
);
Strategies for Obtaining and Closing DataSource Connections
Let's consider strategies for obtaining and closing DataSource connections. Each strategy will have advantages and drawbacks. Understanding these strategies will help you make informed decisions about when to get and close DataSource Connections. The strategies will have a profound impact on your design and coding of EntityBeans with BMP. Consider three strategies for obtaining and closing DataSource Connections:
  • Quick Catch-and-Release Strategy
  • Live Pool Strategy
  • Servicing Instance Strategy

Let's explore each of these strategies in detail.

Quick Catch-and-Release Strategy. In this strategy, obtain the java.sql.Connection instance from the javax.sql.DataSource at the start of the method. Hence, you are obtaining a connection from the pool. Just before the end of the method, close the java.sql.Connection instance. Hence, you are releasing the connection back to the pool. You want to execute all the JDBC API calls of the method in try-catch, try-finally, or try-catch-finally blocks ensuring that you will eventually return the connection back to the pool before you return from the method. Typically, the methods are coded in this manner:

  • ejbFind... () methods
  • ejbCreate () methods
  • ejbRemove () method
  • ejbLoad () method
  • ejbStore () method
  • Business methods

Taking advantage of the Template Method Pattern,1 every method call is templated to obtain a connection as you enter the method and release the connection just before you exit the method.

Listing 2 shows how to use the Template Method. Specifically, Listing 3 illustrates the ejbLoad() method. However, all the other methods are structured similarly.

Live Pool Strategy. In the Live Pool Strategy, you can take advantage of the life cycle of an EntityBean. By taking advantage of the life cycle, you can carefully get, as well as close, DataSource connections. I will now discuss the Unified Modeling Language (UML) State Diagram of the life cycle of an EntityBean.2

EntityBean State Diagram. The DataSource connection object needs to be in the following methods of an EntityBean:

  • ejbFind... () methods
  • ejbCreate () methods
  • ejbRemove () method
  • ejbLoad () method
  • ejbStore () method
  • Business methods

By carefully looking at the State Diagram (see Figure 1), note that you need a DataSource connection instance in the "pooled" as well as "ready" states. Hence, you should obtain the connection while transitioning from the "does NOT exist" state to the "pooled" state. You can release the connection while transitioning from the "pooled" state to the "does NOT exist" state. Thus, you should get the connection from the DataSource instance in the setEntityContext() method and cache it as a member instance. Because you have cached the connection as a member instance, it is available to all the methods in the "pooled" as well as "ready" states. You should close the connection in the unsetEntityContext() method (see Listing 4).

Figure 1
Figure 1. EntityBean State Diagram.

Servicing Instance Strategy. As noted earlier in the state diagram of an EntityBean, you need a DataSource connection instance in the "pooled" as well as "ready" states. Unlike the Live Pool Strategy, you will treat the two states differently in this strategy. The behaviors that can be invoked in the "pooled" state are ejbFind...() methods. For each ejbFind...() method, you will follow the exact same strategy used in the Quick Catch-and-Release Strategy. You will obtain the connection at the beginning of the ejbFind...() method and release the connection just before you exit the ejbFind...() method. Thus, the methods are still in need of a connection object:

  • ejbCreate () methods
  • ejbRemove () method
  • ejbLoad () method
  • ejbStore () method
  • Business methods

You should obtain the connection object at the beginning of the ejbCreate() methods and cache the connection as a member instance. The connection can be released just before you exit the ejbRemove() method (see Listing 5).

Because you have cached the member instance, the connection will be available to the ejbLoad(), ejbStore(), and business methods of the "ready" state (see Listing 6).

However, there is another state transition path due to activation and passivation to and from the "ready" state. Hence, you should also obtain the connection in ejbActivate() method, as well as release the connection in the ejbPassivate() method (see Listing 7).

Advantages and Drawbacks Discussion
I will now examine and compare the advantages, as well as the drawbacks, of each of the strategies highlighted in this article. I also evaluate from various perspectives, such as amount of code and resource usage.

Amount of Code. Typically, the less code you write, the better it is eventually for the project. Not only will you have less code to write, but you also have less code to unit test, debug, and maintain. Thus, less code directly translates into less money, time, and resources expended. Because you have to code for getting and releasing the connection in each method in the Quick Catch-and-Release Strategy, the Quick Catch-and-Release Strategy would have the greatest amount of code. On the other hand, in the Live Pool Strategy you obtain the connection in the setEntityContext () method and release the connection in the unsetEntityContext () method. Hence, the Live Pool Strategy has the least amount of code. However, as demonstrated with usage of the Template Method Pattern (see Listing 2), the amount of code in the Quick Catch-and-Release strategy can be greatly reduced. Hence, instead of having the code obtain and release the connection in each method, you have it only in one place, i.e., the invokeMethod() method of the ConnectionTemplate class.

Resource Usage. For the greatest efficiency, you would want to hold on to critical resources, i.e., database connections for the least amount of time. By quickly obtaining and releasing the resources, the limited number of resources can support a large number of clients. Thus, efficient resource management has a direct impact on the scalability and performance of your application. On the other hand, there is overhead associated with obtaining and releasing resources. For example, if the same client will use the same resource a hundred times, then obtaining and releasing can be expensive and inefficient. A better approach (in this case) would be to obtain the resource, use the resource a hundred times, and then release the resource. Hence, how long you hold on to resources like connections is a fine balancing act.

The Quick Catch-and-Release Strategy holds on to connections for the least amount of time, whereas the Live Pool Strategy holds on to connections for the greatest amount of time. In the Live Pool Strategy, if the application server is maintaining a pool of a hundred (different) EntityBeans, then you have reserved a hundred connections from the connection pool. Thus, you have reserved the connections even though you may not use the connections.

The Servicing Instance Strategy attempts to strike a balance. Is half a bottle of wine "half-empty" or "half-full"? From an optimistic perspective, the Servicing Instance Strategy is "half-full," whereas from a pessimistic perspective it is "half-empty." Because the Servicing Instance Strategy only holds on to the connection when in the "ready" state, it is holding on to the connection when it is likely to need it the most.

Choices Lead To Decisions
So, should you use Quick Catch-and-Release Strategy, Live Pool Strategy, or Servicing Instance Strategy? Should you decide on one of the strategies for all the EntityBeans with BMP in your entire application? Or, should you make the decision on a bean-per-bean basis? If you decide on a single strategy for the entire application, then the safest bet is the Quick Catch-and-Release Strategy. The performance penalty of obtaining and releasing connections too frequently is quite small in comparison to potential scalability problems or issues raised because EntityBeans are holding on to the connections for too long. If you decide to make your decision on a bean-per-bean basis, it is recommended that:

  • If the number of instances is going to be small with a large number of methods utilizing connections being invoked, then use the Live Pool Strategy. Because you have a small number of (even pooled) instances, you are not holding on to too many resources. As you invoke a large number of methods, you do not have to pay the cost of obtaining and releasing resources.
  • If the number of instances is going to be large with a small number of methods utilizing connections being invoked, then use the Quick Catch-and-Release Strategy. Because you have a large number of instances, you do not want to hold on to too many resources. As you invoke a small number of methods on these instances, the cost of obtaining and releasing resources is relatively low.
  • Otherwise, you should carefully consider the Servicing Instance Strategy.

Proof is in The Pudding
Now I construct and test a couple of scenarios to illustrate the strengths and weaknesses of the discussed strategies. I monitor time-elapsed, as well as resources consumed.

In the first test, I constructed 100 EntityBeans with BMP. The test of creating the EntityBeans with Quick Catch-and-Release Strategy performed admirably. However, the test of creating the EntityBeans with Live Pool Strategy and Servicing Instance Strategy threw errors and exceptions. In the Live Pool Strategy and the Servicing Instance Strategy, because every EntityBean instance will hold on to a connection, when creating 100 instances try to have 100 connections to the database. As the default number of connections allowed to the test database was approximately 50, I was only able to create 50 EntityBeans. Thus, while creating the rest of the EntityBeans I encountered errors and exceptions. This supports my conclusion that when you have a large number of instances, Quick Catch-and-Release Strategy is well suited, whereas Live Pool Strategy and Servicing Instance Strategy run into major problems.

In the next test, I looked up an EntityBean and invoked the same behavior 500 times. In the Quick Catch-and-Release Strategy, I obtained and released a connection in each of the methods, whereas in the Live Pool Strategy and Servicing Instance Strategy I cached the connection as a member variable, reusing the same connection in each of the methods. In this test, the Live Pool Strategy and Servicing Instance Strategy performed approximately twice as fast as the Quick Catch-and-Release Strategy, demonstrating the cost of obtaining and releasing connections.

From these two tests, you can conclude that Quick Catch-and-Release Strategy is the best and safest strategy. Under most circumstances, you should choose the Quick Catch-and-Release strategy by default. The disadvantages of a minor performance penalty in the Quick Catch-and-Release Strategy are far outweighed by the scalability concerns of holding on to connections for too long in the Live Pool Strategy and Servicing Instance Strategy.

Note the two tests were done using Java 2 Enterprise Edition Reference Implementation (J2EE-RI). The mile-age may vary depending upon the application server implementation.

EntityBeans with Container Managed Persistence (CMP)
What strategy is used by EntityBeans with CMP? It could be Quick Catch-and-Release Strategy, Live Pool Strategy, Servicing Instance Strategy, or a custom strategy. It is possible for sophisticated CMP tools to provide such options to the entire application at deployment time. Taken a step further, it might be possible for such sophisticated CMP tools to provide such strategy configuration on a per-EntityBean basis. This illustrates an advantage of EntityBeans with CMP with respect to BMP, where strategies like this do not need to be hard-coded in the EntityBean by the programmer. These strategies can be configured at deployment time. If you decide to change the strategy in EntityBean with BMP, then you will have to recode, test, and debug the code. On the other hand, if you decide to change the strategy in an EntityBean with CMP, then it might be as simple as redeployment.

Conclusion
In this article, I looked at database connections and how javax.sql.DataSource interface provides connection pooling. I have studied different ways in which the connections can be obtained in the EntityBeans with BMP, as well as CMP. Because you have to undertake the persistence coding in BMP, I evaluated three different strategies for obtaining and releasing connections in code: Quick Catch-and-Release Strategy, Live Pool Strategy, and Servicing Instance Strategy. I evaluated the strategies from various perspectives, such as amount of code, scalability, and performance. I also made various recommendations for selecting an appropriate strategy based on different situations.

Finally, I looked at some performance benchmarks and concluded that the Quick Catch-and-Release Strategy is the best and safest bet.

References

  1. Gamma, E., et al. Design Patterns: Elements of Reusable Object-Oriented Software. Addison–Wesley, 1995.
  2. Matena, et al. Enterprise JavaBeans Specification Version 1.1. Sun Microsystems Inc., 1999, http://java.sun.com/products/ejb/.

URLs
Enterprise JavaBean Specification
www.java.sun.com/products/ejb/docs.html

JDBC Data Access API
www.java.sun.com/products/jdbc/

Java 2 SDK, Enterprise Edition
www.java.sun.com/j2ee/download.html#dsk