1209-1211

Previous Table of Contents Next

Page 1209

Advanced JDBC Application Design

To this point, the focus of this chapter was the JDBC API and issues related to deploying JDBC applications. However, designing and developing a real-world JDBC application typically involves more than writing a few classes that make JDBC calls. The following sections attempt to fill in the gaps by shifting the focus to some high-level design issues and some low-level programming issues relevant to the development of large-scale JDBC applications.

Performance Considerations and Multithreading

Obviously, hardware, the RDBMS, the database design, and network traffic have as much to do with a JDBC application's performance as how the API is used. However, performance is often measured in terms of the client application first, so it pays to optimize. You can employ a number of general design strategies to ensure that a JDBC application is reasonably optimized.

Minimize server round-trips. This is primarily a matter of selecting the right driver and understanding exactly how it works. For the sake of example, assume that you are considering a thin client driver that has separate client and server components. Examine the set() and get() methods closely. If a message is sent to the server each time one of these methods is called, the driver talks too much. Most drivers of this type delay the calls resulting from set() messages until execute() is called and retrieve all column values from the server when next() is called for a result set. This technique reduces messages between the client and server components , which can enhance performance considerably. Once you understand the driver's operation, you can optimize an application for the driver. For example, direct execution of dynamically generated DML might provide better performance than prepared execution for "chatty" drivers. When an application must support many different drivers, a more generic approach is required. For example, if an application displays small lists that are read from relatively static tables, consider reading the table once and buffering the results in the client application. In general, any technique that reduces the amount of messaging (and data transfer) between the client and server will improve application performance.

Let the database do as much work as possible. You can accomplish this using views and stored procedures, which can have a dramatic impact on performance in some cases. Stored procedures and views result in pre-bound access plans, which reduce the time spent by the RDBMS parsing and selecting access plans for SQL queries and DML operations. Transactions involving multiple DML statements can be encapsulated in stored procedures. This minimizes executions and eliminates the need for transaction control in the client. Complex joins, unions, and subqueries can be encapsulated in views, simplifying SQL access from the client and reducing data transfer.

If your application is designed for a specific RDBMS, take advantage of the RDBMS and driver-specific features. For example, some Oracle drivers support bind arrays and block fetches. This lets you use arrays of parameters in a single execution for a prepared statement and read multiple rows from the server in a single call to next().

Page 1210

You can creatively use buffers, queues, and multithreading to improve perceived performance. For example, you can use multiple threads to begin populating a grid with a result set while reading additional rows from the server on another thread. It might be useful to run complex queries on a separate thread for decision support applications, queue transactions for batch processing in sales force automation applications, and so on.

You must take special care when using multiple threads in JDBC applications. Obviously, the driver must be thread-safe. Multithreaded applications using the JDBC-ODBC bridge to access an ODBC driver must take additional precautions to avoid deadlock. The bridge driver synchronizes ODBC access, which ensures thread safety but limits concurrency. In most cases, the JDBC driver is not an issue, but in any case, the use of multiple threads adds complexity to the design. Regardless of the driver implementation, the rollback() and commit() methods of the Connection interface apply to all statements opened from the connection. As a result, applying DML transactions in multithreaded applications can be extremely dangerous. It is generally much safer to use a separate Connection for each thread. This simplifies Connection-related exception handling and allows an application to safely manage transactions. All other issues related to synchronization and messaging between threads in Java apply equally to JDBC applications.

The very nature of JDBC precludes it from being well-optimized for a specific database or driver. In addition to providing a standard API, it is intended to allow the development of database client applications that are platform, RDBMS, and driver independent. Developers of applications with portability and compatibility requirements can employ the generic strategies to reach a moderate level of optimization. Due to its ease of use, JDBC is also used in applications that are written to a specific RDBMS with no portability requirements. In these cases, implementing driver- and RDBMS-specific optimizations can provide more substantial performance gains.

Writing a JDBC Driver

Even if you are not a software vendor developing components for commercial release, there are a number of reasons why you might want to develop your own JDBC drivers. If an application will be distributed to a large number of users in different geographical locations, per-seat or per-server licensing can be expensive, so it might be more cost effective to develop drivers in-house. Owning the driver source code has additional benefits. This might come as a shock to some readers, but even the most well-respected vendors might have bugs in their production releases. Reliance on third parties for bug fixes and enhancements can cause delays in the development cycle. In some cases, reduced dependency on third-party vendors can minimize upgrade costs, compatibility problems, and turnaround time for bug fixes and driver enhancements. JDBC driver development is definitely not for everyone, but ownership can pay dividends for individuals and organizations with adequate design and development skills.

Page 1211

JDBC-Native Interface Mapping

Most native interface libraries (including the Oracle Call Interface) provide interfaces for C and other procedural third-generation languages. Java, however, is highly object oriented, so the JDBC driver must map the object-oriented interface of JDBC to procedural API calls. This mapping is an important step in the design process. OCI, for example, is based largely on structures related to connections and cursors . The mapping for the Java Connection interface is obvious, but a JDBC-compliant driver must also map the Statement, CallableStatement, and PreparedStatement interfaces to a single set of OCI cursor operations. It might be desirable to wrap OCI in C++ classes that correspond to JDBC interfaces as an initial step in designing the driver, following the JDBC hierarchy as closely as possible. (Native interface libraries often rely heavily on the use of pointers, so regardless of the desired client component of the driver, it might be necessary to implement part of the driver in a natively compiled dynamic link library. A combination of C and C++ is typically the most convenient implementation of the native portion of the driver.)

Drivers requiring native code are often designed in several layers , only one of which is implemented in Java. At the lowest level, a set of C++ classes wraps the native interface. A second layer of C code in the native library manages instances of the C++ classes and assigns unique identifiers to object references to be used in the Java layer. A third layer exports functions using Pascal calling conventions, making them accessible to the Java layer. The exported functions typically use the object management layer to construct C++ objects and return identifiers to Java, access specific C++ object references by identifier and invoke methods on the object, and delete C++ objects that are no longer in use. A Java layer implements the JDBC interfaces and communicates with the database through the functions exported by the native library. You can also design this layer as a server component to be accessed via RMI, IIOP, or some other network protocol. In this case, you can develop a pure Java client component, making up an additional logical layer of the driver.

Drivers with separate client and server components might consider different mapping strategies for optimization or convenience. In any case, the highest and lowest levels of the implementation are relatively fixed. At the highest level, Java classes implement the JDBC interfaces. At the lowest level, the RDBMS native interface communicates with the database. The success of the overall design of a JDBC driver depends largely on the design of one or more intermediate mapping levels, as determined by performance requirements, desired configuration, and other design goals.

JDBC Conformance

As of this writing, there is no official JDBC-compliance certification. However, JavaSoft provides a set of suites that might serve as a certification test in the future. This tool is implemented in distinct components. The JavaSoft harness loads the JDBC classes for the driver being tested ,

Previous Table of Contents Next


Oracle Unleashed
Oracle Development Unleashed (3rd Edition)
ISBN: 0672315750
EAN: 2147483647
Year: 1997
Pages: 391

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net