Sun Java Solaris Communities My SDN Account Join SDN
 
J2EE

Sun Java Center J2EE Patterns

 

Data Access Object

Context

Access to data varies depending on the source of the data. Access to persistent storage, such as to a database, varies greatly depending on the type of storage (RDBMS, OODBMS, flat files, and so forth) and the vendor implementation.

Problem

Many real-world J2EETM applications need to use persistent data at some point. For many applications, the persistent storage is implemented with different mechanisms, and there are marked differences in the APIs used to access these different persistent storage mechanisms. Other applications may need to access data that resides on a different system. For example, the data may reside on a mainframe, an LDAP repository, a B2B service, a credit card bureau, and so forth.

Typically, applications use persistent shared distributed components such as entity beans to represent persistent data. An application is considered to employ bean-managed persistence for its entity beans when these entity beans explicitly access the persistent storage-that is, the entity bean includes code to directly access the persistent storage. An application with simpler requirements may forego using entity beans and instead, use session beans or servlets to directly access the persistent storage to retrieve and modify the data.

Applications can use the JDBCTM API to access data residing in an RDBMS. The JDBC API enables standard access and manipulation of data in a persistent storage, such as a relational database. JDBC enables J2EE applications to use SQL statements, which are the standard means for accessing RDBMS tables. However, even within an RDBMS environment, the actual syntax and format of the SQL statements may vary depending on the particular database product.

There is even greater variation with different types of persistent storage. Access mechanisms, supported APIs, and features vary drastically when comparing a relational type of persistent storage such as RDBMS to other types of persistent stores, such as Object Oriented Databases (OODBMS), file system-based ISAM databases, or simply flat files. Applications that need to access data from a legacy or disparate system (for example, a mainframe, CORBA service or B2B service) are often required to use APIs that may be proprietary. Such disparate data sources offer challenges to the application and can potentially create a tight integration between application code and integration code. When business components-entity beans, session beans and even presentation components like servlets and JSPTM)-need to access a data source, they can use the appropriate API to achieve connectivity and manipulate the data source. But, including the connectivity and data access code within these components introduces a tight coupling between the components and the data source implementation. Such code dependencies in the components makes it difficult and tedious to migrate the application from one type of data source to another. When the data source changes, the components need to be changed to handle the new type of data source.

Forces

  • Components such as bean-managed entity beans, session beans and servlets/JSP need to retrieve and store information from persistent stores and other data sources like legacy systems, B2B, LDAP, and so forth.
  • Persistent storage APIs vary depending on the product vendor. Other data sources may have APIs that are non-standard and/or proprietary. These APIs and their capabilities also vary depending on the storage type (RDBMS, OODBMS, XML documents, flat files, and so forth). There is a lack of uniform APIs to address the requirements to access such disparate systems.
  • Components accessing legacy systems to retrieve and store data is typically done using proprietary APIs.
  • Portability of the components is directly affected when specific access mechanisms and APIs are included in the components.
  • Components need to be transparent to the actual persistent store or data source implementation to provide easy migration to different vendor products, different storage types, and different data source types.

Solution

Use a Data Access Object to abstract and encapsulate all access to the data source. The Data Access Object manages the connection with the data source to obtain and store data.

The Data Access Object (DAO) is the primary object of this pattern. The DAO implements the access mechanism required to work with the data source. The data source could be a persistent store like an RDBMS, an external service like a B2B exchange, a repository like an LDAP database or a business service accessed via CORBA IIOP or low-level sockets. The business component that relies on the DAO object uses the simpler interface exposed by the DAO for its clients. The DAO completely hides the data source implementation details from its clients. Because the interface exposed by the DAO to clients does not change when the underlying data source implementation changes, this pattern allows the DAO to adapt to different storage schemes without affecting its clients or business components. Essentially, the DAO acts as an adapter between the component and the data source.

Structure

The following class diagram represents the relationships for the Data Access Object pattern.

click to enlarge

 

Participants & Responsibilities

The following sequence diagram shows the interaction between the various participants in this pattern.

 

 

BusinessObject
The BusinessObject represents the client and is the object that requires access to the data source to obtain and store data. A BusinessObject may be implemented as a session bean, entity bean, or some other Java object, including a servlet or helper (or worker) bean that accesses the data source.

DataAccessObject (DAO)
The DAO is the primary object of this pattern. It provides the encapsulation and delegation features to the BusinessObject. The DAO abstracts the underlying data access implementation for the BusinessObject to enable transparent access to the data source. The BusinessObject also delegates loading and storing data operations to the DAO.

DataSource
This represents a data source implementation. A data source could be a database such as an RDBMS, OODBMS, XML repository, flat file system, and so forth. A data source can also be another system (legacy/mainframe), or service (B2B service or credit card bureau), or some kind of repository (LDAP).
 

Strategies

Automatic DAO Code Generation Tools

Since each BusinessObject corresponds to a specific DAO object, it is possible to establish relationships between the BusinessObject, DAO, and the underlying implementation (such as the tables in an RDBMS). Once the relationships are established it is possible to write a simple application-specific code generation utility that generates the code for all DAOs required by the application. The meta-data to generate the DAO can come from a developer-defined descriptor file. Or, the code generator can automatically introspect the database and provide the necessary DAOs to access the database. If the requirements for DAOs are sufficiently complex, consider using third party tools that provide Object-to-Relational mapping for RDBMS databases. These tools typically include GUI tools to map the BusinessObjects to the persistent storage objects and thereby define the intermediary data access objects. The tools automatically generate the code once the mapping is complete and may provide other value-added features such as results caching, query caching, integration with application servers, integration with other third party products (distributed caching), and so forth.

Factory for Data Access Object

The DAO pattern can be made highly flexible by adopting the Abstract Factory and the Factory Method patterns. (See related patterns.) This strategy provides a DAO factory object that can construct various types of DAO factories, each factory supporting a different type of persistent storage implementation. Once you obtain the DAO factory for a specific implementation, you use it to produce DAOs supported and implemented in that implementation (CustomerDAO, AccountDAO, and so forth). The following class diagram for this strategy shows the DAO factory as a base class from which different DAO factories inherit and implement specific storage access mechanisms to different implementations (for example, RdbDAOFactory to access an RDBMS such as Oracle, XmlDAOFactory to access an XML repository, and so on). Then, use a specific DAO factory such as RdbDAOFactory to obtain specific DAOs that support the business objects (for example, DAO1, DAO2, and so forth). This is similar to obtaining a CustomerDAO for a CustomerBusinessObject, an AccountDAO for an AccountBusinessObject, and so on. Each DAO is responsible for connecting to the data source, and obtaining and manipulating data for the business object it supports.

 

 

 

The following sequence diagram shows the interactions for this strategy:

 

click to enlarge

 

 

Consequences

  • Enables transparency: Business objects can use the data source without knowing the specific details of the data source's implementation. Access is transparent because the implementation details are hidden inside the Data Access Object.
  • Enables easier migration to different persistent storage implementation: A layer of Data Access Objects makes it easier for an application to migrate to a different database implementation. The business objects have no knowledge of the underlying data implementation. Thus, the migration involves changes only to the data access object layer. Further, if employing the factory strategy, it is possible to provide a concrete factory implementation for each underlying storage implementation. In this case, migrating to a different storage implementation means providing a new factory implementation to the application.
  • Reduces code complexity in business objects: Because the Data Access Objects manage all the data access complexities, it simplifies the code in the business objects that use the data access objects. All implementation-related code (such as SQL statements) is coded in the DAO and not in the business object. This improves code readability and development productivity. 
  • Centralizes all data access into a separate layer: Because all data access operations are now delegated to the data access objects, the separate data access layer can be viewed as the layer that can isolate the rest of the application from the data access implementation. This centralization makes the application easier to maintain and manage.
  • Not useful for entity beans with container-managed persistence: Because the EJB container manages entity beans with container-managed persistence, the container automatically services all persistent storage access. Applications using container-managed entity beans do not need a data access objects layer since the application server transparently provides this functionality.

 

Related Patterns

  • Abstract Factory [GoF]: The factory for data access object strategy is based on the abstract factory method.

(c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.

Version 1.0 Beta