Note: This tutorial requires Resin-CMP 2.1.1 or later.
Improving performance generally means eliminating unnecessary operations. Resin-CMP offers a number of techniques for improving performance. As with all performance work, it's best to use a profiler with a representative load to find out where most of the time is being taken.
A very effective technique for improving performance is to use Resin's proxy caching to cache entire pages. Caching a heavily used page for as short a time as 60 seconds can avoid most of the database calls.
Even if the entire page can't be cached, it's normally possible to cache subpages. Any include() page is cached in the exact same way as the main page.
Resin's page caching uses the HTTP caching headers. The simplest example just sets the expires time to 60 seconds in the future. The technique is identical for both servlets and JSP pages.
Most database queries read data from the database; updating the database is more rare. Because reads can be cached, it's important to tell Resin which business methods are expected to be read methods (transactions) and which are update methods (transactions).
Read transactions can use cached values. Even a short cache timeout like 10s can save many database queries. In many cases, read transactions don't need to query the database at all.
Update transactions must read the data from the database, update the data, and store it back to the database.
By default, Resin knows that findXXX, ejbSelectXXX, and cmp-field and cmr-field getXXX methods are read transactions. It assumes that all other business methods are update transactions.
For example, the following sum method adds the values of cmp-fieldsand . Because it only reads data, it could use Resin's cache, but because it's a business method, Resin can't automatically determine that it's a read-only method. By declaring it read-only, the application can cache and improve performance.
Resin-CMP supports read-only transactions by letting application mark business methods as read-only. If a transaction is read-only, Resin can use a cached value. If the transaction is read-write, Resin will need to load the data from the database to ensure the data is properly locked.
The <method> configuration with the <resin-isolation> tag configures read-only methods. Thevalue is used for read methods and the value is used for read-write methods, i.e. methods that need to load from the database to ensure locking.
Thevalue for the signature specifies the default value.
Resin-CMP knows the setXXX, create, and remove methods are update. Resin-CMP will always usefor those methods, ignoring the resin-isolation value. Resin-CMP also knows the getXXX methods and findXXX methods are read-only, so it can ignore the resin-isolation value. So applications only need to supply values for the business methods.
Some database tables never change, or are only changed by infrequent external maintenance so the CMP read-only. Beans for read-only tables can always cache the bean values even inside an "update" transaction. (See above for read-only vs update transactions.)
Read-only entity beans are marked with the <read-only> attribute.
Even when a read-only bean is in an updating transaction, i.e. other beans are changing, the read-only bean can use the cached value.
Theconfigures how long Resin can cache a loaded bean. The default is only 5 seconds. Although that's short, it ensures that a single page that reads the uses entity bean several times will only access the database once. For beans like the category example, a longer value like an hour may be more appropriate.
Because the EJBLocalHome object is a constant object, servlets should load it in the init() method and use that loaded value in the servlet. Because this optimization is so simple, all servlets should use it as their default EJB use pattern.
Some databases can limit queries to a short subsequence of the entire query. For example, a search engine list will normally have several pages of results. Normally, the OFFSET and LIMIT will also use ORDER BY to make sure the results returned are consistent.
By default, Resin-CMP will load the bean values when it runs the query. For example, a findAll method will load all the beans with a single SQL SELECT. The followingmethods will not need to access the database.
Normally, this preloading will provide the best performance. In some cases, only the identity of the loaded beans is important, not the data values. In those cases, the query should only ask the database for the primary key, not the entire bean's state.
The loading is configured with the <query-loads-bean> tag.
The performance techniques described above give the application developer great flexibility for improving CMP performance. As with all performance work, it's always important to use a profiler to find the bottlenecks in the application. Very often, the real bottleneck will be a surprise.