Features of WebLogics CMP

Features of WebLogic s CMP

This section examines a number of WebLogic features that distinguish WebLogic's CMP implementation. These include convenience features such as automatic generation of primary keys for new EJB instances, automatic creation of DBMS tables that map to the abstract persistent model, and more performance-oriented features such as statement batching, optimistic concurrency, and fetching preconfigured groups of fields. Later in this chapter, we look at two optimizations for container-managed EJB relationships: enabling the DBMS to take charge of cascading an EJB remove to related EJB instances and relationship caching.

11.2.1 Automatic Primary Key Generation

WebLogic can generate primary key values automatically for noncompound primary key fields. To support this, the primary key class element in the ejb-jar.xml file must be either java.lang.Integer or java.lang.Long. The keys can be generated in two ways: WebLogic can either delegate the primary key generation to the DBMS, or it can use a named sequence table.

11.2.1.1 DBMS-generated primary keys

If you are using either Oracle or Microsoft's SQL Server, WebLogic can use the underlying DBMS to generate primary keys. In Oracle, the EJB container accomplishes this using Oracle's sequences. When a new primary key is needed, it calls on the sequence (or increments a cached sequence number). For SQL Server, it uses identity columns, which means that the primary key value is supplied automatically by the DBMS when the row is inserted.

Using Oracle, you can create a sequence together with an increment value via the following SQL:

create sequence seqEmployee start with 1 increment by 5;

By utilizing increment values, you can minimize the number of times that WebLogic has to interact with the sequence, which can in turn help performance. Once you have created the sequence, use the automatic-key-generation element in the weblogic-cmp-rdbms-jar.xml descriptor to specify the name of the sequence and a cache size:

ORACLE seqEmployee 5

Ensure that the cache size matches the sequence increment. If it does not, the EJB container may obtain duplicate values from the sequence or obtain unnecessary gaps in the primary keys generated for the actual rows. For SQL Server, simply ensure that the database column corresponding to the primary key field is an IDENTITY column with AUTO-INCREMENT enabled. Now set the generator-type to SQLServer in the weblogic-cmp-rdbms-jar.xml descriptor:

SQLServer

11.2.1.2 Sequence tables

An alternative approach that doesn't rely on any particular database is to provide a table that holds a monotonically increasing value. For this, you need a table with a single column and a single row. The row will hold the current key value. In Oracle, you can create and populate such a table as follows:

CREATE mySequenceTable (SEQUENCE int) INSERT into mySequenceTable VALUES (1)

To ensure that no duplicate keys are generated under concurrent access, WebLogic uses the Serializable transaction isolation level when accessing the table. Hence, the DBMS must support this isolation level if the EJB container can generate primary keys using sequence tables. However, the Serializable isolation level also will slow down access to the sequence table. To minimize this degradation, you should create a unique sequence table for each entity bean type. Here are the changes you need to make to the weblogic-cmp-rdbms-jar.xml descriptor in order to use this form of key generation:

NamedSequenceTable mySequenceTable

11.2.2 Automatic Table Creation and Validation

WebLogic can be configured to automatically generate the database tables that map to the EJB's persistence schema. WebLogic creates the database tables for all entity beans packaged in an EJB JAR during deployment. It uses the value of the database-type[1] element in the weblogic-cmp-rdbms-jar.xml descriptor to determine the SQL commands specific to the underlying DBMS that are needed to create the required database tables. The tables are generated based on the bean classes and the abstract persistence schema defined in the deployment descriptors. In WebLogic 7.0, you can enable automatic table creation when the EJB JAR is deployed by including the following element in the weblogic-cmp-rdbms-jar.xml descriptor:

[1] WebLogic 8.1 can automatically detect the type to the DBMS being used to persist the EJBs. If the detected type conflicts with the value of the database-type element, WebLogic issues a warning and uses the specified type.

True

The tables are created only if they do not already exist in the database. For this reason, you should delete the tables if the fields in the entity bean change and you use this flag in WebLogic 7.0. If an error occurs during table creation, WebLogic aborts the process and continues with deployment. In that case, you need to set up the database schema manually.

WebLogic 8.1 can recreate the database tables automatically when the EJB's table schema changes i.e., if any of the table columns that map to the CMP fields are modified. Thus, when you enable automatic table creation on an EJB JAR, the EJB container automatically changes the underlying database schema, to ensure that it remains in sync with the EJB's persistence schema. If any CMP field cannot be mapped properly to a database column, a Table Not Found error occurs indicating that the table could not be created and must be set up manually. Moreover, you must use the create-default-dbms-tables element to define precisely how WebLogic creates the database schema when the EJB module is deployed. You can choose from the following values for the create-default-dbms-tables element:

Disabled

By default, the EJB container ignores any changes to the underlying table schema.

CreateOnly

The EJB container creates the necessary database tables for each CMP bean in the JAR, provided they don't already exist.

DropAndCreate

For each CMP bean in the JAR, the EJB container drops and creates the table if any of its columns have changed. All data held in the database table is lost.

DropAndCreateAlways

For each CMP bean in the JAR, the EJB container drops and creates the table, even if none of its columns has changed.

AlterOrCreate

For each CMP bean in the JAR, the EJB container attempts to alter the table schema, if it already exists. Otherwise, the EJB container creates the database table during deployment. Note that, if a new column (or a column with null values) is made the primary key, this table creation mode will fail.

AlterOrCreate is disabled if the server is running in production mode. In general, the database tables generated will be a close approximation to the EJB's CMP fields and the EJB relationships defined in the deployment descriptors. For production environments, usually you will need to refine the database schema and provide a more precise schema definition.

WebLogic can validate whether the entity beans have been mapped correctly to the actual database schema during deployment. You can enable this validation by specifying a validate-db-schema-with element in the weblogic-cmp-rdbms-jar.xml descriptor file:

DepartmentEJB ... ... SQL_SERVER TableQuery

You can specify two possible values for this setting:

MetaData

This implies that the CMP runtime uses the JDBC metadata to validate the actual database schema.

TableQuery

This means that the CMP runtime will query the database tables directly to determine whether they match the expected database schema.

If you don't want to rely on WebLogic's DBMS detection capability, make sure that you specify the database-type element when you enable automatic table creation or database schema validation.

11.2.3 Mapping CMP Fields Across Multiple DBMS Tables

Any entity bean in WebLogic can be partitioned across a number of tables. This means that you can store the different CMP and CMR fields of a single bean in several tables. You may want to do this for performance reasons, or simply because you need to support a legacy database schema. When using this feature, creating a new entity bean will result in a new row being inserted into each table to which the bean is mapped. Likewise, deleting a bean will delete a row from each table. The rows across the tables are correlated by their primary key values. This feature comes with a couple of sensible restrictions:

To map the CMP fields to multiple database tables, simply include multiple table-map elements in the weblogic-cmp-rdbms-jar.xml descriptor file, one for each table involved, while ensuring that each table map includes the primary key column. Earlier, we saw in Example 11-5 how the CMP fields of the Department EJB were mapped to a single table. If you were to add an additional CMP field that mapped to a column in a separate table say, tblHistory you would modify the weblogic-cmp-rdbms-jar.xml descriptor file as described next.

DepartmentEJB MyDataSource tblDepartment id Id name Name tblHistory id Id history history

11.2.4 Adjusting the Insert Behavior

WebLogic lets you configure precisely when the EJB container inserts newly created EJBs into the database. The delay-database-insert-element in the weblogic-cmp-rdbms-jar.xml descriptor lets you adjust this setting. The default value for this setting is ejbPostCreate:

ejbPostCreate

This means that by default, WebLogic delays inserting the new bean until after the call to the ejbPostCreate( ) method. If a CMR field is mapped to a foreign-key column, which doesn't allow null values, you must delay the actual database insert until after the ejbPostCreate( ) method. In this way, you can initialize the CMR field to a non-null value in the ejbPostCreate( ) method before the EJB instance is inserted into the database, thereby avoiding a constraint exception. Remember, you cannot initialize CMR fields in the ejbCreate( ) method before the primary key for the entity bean is known. This setting generally yields better performance.

If you specify ejbCreate as the value for the delay-database-insert-until element, WebLogic inserts the EJB immediately after the call to the ejbCreate( ) method. And if you specify commit as the value for the previous setting, WebLogic performs a bulk insert of EJBs when the transaction is committed. This improves the performance of EJB creation because the EJB container then can execute a single batch command that handles multiple database inserts for newly created EJB instances. In this case, the client must explicitly initiate a JTA transaction that wraps calls to multiple EJB create operations. The newly created EJB instances will be inserted only when the transaction completes successfully.

WebLogic supports bulk inserts for entity beans only if the underlying JDBC driver also supports the addBatch( ) and executeBatch( ) methods on the JDBC Statement interface.

A client must ensure that a bulk insert does not create more EJBs than the max-beans-in-cache setting in the weblogic-ejb-jar.xml descriptor file.

11.2.5 Batch Operations

You often need to update multiple EJB instances of the same type within a transaction. For each update to an EJB instance, the EJB container needs to execute a corresponding database update. Clearly, this approach impedes performance when you need to update a large number of EJB instances because of the number of database trips that are involved. WebLogic lets you configure the EJB container to take advantage of JDBC 2.0 statement batching. By enabling batch operations, the EJB container is able to perform multiple database operations (inserts, updates, or deletes) using a single JDBC call, and can therefore limit the number of database trips to just one. The enable-batch-operations element within the weblogic-cmp-rdbms-jar.xml descriptor file toggles this behavior:

True

When batched operations are enabled, the EJB container delays all database updates on the EJB until the transaction is committed.

11.2.6 Delayed Existence Checking

By default, the EJB container in WebLogic 8.1 checks whether an entity EJB instance actually exists in the database before any EJB method call completes. If the EJB instance does not exist, it will notify the application with an exception. This is in keeping with the J2EE 1.3 standard. For instance, if a client gets the value of a CMP field and the entity bean no longer exists in the database, the EJB container will throw a NoSuchObjectException. (For local EJBs, it will throw a NoSuchLocalObjectException.)

For higher performance, you can instruct WebLogic to perform these checks only when a transaction commits. The check-exists-on-method element in the weblogic-cmp-rdbms-jar.xml descriptor file lets you enable this late checking:

False

Note that in WebLogic 7.0, the EJB container performs the late checking by default. You must explicitly enable this setting to force WebLogic 7.0 to perform strict checking for existence before an EJB method is invoked.

11.2.7 Optimistic Concurrency

In Chapter 10, we saw how the optimistic concurrency strategy ensures that no locks are held by the EJB container or the actual database. Instead, the EJB container does a "smart update" by ensuring that the data being modified hasn't changed since the start of the transaction. To configure optimistic concurrency for an entity bean, you need to use the concurrency-strategy element in the weblogic-ejb-jar.xml descriptor file:

15 Optimistic

After this, you need to configure the EJB container so that it can check for data validity before it performs the updates. The verify-columns element in the weblogic-cmp-rdbms-jar.xml descriptor file lets you configure this checking:

EmployeeEJB testds ... ... ...

You can specify one of the following values for the verify-columns element:

Read

This implies that all database columns that have been read during the transaction are checked before the transaction is committed.

Modified

This implies that only those columns that have been modified during the transaction are checked before the transaction is committed.

Version

This implies that a version pseudocolumn exists in the table, and this column is used to determine whether database columns have been modified since the start of the transaction.

Timestamp

This implies that a timestamp pseudocolumn exists in the table, and this column is used to determine whether database columns have been modified since the start of the transaction.

If you choose either Version or Timestamp as the value for the setting, the database is responsible for keeping the version or timestamp columns in sync (typically via an update trigger). A version column should be an integer column whose value is incremented whenever a row is modified. A timestamp column should be set to the current system time whenever the row is modified. Finally, you need to designate a version or timestamp column that will be used to implement optimistic concurrency. For this, you should use the optimistic-column element in the weblogic-cmp-rdbms-jar.xml descriptor:

... Timestamp lastModified

In this case, the EJB container uses the lastModified column in the underlying table to implement a timestamp-based optimistic concurrency strategy. Remember, if the EJB is mapped to multiple database tables, optimistic checking occurs only on those tables that are modified during the transaction.

In WebLogic 8.1, you can use the verify-rows element in the weblogic-cmp-rdbms-jar.xml descriptor to indicate which database rows are under the purview of optimistic checking:

EmployeeEJB testds ... Modified ...

The default value for the verify-rows element is Modified i.e., the EJB container checks only the rows that were updated or deleted during the transaction. If you set the verify-rows element to Read, the EJB container performs optimistic checks on all rows read during the transaction, regardless of whether they are updated later or deleted during the transaction. Clearly, this yields a higher level of data consistency, but at the cost of lower performance.

Clearly, if verify-rows is set to Read, verify-columns must not be set to Modified because otherwise, the EJB container will end up checking only the modified rows.

 

11.2.8 Field Groups and Finder Optimizations

The finders-load-bean element in the weblogic-ejb-jar.xml descriptor file determines whether the EJB fields are loaded eagerly or lazily. By default, this is set to true, which means that when a finder method is executed, the EJB container will eagerly load all of the EJB's data the primary key as well as its CMP fields. This default strategy saves multiple round trips to the database if an application needs to access the EJBs returned by the finder method. However, if you set the finders-load-bean setting to false, the EJB instances returned by the finder method will not be loaded when it executes. Instead, the values of the CMP fields of the EJB will be loaded by the EJB container when a field is accessed by the application. Note that this behavior applies only to EJBs that are loaded explicitly by finder methods, or implicitly by navigating a CMR field.

Optimizing JDBC round trips by using eager loading is all very well, but what if this causes too much data to be transferred? For example, suppose the Department bean has a field containing a large amount of data say, a "history" field. As an architect, you may know that the history field is used only rarely. In this case, the eager finder behavior may hurt performance. To compensate for this, you can use field groups.

A field group is a named subset of a bean's CMP and CMR fields. When a bean is loaded using a query or relationship that has been associated with a field group, only the fields specified in the field group are loaded. Example 11-6 shows a simple field group that contains only the identity and name CMP fields.

Example 11-6. A simple field group

DepartmentEJB testds ... noHistory id name ...

If a field group is not specified, a special default field group is used that ensures that all of the bean's fields are loaded.

Once you have established a field group, simply associate it with a finder method to ensure that the finder loads only the desired EJB fields:

finderNoHistory noHistory

A CMP field may belong to multiple field groups, and the EJB may define many finder methods, each referring to a different field group. Because of these optimizations, you can implement precise control over how much data is loaded, as well as when it is loaded. Field groups also are used in optimizing relationship caching, discussed later.

Категории