|
Entity beans provide a clear model to represent persistent business objects in applications and their design. In object models, simple JavaTM objects are normally represented in a straightforward way, but do not include the transactional persistence management functionality usually required for business objects. Entity beans not only allow the same type of modelling and thinking about business objects in an object model, but they also encapsulate persistence mechanisms while hiding all complexity behind the bean and container services. This allows applications to manipulate them as Java object references. By hiding the persistent form and persistence mechanism from any calling code, entity beans allow for creative persistence optimizations by the container, while keeping the data store open and flexible, only to be determined at deployment time. Based on Enterprise JavaBeansTM (EJBTM) development projects, which make extensive use of object-oriented methodologies and result in heavy use of entity beans, Sun engineers have learned about using entity beans in the real world. This article elaborates on such development experience to:
Use Container-Managed Persistence When You Can
Container-managed persistence (CMP) not only eases the job by requiring
a lot less coding, but also enables many optimization possibilities
within the container and the container-generated database access code. The
container has access to the in-memory buffer of the bean which
allow it to monitor for any change in the buffer. Storing the buffer to
the database before committing a transaction can be avoided if
the buffer has not changed. This avoids unnecessary expensive database
calls.
Another instance of this optimization is calling
CMP allows for optimizing these two database accesses into a single database access whenever it makes sense to do so, allowing retrieval of both the key and the record data in one database call. Write Code that Supports Both Bean- and Container-Managed Persistence In many cases the EJB's author does not have control over how the
EJBs are deployed and whether the container used for deployment will
support CMP. Also, the deployer may choose to use bean-managed
persistence (BMP) in the target container. You must
find a way to implement the beans to allow BMP deployment without
disrupting the support for the potentially more optimized CMP mechanism.
One easy way to achieve this is to separate pure business
logic from the persistence mechanism. Implement the business logic
in your CMP class, which can be deployed alone if CMP is chosen. Then
implement the persistence code into the BMP class, which
inherits from the CMP class. This preserves all the business logic of
the CMP superclass and adds database access code in the BMP subclass, as
shown in figure 1.
![]() Figure 1: Separation between CMP and BMP
![]() Figure 2: Multiple inheritance not supported in Java To solve these problems, you can change the current model for the BMP class to delegate all the persistence code to a helper class and leave a skeleton in the BMP class. This kind of helper class is called a Data Access Object (DAO). You can provide multiple DAO classes by subclassing a DAO interface, which then allows the correct DAO subclasses to be instantiated. This is shown in Figure 3. There are many ways to choose and instantiate the correct DAO subclass, for example, by reading environment entries or by figuring out the DB type and choosing the most appropriate subclass.
![]() Figure 3: Delegation and allowing for alternate DAO implementations.(Click to enlarge) Using this model, both the CMP implementation and the DAOs that contain the implementations can be easily extended; everything but the BMP classes can be extended. Because these BMP classes contain a skeleton of delegation code that looks almost the same for every entity bean, and the instantiation code to choose the right DAO object, you can easily copy from one bean to another with very little modification. Also, you could eventually automatically generated them with a tool. While it is possible to extend an entity bean to reuse the logic provided by another entity bean, it is not possible in the EJB 1.1 specification to allow extension of entity types that extend the home interface. Finders and create calls are theoretically always remote calls. The generated stubs will never represent a subtype, although logically you might want to (for instance, to use them as a factory method). This prevents the use of many useful design patterns in EJB implementations that follow the EJB 1.1 specification.
Minimize Database Access in ejbStores When using CMP, the bean has absolutely no control over
Whenever the bean is deployed using BMP, it is very useful to
maintain a
There are caveats with this technique. Since the
Philosophically, the writer of an EJB should not have to deal with
system-level issues like buffer handling. Unfortunately EJB 1.1
using BMP does not provide any alternative for such an optimization, so
the bean author still has to set this Always Cache References Obtained from lookups and find Calls Reference caching is useful for both entity beans and session beans. JNDI lookups of EJB resources, such as DataSources, bean references, or even environment entries can be fairly costly, and it is simple to avoid redundant lookups. To solve this problem, always:
The
Calls to the finders of other entity beans are also heavyweight
calls. While these calls may or may not fit into bean initialization
callbacks like Always Prepare Your SQL Statements This optimization is useful for all code using SQL to access relational databases. And since most of the current EJB implementations use relational databases, this rule is also very useful for EJB development where the author of the bean has to write database access code. For each SQL statement processed by the database, the database has to spend time compiling the statement before executing it. Good relational databases, however, can cache the statement and its compiled form and match new statements against the cache to retrieve its compiled form. However, in order to use this optimization, the new statements must exactly match the old statements.
When you use the statement, data is then passed to it and the statement gets executed. Normally, the statement is compiled at prepare time, but subsequent prepares already match the cache and are not recompiled. This technique promotes very high statement cache hit ratios (close to 100%) that minimizes the amount of statement compilations. For small database accesses, this can decrease the statement execution time by up to 90%. Close all Statements Properly
When dealing with database access code in BMP implementations, never leave the
statements open after database access calls. Each
open statement corresponds to an open cursor in the database.
(While the garbage collector eventually claims the open statement and closes
it at garbage collection (GC) time, you do not have control over the time
the GC kicks in. Do not enforcing GC by calling the
Also, be sure to catch all exceptions properly when closing the statements. An exception in closing one statement must not cause other statements to be ignored and left open. Avoid Deadlocks
Application code does not have direct control when
If multiple entity beans or multiple entities are involved in a transaction,
the sequence in which Looking on the bright side, ideally, container-controlled access and locking in EJBs should allow the container to account for deadlocks and free the developers/deployers from such worries. Unfortunately, few if any of the currently available commercial application servers do a good job in ordering database locks, leaving deadlock problems in complex entity bean deployments to the deployer.
The applicable rule, at least at the time of this writing, is to assume the
container will invoke the database access calls of the beans in the same
sequence a transactional method of the bean is first accessed as part of
the transaction. To make this clearer, consider the following example:
Assume entity bean As application servers become more intelligent and know how to order database accesses, authors and deployers can be less careful on the bean access sequence. However, code that strictly deals with invocation order as in the example provided will continue to run on future servers as well as today's.
The Going ForwardThese rules, when utilized with entity-intensive developments and deployments, can significantly help increase the performance and flexibility of the beans, allowing them to adapt to different persistent storage types while minimizing their load on the container and the underlying system. This gives the deployer the flexibility to choose the most suitable deployment infrastructure and all allowing the beans to make efficient use of the infrastructure provided. In other words -- write once run anywhere, efficiently.
For More Information
About the AuthorAkara Sucharitakul was one of the developers of the ECperf benchmark and other J2EE server based applications inside Sun. He has more than 5 years of experience with Java technology and has been working on J2EE technology since its early days. Have a question about programming? Use Java Online Support. | ||||||||
|
| ||||||||||||