• 沒有找到結果。

Object Persistence

在文檔中 WILEY advantage (頁 58-63)

Business objects implemented as regular Java classes do not have any built-in frame-work to manage object persistence. An application frameframe-work that automates much of the JDBC processing and ties in to the business object model can make this less of an issue. While the construction of basic JDBC frameworks can be done fairly quickly, the creation of highly optimized JDBC frameworks is not a trivial task. Persistence frame-works that can be used by either BMP Entity Beans or Java business objects are dis-cussed later in this chapter.

Entity Bean Persistence

One of the primary component services provided with Entity Beans is Container-Managed Persistence (CMP). In this option, the container uses a deployment configu-ration to map a set of beans to their respective database tables in order to automatically manage the selects, inserts, updates, and deletes to the database. The EJB 2.0 persis-tence model, unlike EJB 1.1, uses an abstract persispersis-tence schema.

The abstract persistence schema used by EJB 2.0 refers to the fact that a bean developer implements only abstract getter and setter methods for both CMP and CMR (container-managed relationships) fields. The container, upon deploy-ment, generates a subclass that implements these abstract methods for all of the properties of the bean. This is vastly different from the EJB 1.1 model, which required public member variables. The EJB 2.0 model allows the container to optimize much of the database access because it has greater control over when to load data and more information about what data was modified. These control points are provided through the implementation of the abstract getter and setter methods. For example, the container can choose either to aggressively load a col-lection of beans or to wait until a getter method is invoked to load the state of an individual bean. It can also update only those properties of the bean that were modified in a given transaction because it can take note of this during the setter methods.

N OT E

34 J2EE Best Practices: Java Design Patterns, Automation, and Performance

EJB 2.0 CMP Entity Beans provide the following persistence services:

Persistence of each Entity Bean’s properties to a single database table (CMP fields).

Container-managed relationships between related Entity Beans (CMR fields).

Database queries to return individual components or collections of them. This is done both through the use of finder methods on the EJB Home interfaces as well as ejbSelectmethods within an Entity Bean class.

It is important to note that the EJB specification provides explicit support only for a one-to-one bean to table mapping. It does not specify a standard mechanism for map-ping properties of a single Entity Bean to multiple database tables. In terms of more complicated object-relational mapping with Entity Beans, J2EE container vendors and object-relational mapping tools vendors compete to provide more flexible persistence engines built into the Entity Bean component mechanism as a value-added service within their products.

Entity Beans can also manage their own persistence using the Bean-Managed Persistence (BMP) option. In this option, the developer uses the EJB hook methods (ejbStore, ejbLoad, ejbCreate, ejbRemove) as placeholders to implement persistence on its own. The object lifecycle is still managed by the container because these hooks are called as determined by the container at various points within a transaction.

Because Entity Beans are fairly heavyweight components, you might not want to use a large number of them in a given transaction. The EJB 2.0 specification attempts to address this by providing local interfaces to access related components in the same JVM (Java Virtual Machine) without the overhead of RMI. For the purposes of this dis-cussion, you will see that local interfaces do provide a slightly more efficient way to use colocated Entity Beans as helper classes that can be used solely for the persistence of data aggregated within a more complex business object.

An EJB 2.0 component can have a local interface, a remote interface, or both. Because the interface to an Entity Bean can now be either local or remote, these are referred to as component interfaces in the specification. Thus, this term is used when no distinction is required between the two.

In EJB 1.1, every component was assumed to be location independent. This means that the component could be colocated in the same JVM or it could reside on a remote server. Thus, every remote call to the Entity Bean was required to go through RMI, which adds a layer of overhead. All method invocations were pass-by-value requiring the arguments to be copied, serialized, and sent through the RMI protocol. Well, in order to efficiently model the concept discussed earlier of aggregated business objects, you would naturally want to colocate them in the same container instance so that the method calls between the two aggregated business objects did not actually have to go over a network. However, the method invocations were still required to go through RMI because of the location independence feature. Local interfaces in EJB 2.0

N OT E

provide a mechanism through which a component can invoke another EJB that does not go through RMI through its local interface. This is essentially equivalent to a normal method call. However there is still an interface class implementation (the componentinterface), generated by the container, that intercepts and proxies the method invocation. The local component must be resident in the same JVM, and the arguments are now passed by reference. This changes the programming paradigm a bit because developers must be aware that objects passed as arguments to EJB through the local interface can be modified. However, you can now avoid the RMI overhead on these method calls, allowing yourself to build more fine-grained compo-nents such as aggregated or dependent objects. Thus, local interfaces should be used wherever possible.

Comparing Container-Managed and Bean-Managed Persistence

Following is a comparison between the CMP and BMP approaches. Using CMP actu-ally has a number of distinct advantages over the BMP approach. The first one is sim-ple; it is one less component service that you are responsible for developing. If you consider things such as database optimizations, object relationships, and concurrency issues, this is a major benefit to application developers. The second reason is that the EJB 2.0 specification’s abstract persistence schema has provided containers with the ability to optimize much of the bean’s database access. Although the two options might be relatively equal with regards to individual database calls, a CMP Entity Bean usually outperforms a BMP Entity Bean within a transactional application context. An individual database interaction with either a CMP or BMP Entity Bean, or a regular Java class for that matter, exhibits similar characteristics on its own because all of the options execute generally the same JDBC operations. The only noteworthy difference to this may come with containers that use native calls underneath the hood rather than JDBC calls. For the most part, however, this has not taken place in the application server market as products strive to be 100% Java. It is, in fact, the behavior of the com-ponent implementation model within a transactional application where you see the differences emerge. For example, consider a finder method invoked on a BMP Entity Bean’s Home interface. The finder method itself causes a database lookup to get the primary key. Once a business method is invoked on the component interface, the con-tainer calls the ejbLoadmethod to load the state of the instance from the database prior to the bean’s business method being executed. Thus, the simple operation of locating an instance of a business object required two database interactions as opposed to one. It should be noted that CMP Entity Beans have the potential to exhibit the same behavior if run in a container that does not optimize database access. However, newer versions of EJB containers are providing much more robust persistence engines, and the amount of optimization being done has greatly increased. EJB containers are now also providing much more control over these types of operations in the deployment configuration so that the application deployer can tune the behavior of Entity Beans.

This can make a significant difference in terms of performance, particularly when defined data-access patterns exist.

For all of these reasons, there are few compelling reasons to use BMP Entity Beans as a persistence approach. You get the additional overhead of Entity Beans without

36 J2EE Best Practices: Java Design Patterns, Automation, and Performance

deriving many of the benefits. CMP Entity Beans can provide better performance if deployed correctly. As you will see, however, the transaction model and general com-ponent overhead can also greatly affect the overall performance of your applications.

In particular, the Entity Bean model has the potential to increase the amount of data-base interaction and disk I/O under a heavy user load, which of course decreases the overall performance and then becomes a factor in the overall decision. One situation in which this can happen is when there are enough concurrent transactions with EJB clients that the entire pool of Entity Bean instances is being used at once. In these cases, the container is often forced to activate and passivate bean instances in order to balance the load and meet the throughput demands being placed on it. Each of these operations adds additional I/O, which can slow down the application. This topic is discussed in detail in the chapter on performance.

Another such example of the component implementation model increasing the number of database interactions is that of finder methods in Entity Beans. A finder method declared on a Home interface can return a collection of Entity Bean component interfaces if the associated database query can return more than one instance. The client can then iterate through the collection of component interfaces invoking meth-ods on each one. Similar to the BMP/CMP comparison scenario, if you say the number of objects found with the query is n, then the number of database interactions used by the Entity Bean model to call the finder and iterate through the collection can actually be (n + 1). If the container is using a lazy-loading approach, this is the number of actual database calls that would be made, which would be horribly inefficient. This results from the following steps that take place:

1. The finder method is called to run the initial query. This returns a list of primary keys to the container that translates into component interfaces.

2. As the collection returned from the finder method is iterated, each method invocation on the Entity Beans can result in another database query (ejbLoad) if the state of the instance has not already been loaded into the Entity Bean component. This occurs if either BMP or a lazy-loading CMP implementation is used.

In many early application server implementations, this inefficient behavior was the result. Some application servers now allow some control over this behavior by giving the container a hint to use an aggressive-loading approach. This would populate the Entity Beans on the initial finder method query. This provides a much more efficient database interaction, one that you would expect from a high-performance transac-tional application. However, this approach is also not without its potential problems.

Because Entity Beans are fairly heavyweight components, you can have a large num-ber of instances that are used for a particular query. If more than a few users are hitting this particular data retrieval operation at the same time, you could quickly reach the limit on the pool size for your particular Entity Bean. Once this happens, a pending client request could cause some of the beans that were just retrieved to passivate. This causes another level of overhead to be applied to the application when the client iter-ates through the list, although managing a pool of shared component instances is one of the EJB container’s specialties, so this may be less of an issue.

TE AM FL Y

Team-Fly

®

Do not use Entity Bean finder methods to iterate through a result set of business objects unless you can enforce either a read-only caching strategy or an aggressive-loading approach by the container. For a result set of nobjects using lazy loading, this can actually cause (n + 1) database interac-tions. Use a JDBC wrapper component to run the database query and either hold the result set for iteration or return a set of value objects. This limits the operation to one database interaction.

For read-only operations, the client can also easily iterate through the data using a JDBC wrapper component. If transactional update operations are required, a business object can be instantiated from a given row in the result set. This JDBC wrapper can become a generic, smart-instantiation list service that is a part of the Business Logic Foundation. This concept is discussed in full in the next section on building the Business Object Architecture.

Object-Relational Mapping

There are many different approaches to object-relational mapping, which defines how an object’s properties map to database tables and columns. As discussed earlier, CMP Entity Beans are limited to persistence to one table. Any object-relational mapping scheme more complicated than a one-to-one table-object mapping is not currently sup-ported specifically by the EJB specification. To implement a more complex approach, you are required to use either Bean-Managed Persistence, vendor-specific persistence mechanisms, or your own Java business objects and JDBC. You have already seen that there are potential performance issues with BMP Entity Beans, so this is not an ideal approach. The one nice thing about using vendor-specific mechanisms here is that it largely does not affect the portability of your code. The mapping between object prop-erties and database columns is done in the deployment step and container-managed relationships abstract the database specifics of foreign key relationships. Thus, your bean’s code can operate without specific knowledge of the persistence strategy or data-base schema. There are a number of object-relational mapping tools that integrate both into EJB and Java components to cause persistence of the business object data in a data-base. All of these tools, of course, add some overhead to the processing but provide additional flexibility in terms of abstracting the object model from the data model.

It is sometimes best to start with the simple approach and see if that works to some degree of satisfaction. The one-to-one table-object mapping is straightforward and pro-vides a decent level of performance compared to some of the more complicated schemes available. The trade-off comes in terms of the object-oriented design. Assume that for data architecture reasons, the data for a Customer component is actually stored in four different database tables. Conceptually speaking, a customer is a single business entity, and thus you would like to represent it with a single business object.

With the one-to-one table mapping, this presents a bit of a problem.

Short of using an object-relational mapping tool, there are some things that you can do to alleviate this type of problem. The primary tool is that of encapsulation. If you use a lightweight business object implementation, you can define “business objects”

B E ST P R AC T I C E

38 J2EE Best Practices: Java Design Patterns, Automation, and Performance

for each table, although some will be used only for database purposes. These could be called “helper” objects because they really are used only for persistence. The business logic, in this case, is contained within the “super” business objects that aggregate the helper objects. In the banking example, you create a Customerbusiness object and three helper classes, which although technically are business objects in this particular implementation, will be used only by the primary Customerobject for the persistence of the additional data to those tables. All of the actual business logic associated with the customer entity resides in the primary Customerobject. From the perspective of a business object client, it looks as if there is a single business object that deals with the customer, and that is all it needs to know about. The rest of the database logic is encapsulated within the Customercomponent. This approach is particularly appeal-ing if you already have code-generation capabilities for business objects based on the data model. You can then generate all of the business objects to deal with persistence and then code business logic in your primary entities.

This approach does have the disadvantage of moving the knowledge of your data model into the business object layer. However, this is the trade-off for simplicity and, in many cases, performance. It might not bring a smile to the face of an object purist, but it is a very commonly used approach. The other model to use is encapsulating this knowledge in the data-access layer. Thus, you would have only one Customer busi-ness object and a single data-access object whose data is persistent. Once inside the data access object, the data fields are moved to the appropriate database tables. This removes any knowledge of the data model from the business object, although it is dif-ficult to generate this type of data object through standard code generation. In order to go to this level, you would either need to hand-code these data objects or use an object-relational mapping tool.

在文檔中 WILEY advantage (頁 58-63)