In this chapter we've surveyed some of the most effective data-access approaches for J2EE apps. We've considered:

All the approaches discussed in this chapter can be used in either the EJB container or web container of a J2EE app server. They can also easily be tested outside a J2EE app server: an important consideration, as we saw in . We can use any of these strategies in entity beans with BMP, but, as we have seen, BMP is unusable in many cases and imposes a complex, prescriptive model that delivers little or no benefit. We concluded that a SQL-based approach using JDBC was most appropriate for our sample app, as it could not benefit significantly from caching in an O/R mapping layer, and because we saw in that we can make effective use of stored procedures to move some of its persistence logic into the RDBMS. However, as we don't want our app's design to be dependent on use of an RDBMS, we chose to use the DAO pattern to conceal the use of JDBC behind an abstraction layer of persistent-store-independent interfaces. As the sample app will use JDBC, we took a closer look at the JDBC API. We saw the importance (and difficulty) of correct error handling, how to extract information about the cause of a problem from a javax.sql.SQLException, and the pros and cons of JDBC PreparedStatements and Statements. We concluded that using the JDBC API directly isn't a viable option, as it requires too much code to be written to accomplish each task in the database. Thus we need a higher level of abstraction than the JDBC API provides, even if we don't want to use an O/R mapping framework. We examined the implementation of a generic JDBC abstraction framework, which delivers such a higher level of abstraction. We use this framework in the sample app, and it can be used in any app working with JDBC. This framework offers two levels of abstraction:

Another important benefit of our abstraction framework is that it enables code using it to work with a generic hierarchy of data-access exceptions, rather than JDBC SQLExceptions. This ensures that business objects never depend on JDBC-specific concepts. As all data access exceptions are runtime, rather than checked exceptions, app code is greatly simplified by being able to ignore unrecoverable exceptions. (JDO illustrates the effectiveness of this approach.) We looked at how the sample app implements the DAO pattern using our JDBC abstraction framework. Using the abstraction framework enables us to write much simpler code than would have been required making direct use of JDBC. Using the DAO pattern enables us to use proprietary features of the Oracle target database without making our app's overall design dependent on Oracle, or even relational concepts. In this case the use of proprietary features is justified as it enables us to use efficient RDBMS constructs, and use PL/SQL stored procedures to handle persistence logic that would be much harder to implement in Java code. This concludes our examination of data access in J2EE apps.

In the next chapter we'll look at effective use of session EJBs.