This section discusses two special performance-enhancing techniques: version consistency and request partitioning.
Use version consistency to improve performance while protecting the integrity of data in the database. Since the application server can use multiple copies of an EJB component simultaneously, an EJB component’s state can potentially become corrupted through simultaneous access.
The standard way of preventing corruption is to lock the database row associated with a particular bean. This prevents the bean from being accessed by two simultaneous transactions and thus protects data. However, it also decreases performance, since it effectively serializes all EJB access.
Version consistency is another approach to protecting EJB data integrity. To use version consistency, you specify a column in the database to use as a version number. The EJB lifecycle then proceeds like this:
The first time the bean is used, the ejbLoad() method loads the bean as normal, including loading the version number from the database.
The ejbStore() method checks the version number in the database versus its value when the EJB component was loaded.
If the version number has been modified, it means that there has been simultaneous access to the EJB component and ejbStore() throws a ConcurrentModificationException.
Otherwise, ejbStore() stores the data and completes as normal.
The ejbStore() method performs this validation at the end of the transaction regardless of whether any data in the bean was modified.
Subsequent uses of the bean behave similarly, except that the ejbLoad() method loads its initial data (including the version number) from an internal cache. This saves a trip to the database. When the ejbStore() method is called, the version number is checked to ensure that the correct data was used in the transaction.
Version consistency is advantageous when you have EJB components that are rarely modified, because it allows two transactions to use the same EJB component at the same time. Because neither transaction modifies the data, the version number is unchanged at the end of both transactions, and both succeed. But now the transactions can run in parallel. If two transactions occasionally modify the same EJB component, one will succeed and one will fail and can be retried using the new values—which can still be faster than serializing all access to the EJB component if the retries are infrequent enough (though now your application logic has to be prepared to perform the retry operation).
To use version consistency, the database schema for a particular table must include a column where the version can be stored. You then specify that table in the sun-cmp-mapping.xml deployment descriptor for a particular bean:
<entity-mapping> <cmp-field-mapping> ... </cmp-field-mapping> <consistency> <check-version-of-accessed-instances> <column-name>OrderTable.VC_VERSION_NUMBER</column-name> </check-version-of-accessed-instances> </consistency> </entity-mapping>
In addition, you must establish a trigger on the database to automatically update the version column when data in the specified table is modified. The Application Server requires such a trigger to use version consistency. Having such a trigger also ensures that external applications that modify the EJB data will not conflict with EJB transactions in progress.
For example, the following DDL illustrates how to create a trigger for the Order table:
CREATE TRIGGER OrderTrigger BEFORE UPDATE ON OrderTable FOR EACH ROW WHEN (new.VC_VERSION_NUMBER = old.VC_VERSION_NUMBER) DECLARE BEGIN :NEW.VC_VERSION_NUMBER := :OLD.VC_VERSION_NUMBER + 1; END;
Request partitioning enables you to assign a request priority to an EJB component. This gives you the flexibility to make certain EJB components execute with higher priorities than others.
An EJB component which has a request priority assigned to it will have its requests (services) executed within an assigned threadpool. By assigning a threadpool to its execution, the EJB component can execute independently of other pending requests. In short, request partitioning enables you to meet service-level agreements that have differing levels of priority assigned to different services.
Request partitioning applies only to remote EJB components (those that implement a remote interface). Local EJB components are executed in their calling thread (for example, when a servlet calls a local bean, the local bean invocation occurs on the servlet’s thread).
Configure additional threadpools for EJB execution using the Admin Console.
Add the additional threadpool IDs to the Application Server’s ORB.
You can do this by editing the domain.xml file or through the Admin Console.
For example, enable threadpools named priority-1 and priority-2 to the <orb> element as follows:
<orb max-connections="1024" message-fragment-size="1024" use-thread-pool-ids="thread-pool-1,priority-1,priority-2">
Include the threadpool ID in the use-thread-pool-id element of the EJB component’s sun-ejb-jar.xml deployment descriptor.
For example, the following sun-ejb-jar.xml deployment descriptor for an EJB component named “TheGreeter” is assigned to a thread pool named priority-2:
<sun-ejb-jar> <enterprise-beans> <unique-id>1</unique-id> <ejb> <ejb-name>TheGreeter</ejb-name> <jndi-name>greeter</jndi-name> <use-thread-pool-id>priority-1</use-thread-pool-id> </ejb> </enterprise-beans> </sun-ejb-jar>
Restart the Application Server.