Why are our tutorials constructed as they are?
Hi,
I've always been puzzled by the fact that the tutorials that Sun and
others release to teach new developers the ins and outs of J2EE
technologies are very often implemented in ways that could not even be
considered in real world applications. To illustrate my point, I would
point to the 'getAccountsOfCustomer' method on
com.sun.ebank.ejb.account.AccountControllerBean in the 'Bank' example
in the J2EE 1.4 tutorial.
For the default four account list for customer 200, the original
version executes five EJB Home calls (1 to load the Customer and 1 to
lead each Account) and executes 6 SQL statements (1 to load the
Customer, one to load the set of Customer/Account relations and 1 to
load each Account). My modified version executes 1 SQL statement and
makes no EJB Home calls at all. Measuring wall clock time shows that
the original version takes at LEAST 10 times as long as my modified
version and ignores the extra contention caused by all theat extra EJB
container and SQL activity in the execution environment.
Is it too much to say that you can't even consider an implementation
strategy that imposed an order of magnitude decrease in performace when
implementing real world applications? In my experience, no. You can't
consider the CMP based implementation strategy illustrated in the
original version of this method because no rational IT organization or
customer is going to invest an order of magnitude more in server
hardware to support a development strategy. If I'm right, then why
would we illustrate the use such an important technology with such a
terrible example? If I'm wrong, what benifit of the original
implementation of this method justifies the order of magnitude decrease
in performance?
The problem from my perspective is that developers learn the techniques
they see used in the tutorials and then try to apply them at work.
When they do that, they often run into someone like me who makes them
alter their approach. At that point, the best possible outcome is that
they learn a new development approach without the support of published
tutorials. A more typical outcome is a period of time when they think
I'm out of my mind.
What is everyone elses experience? This is not to say that CMP is not
relevant to enterprise application development, we may just need a
realistic example.
Thanks,
Jim Harrington
Slightly Modified Original Version:
// getters
public ArrayList getAccountsOfCustomer(String customerId)
throws InvalidParameterException, CustomerNotFoundException {
long start = System.currentTimeMillis();
// returns an ArrayList of AccountDetails
// that correspond to the accounts for the specified
// customer
Debug.print("AccountControllerBean getAccountsOfCustomer");
Collection accounts = null;
LocalCustomer customer = null;
if (customerId == null) {
throw new InvalidParameterException("null customerId");
}
try {
customer = customerHome.findByPrimaryKey(customerId);
accounts = customer.getAccounts();
} catch (FinderException ex) {
throw new CustomerNotFoundException();
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
ArrayList rtn = copyAccountsToDetails(accounts);
long stop = System.currentTimeMillis();
System.out.println( "EJB Duration: " + (stop - start));
return rtn;
}
My Highly Altered Version:
private static final String ACCT_LIST =
"SELECT A.ACCOUNT_ID, A.TYPE, A.DESCRIPTION, \n" +
" A.BALANCE, A.CREDIT_LINE, A.BEGIN_BALANCE, \n" +
" A.BEGIN_BALANCE_TIME_STAMP \n" +
"FROM ACCOUNT A \n" +
" INNER JOIN CUSTOMER_ACCOUNT_XREF C \n" +
" ON ( C.ACCOUNT_ID = A.ACCOUNT_ID ) \n" +
"WHERE C.CUSTOMER_ID = ?";
// getters
public ArrayList getAccountsOfCustomer(String customerId)
throws InvalidParameterException, CustomerNotFoundException
{
// returns an ArrayList of AccountDetails
// that correspond to the accounts for the specified
// customer
Debug.print("AccountControllerBean getAccountsOfCustomer");
long start = System.currentTimeMillis();
ArrayList accounts = new ArrayList();
if (customerId == null) {
throw new InvalidParameterException("null customerId");
}
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
conn = ConnectionFactory.getConnection();
pstmt = conn.prepareStatement( ACCT_LIST );
pstmt.setString( 1, customerId );
rs = pstmt.executeQuery();
while( rs.next() )
{
AccountDetails details =
new AccountDetails( rs.getString( 1 ),
rs.getString( 2 ),
rs.getString( 3 ),
rs.getBigDecimal( 4 ),
rs.getBigDecimal( 5 ),
rs.getBigDecimal( 6 ),
rs.getDate( 7 ));
accounts.add( details );
}
}
catch( Throwable e )
{
e.printStackTrace();
}
finally
{
DBUtil.close( rs );
DBUtil.close( pstmt );
ConnectionFactory.releaseConnection( conn );
}
long stop = System.currentTimeMillis();
System.out.println( "JDBC Lookup Time: " + (stop - start));
return accounts;
}