Java Development News:
Optimizing CMP Performance in Weblogic with Long-term Caching
By Dmitri Maximovich
29 Mar 2005 | TheServerSide.com
Not very popular choice for persistence nowadays, CMP still too often is only readily available persistence framework in Enterprise environment. While not as sexy as hibernate or SQL Maps, CMP 2.X implementation in leading application servers such as BEA Weblogic offers quite good solution for ORM problems. Beside there is a lots of developers familiar with EJB and mature support from different tools from xdoclet to Eclipse wtp/jst.
Let's take a look at what can be done to improve performance of CMP in Weblogic by enabling more aggressive than default caching strategies.
Everybody knows that EJB Container maintains cache or pool of Entity Beans, usually configurable
in deployment descriptor. Amazingly lots of developers don't realize that it doesn't mean that once
Container loaded particular bean instance from database it won't go to database again while bean
instance is kept in pool. Quite contrary, by default Container calls
synchronize instance's state from the database at the beginning of every transaction. Basically on
every operation with CMP bean, even if bean was loaded seconds ago in previous transaction
Container executes SQL select to refresh it. Only while you operating with CMP instance(s) in one
transaction Container caches them. This is so called 'Commit Options A/B/C' as described in EJB 2.0
Obviously reloading state from database in every transaction could have some performance impact. Easy to understand why this is default behavior - this is safest way if database shared between multiple processes and each one of them could change state of persisted object in database while it's cached in EJB pool. In this case we're facing possibility of lost updates - other process updates record in database and then Container overwrites it with potentially stale data from cache. But first of all refreshing data in the beginning of transaction doesn't guarantee against lost updates, it's just reduces possibility of it. This is a well know problem in database world and there are two approaches to deal with it. First approach is so called 'pessimistic concurrency locking', when records in database locked for other updaters for duration of transaction ('select for update'). This is almost never used because of significant overhead and performance impact. Second approach is called 'optimistic concurrency locking', in this case there is no actual locks held in database but process which execute update has some mechanism to detect that record been updated by other process between his read and update. Preferred way to implement this is with 'version' column on the database table (in SQL update increment value for that column, include previous value in 'where' clause and then detect if no rows are updated).
Weblogic has built in support for optimistic concurrency in CMP beans via verify-columns element in weblogic-cmp-rdbms-jar.xml deployment descriptor. It is a good practice to have 'version' column in all (updatable) tables in your database and configure CMPs to use it by enabling optimistic concurrency in concurrency-strategy element in weblogic-ejb-jar.xml
Optimistic concurrency alone doesn't give you any performance improvement, but it's necessary
step to enable cache-between-transactions
functionality which is not available without enabling optimistic concurrency (for the reasons
discussed above). Setting cache-between-transactions to 'true' will result in Container skipping
ejbLoad() if bean instance is already available in the EJB cache. For certain
types of applications where the same objects accessed more than once from different transactions
over short period of time this can lead to significant performance improvements (in our tests up to
30% for our application).
Naturally your application must be ready to deal with
OptimisticConcurrencyException when concurrency violation is detected by container.
OptimisticConcurrencyException (subtype of RuntimeException) is thrown Container
discards EJB instance from cache. In a cluster, when a bean with Optimistic concurrency is updated,
notifications are broadcast to other cluster members to prevent optimistic conflicts. Note that if
you have delay-updates-until-end-of-tx
set to 'true' (default) your code won't see optimistic exception until transaction commit.
Word of caution. While available for quite a long time, cache-between-transactions functionality never worked stable in Weblogic 7, but it seems to be fixed in version 8.1. We're using it in production applications and quite happy with the results.
About the author
Dmitri Maximovich is an independent consultant specializing in software design, development, and technical training. He has more than twelve years of industry experience and has been involved with J2EE since its inception. His job profile includes designing and developing mission critical applications for financial and pharmaceutical industries. Dmitri lives in Toronto, Canada and has a master's degree in Physics from St. Petersburg university.