31.8.3. Lazy loading Process
Lazy loading is the other half of eager loading. If a field is not eager loaded, it must be lazy loaded. When an access to an unloaded field of a bean is made, JBoss loads the field and all the fields of any
lazy-load-group
the field belong to. JBoss performs a set join and then removes any field that is already loaded. An example configuration is shown below.
<jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>GangsterEJB</ejb-name> <!-- ... --> <load-groups> <load-group> <load-group-name>basic</load-group-name> <field-name>name</field-name> <field-name>nickName</field-name> <field-name>badness</field-name> </load-group> <load-group> <load-group-name>contact info</load-group-name> <field-name>nickName</field-name> <field-name>contactInfo</field-name> <field-name>hangout</field-name> </load-group> </load-groups> <!-- ... --> <lazy-load-groups> <load-group-name>basic</load-group-name> <load-group-name>contact info</load-group-name> </lazy-load-groups> </entity> </enterprise-beans> </jbosscmp-jdbc>
When the bean provider calls
getName()
with this configuration, JBoss loads name
, nickName
and badness
, assuming they are not already loaded. When the bean provider calls getNickName()
, the name
, nickName
, badness
, contactInfo
, and hangout
are loaded. A detailed description of the lazy loading process follows:
- All data in the preload cache for this entity is loaded into the fields.
- If the field value was loaded by the preload cache the lazy load process is finished.
- JBoss finds all of the lazy load groups that contain this field, performs a set join on the groups, and removes any field that has already been loaded.
- A query is executed to select the necessary columns. As in the basic load process, JBoss may load a block of entities. The data for the current entity is stored in the context and the data for the other entities is stored in the preload cache.
31.8.3.1. Relationships
Relationships are a special case in lazy loading because a CMR field is both a field and query. As a field it can be
on-load
block loaded, meaning the value of the currently sought entity and the values of the CMR field for the next several entities are loaded. As a query, the field values of the related entity can be preloaded using on-find
.
Again, the easiest way to investigate the loading is to look at a usage scenario. In this example, an HTML table is generated containing each gangster and their hangout. The example code follows:
Example 31.3. Relationship Lazy Loading Example Code
public String createGangsterHangoutHtmlTable() throws FinderException { StringBuffer table = new StringBuffer(); table.append("<table>"); Collection gangsters = gangsterHome.findAll_onfind(); for (Iterator iter = gangsters.iterator(); iter.hasNext(); ) { Gangster gangster = (Gangster)iter.next(); Location hangout = gangster.getHangout(); table.append("<tr>"); table.append("<td>").append(gangster.getName()); table.append("</td>"); table.append("<td>").append(gangster.getNickName()); table.append("</td>"); table.append("<td>").append(gangster.getBadness()); table.append("</td>"); table.append("<td>").append(hangout.getCity()); table.append("</td>"); table.append("<td>").append(hangout.getState()); table.append("</td>"); table.append("<td>").append(hangout.getZipCode()); table.append("</td>"); table.append("</tr>"); } table.append("</table>");return table.toString(); }
For this example, the configuration of the gangster's
findAll_onfind
query is unchanged from the on-find
section. The configuration of the Location
entity and Gangster-Hangout
relationship follows:
Example 31.4. The jbosscmp-jdbc.xml Relationship Lazy Loading Configuration
<jbosscmp-jdbc> <enterprise-beans> <entity> <ejb-name>LocationEJB</ejb-name> <load-groups> <load-group> <load-group-name>quick info</load-group-name> <field-name>city</field-name> <field-name>state</field-name> <field-name>zipCode</field-name> </load-group> </load-groups> <eager-load-group/> </entity> </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Gangster-Hangout</ejb-relation-name> <foreign-key-mapping/> <ejb-relationship-role> <ejb-relationship-role-name> gangster-has-a-hangout </ejb-relationship-role-name> <key-fields/> <read-ahead> <strategy>on-find</strategy> <page-size>4</page-size> <eager-load-group>quick info</eager-load-group> </read-ahead> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> hangout-for-a-gangster </ejb-relationship-role-name> <key-fields> <key-field> <field-name>locationID</field-name> <column-name>hangout</column-name> </key-field> </key-fields> </ejb-relationship-role> </ejb-relation> </relationships> </jbosscmp-jdbc>
JBoss will execute the following query for the finder:
SELECT t0_g.id, t0_g.name, t0_g.nick_name, t0_g.badness FROM gangster t0_g ORDER BY t0_g.id ASC
Then when the hangout is accessed, JBoss executes the following two queries to load the
city
, state
, and zip
fields of the hangout:
SELECT gangster.id, gangster.hangout, location.city, location.st, location.zip FROM gangster, location WHERE (gangster.hangout=location.id) AND ((gangster.id=0) OR (gangster.id=1) OR (gangster.id=2) OR (gangster.id=3)) SELECT gangster.id, gangster.hangout, location.city, location.st, location.zip FROM gangster, location WHERE (gangster.hangout=location.id) AND ((gangster.id=4) OR (gangster.id=5) OR (gangster.id=6) OR (gangster.id=7))
The following table shows the execution of the queries:
Table 31.4. on-find Optimized Relationship Query Execution
id | name | nick_name | badness | hangout | id | city | st | zip |
---|---|---|---|---|---|---|---|---|
0 | Yojimbo | Bodyguard | 7 | 0 | 0 | San Fran | CA | 94108 |
1 | Takeshi | Master | 10 | 1 | 1 | San Fran | CA | 94133 |
2 | Yuriko | Four finger | 4 | 2 | 2 | San Fran | CA | 94133 |
3 | Chow | Killer | 9 | 3 | 3 | San Fran | CA | 94133 |
4 | Shogi | Lightning | 8 | 4 | 4 | San Fran | CA | 94133 |
5 | Valentino | Pizza-Face | 4 | 5 | 5 | New York | NY | 10017 |
6 | Toni | Toothless | 2 | 6 | 6 | Chicago | IL | 60661 |
7 | Corleone | Godfather | 6 | 7 | 7 | Las Vegas | NV | 89109 |