The Loading ProcessIn the previous sections, several times we use the phrase "when an entity is loaded." This is intentionally left vague because the commit option specified for the entity and the current state of the transaction determine when an entity is loaded. The following sections describe the commit options and the loading processes. Commit Options
Central to the loading process are the commit options, which control when the cached data for an entity
The commit option is declared in the jboss. xml file. For a detailed description of this file, see Chapter 5, "EJBs on JBoss." The example shown in Listing 11.2 changes the commit option to A for all entity beans in the application. Listing 11.2. The jboss.xml Commit Option Declaration
<jboss>
<container-configurations>
<container-configuration>
<container-name>Standard CMP 2.x EntityBean</container-name>
<commit-option>A</commit-option>
</container-configuration>
</container-configurations>
</jboss>
The
|
|
1. |
If the entity context is still valid, no loading is necessary, and therefore the loading process is done. The entity context is valid when you use commit option
A
or commit option
D
and the data has not timed out.
|
|
2. |
Any
|
|
3. |
The primary key value is injected back into the primary key fields. The primary key object is actually independent of the fields and needs to be reloaded after the flush in step 2.
|
|
4. |
All data in the preload cache for this entity is loaded into the fields.
|
|
5. |
JBoss determines what additional fields still need to be loaded. Normally, the fields to load are determined by the eager-load group of the entity, but this can be overridden if the entity is located by using a query or CMR field with an
on-find
or
on-load read-ahead
strategy. If all the fields have already been loaded, the load process skips to step 7.
|
|
6. |
A query is executed to select the necessary column. If this entity uses the
on-load
strategy, a page of data is loaded, as described in the section "The on-load Strategy," earlier in this chapter. The data for the current entity is stored in the context, and the data for the other entities is stored in the preload cache.
|
|
7. |
The
ejbLoad
method of the entity is called.
|
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
<jbosscmp-jdbc>
<enterprise-beans>
<entity>
<ejb-name>GangsterEJB</ejb-name>
<!-- ... -->
<load-groups>
<load-group>
<load-group-name>most</load-group-name>
<field-name>name</field-name>
<field-name>nickName</field-name>
<field-name>badness</field-name>
<field-name>hangout</field-name>
<field-name>organization</field-name>
</load-group>
</load-groups>
<eager-load-group>most</eager-load-group>
</entity>
</enterprise-beans>
</jbosscmp-jdbc>
When the bean provider calls
getName()
with this configuration, JBoss loads
name, nickName
, and
badness
,
|
1. |
All data in the preload cache for this entity is loaded into the fields.
|
|
2. |
If the field value was loaded by the preload cache, the lazy-load process is finished.
|
|
3. |
JBoss finds all the lazy-load groups that contain this field, performs a set join on the groups, and removes any field that has already been loaded.
|
|
4. |
A query is executed to select the necessary
|
Relationships are a special case in lazy loading because a CMR field is both a field and a query. As a field, it can be
on-load
block loaded, meaning that the value of the currently sought entity and the values of the CMR field for the
Again, the
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 what is described earlier in this chapter. The configuration of the Location entity and Gangster-Hangout relationship is shown in Listing 11.4.
<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-filaelds>
</ejb-relationship-role>
</ejb-relation>
</relationships>
</jbosscmp-jdbc>
JBoss executes 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))
Table 11.4 shows the execution of the queries.
|
id name |
nick_name |
badness |
hangout |
id |
city |
st |
zip |
|---|---|---|---|---|---|---|---|
|
0 Yojimbo |
Bodyguard |
7 |
|
|
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 |
By default, when a multi-object finder or select method is executed, the JDBC result set is read to the end immediately. The client receives a collection of
EJBLocalObject
or CMP field values that it can then iterate through. For big result sets, this approach is not efficient. In some cases, it is better to delay reading the next row in the result set until the client
<query>
<query-method>
<method-name>findAll</method-name>
</query-method>
<jboss-ql><![CDATA[select object(o) from A o]]></jboss-ql>
<lazy-resultset-loading>true</lazy-resultset-loading>
</query>
There are some issues you should be aware of when using lazy result set loading. You need to take special care when working with a
Collection
associated with a lazily loaded result set. The first call to
iterator()
returns a special
Iterator
that reads from the
ResultSet
. Until this
Iterator
has been exhausted,