Search the Catalog
Database Programming with JDBC and Java

Database Programming with JDBC and Java

By George Reese
1st Edition June 1997
1-56592-270-0, Order Number: 2700
240 pages, $29.95

Chapter 4.
Database Access Through JDBC

In this chapter:
What Is JDBC?
Connecting to the Database
Basic Database Access
The JDBC Support Classes

These common thoughts are expressed in a shared public language, consisting of shared signs ... a sign has a "sense" that fixes the reference and is "grasped by everybody" who knows the language...Noam ChomskyLanguage and Thought

Database programming has traditionally been a technological Tower of Babel. We are faced with dozens of available database products, and each one talks to our applications in its own private language. If your application needs to talk to a new database engine, you have to teach it (and yourself) a new language. As Java programmers, however, we should not be worrying about such translation issues. Java is supposed to bring us the ability to "write once, compile once, and run anywhere," so it should bring it to us with database programming as well.

Java's JDBC API gives us a shared language through which our applications can talk to database engines. Following in the tradition of its other multi-platform APIs such as the AWT, JDBC provides us with a set of interfaces that create a common point at which database applications and database engines can meet. In this chapter, we will discuss the basic interfaces that JDBC provides.

What Is JDBC?

Working with leaders in the database field, JavaSoft developed a single API for database access--JDBC. As part of this process, they kept three main goals in mind:

An SQL-level API means that JDBC allows us to construct SQL statements and embed them inside Java API calls. In short, you are basically using SQL. But JDBC lets you smoothly translate between the world of the database and the world of the Java application. Your results from the database, for instance, are returned as Java variables, and access problems get thrown as exceptions. Later on in the book, we go a step further and talk about how we can completely hide the existence of the database from a Java application using a database class library.

Because of the confusion caused by the proliferation of proprietary database access APIs, the idea of a universal database access API to solve this problem is not a new one. In fact, JavaSoft drew upon the successful aspects of one such API, Open DataBase Connectivity (ODBC). ODBC was developed to create a single standard for database access in the Windows environment. Although the industry has accepted ODBC as the primary means of talking to databases in Windows, it does not translate well into the Java world. First of all, ODBC is a C API that requires intermediate APIs for other languages. But even for C developers, ODBC has suffered from an overly complex design that has made its transition outside of the controlled Windows environment a failure. ODBC's complexity arises from the fact that complex, uncommon tasks are wrapped up in the API with its simpler and more common functionality. In other words, in order for you to understand a little of ODBC, you have to understand a lot.

In addition to ODBC, JDBC is heavily influenced by existing database programming APIs such as X/OPEN SQL Call Level Interface. JavaSoft wanted to re-use the key abstractions from these APIs, which would ease acceptance by database vendors and capitalize on the existing knowledge capital of ODBC and SQL CLI developers. In addition, JavaSoft also realized that deriving an API from existing ones can provide quick development of solutions for database engines that support the old protocols. Specifically, JavaSoft worked in parallel with Intersolv to create an ODBC bridge that maps JDBC calls to ODBC calls, thus giving Java applications access to any database management system (DBMS) that supports ODBC.

JDBC attempts to remain as simple as possible while providing developers with maximum flexibility. A key criterion employed by JavaSoft is simply asking whether database access applications read well. The simple and common tasks use simple interfaces, while more uncommon or bizarre tasks are enabled through extra interfaces. For example, three interfaces handle a vast majority of database access. JDBC nevertheless provides several other interfaces for handling more complex and unusual tasks.

The Structure of JDBC

JDBC accomplishes its goals through a set of Java interfaces, each implemented differently by individual vendors. The set of classes that implement the JDBC interfaces for a particular database engine is called a JDBC driver. In building a database application, you do not have to think about the implementation of these underlying classes at all; the whole point of JDBC is to hide the specifics of each database and let you worry about just your application. Figure 4-1 shows the JDBC classes and interfaces.

Figure 4-1. The classes and interfaces of java.sql, the JDBC API package

 

If you think about a database query for any database engine, it requires you to connect to the database, issue your SELECT statement, and process the result set. In Example 4-1, we have the full code listing for a simple SELECT application from the Imaginary JDBC Driver for mSQL.[1] I wrote this driver for the Center for Imaginary Environments (http://www.imaginary.com), which is a non-commercial organization that promotes the development of virtual environment technologies like muds. This application is a single class that gets all of the rows from a table in an mSQL database located on my Sun box. First, it connects to the database by getting a database connection under my user id, borg, from the JDBC DriverManager class. It uses that database connection to create a Statement object that performs the SELECT query. A ResultSet object then provides the application with the key and val fields from the t_test table.

Example 4-1: A Simple SELECT Application from the Imaginary JDBC Implementation for mSQL

import java.sql.*;
 
public class SelectApp {
  public static void main(String args[]) {
    String url = "jdbc:msql://athens.imaginary.com:4333/db_web";
 
    try {
      Class.forName("imaginary.sql.iMsqlDriver");
    }
    catch( Exception e ) {
      System.out.println("Failed to load mSQL driver.");
      return;
    }
    try {
      Connection con = DriverManager.getConnection(url, "borg", "");
      Statement select = con.createStatement();
      ResultSet result = select.executeQuery
                          ("SELECT key, val FROM t_test");         
 
      System.out.println("Got results:");
      while(result.next()) { // process results one row at a time
        int key = result.getInt(1);
        String val = result.getString(2);
 
        System.out.println("key = " + key);
        System.out.println("val = " + val);
      }
      select.close();
      con.close();
    }
    catch( Exception e ) {
      e.printStackTrace();
    }
  }
}

If you already have Java experience, then you should be able to understand the flow of the code in Example 4-1 without knowing any JDBC. There are no references to specific database engine classes. Instead, the code simply uses JDBC interfaces to provide a facade for the DBMS-specific implementation. The JDBC implementation, in turn, performs the actual database access somewhere behind the scenes.

In this simple application, the SelectApp class asks the JDBC DriverManager to hand it the proper database implementation based on a database URL. The database URL looks similar to other Internet URLs. The actual content of the URL is loosely specified as jdbc:subprotocol:subname. The subprotocol identifies which driver to use, and the subname provides the driver with any required connection information. For the Imaginary JDBC Implementation for mSQL that I used in testing the above example, the URL is jdbc:msql://athens.imaginary.com:4333/db_web. In other words, this URL says to use the mSQL JDBC driver to connect to the database db_web on the server running at port 4333 on athens.imaginary.com. Each URL, however, is specific to the JDBC implementation being sought, and so I can't say anything more explicit about it. Whatever its format, the primary function of a database URL is to uniquely identify the implementation needed by the application and pass that implementation any information it needs in order to connect to the proper database.

Databases and Drivers

In putting together the examples in this book, I used both an mSQL database for the simple Chapter 4 examples and an Oracle database for the more complex examples of Chapter 5. If you do not have a corporate pocketbook to back up your database purchase, mSQL is probably the most feasible solution. You should keep in mind, however, that mSQL does not allow you to abort transactions and does not support the stored procedures used in Chapter 5. Whatever your database choice, you must set up your database engine, create a database, and create the tables shown in the Chapter 3 data model before you can begin writing JDBC code.

Once your database engine is installed and your database is all set up, you will need a JDBC driver for that database engine. You can find an mSQL JDBC driver at http://www.imaginary.com/Java. The more commercial database engines like Oracle have commercial JDBC drivers. Most of them, however, allow you to have a free trial period for experimenting with the driver. Follow the install instructions for the driver you choose, and remember that some JDBC drivers require to you install native code on client machines. To help you understand what different drivers require, JavaSoft has defined the following driver categorization system:

type 1
These drivers use a bridging technology to access a database. The JDBC-ODBC bridge that comes with the JDK 1.1 is a good example of this kind of driver. It provides a gateway to the ODBC API. Implementations of that API in turn do the actual database access. Bridge solutions generally require software to be installed on client systems, meaning that they are not good solutions for applications that do not allow you to install software on the client.

type 2
The type 2 drivers are native API drivers. This means that the driver contains Java code that calls native C or C++ methods provided by the individual database vendors that perform the database access. Again, this solution requires software on the client system.

type 3
Type 3 drivers provide a client with a generic network API that is then translated into database specific access at the server level. In other words, the JDBC driver on the client uses sockets to call a middleware application on the server that translates the client requests into an API specific to the desired driver. As it turns out, this kind of driver is extremely flexible since it requires no code installed on the client and a single driver can actually provide access to multiple databases.

type 4
Using network protocols built into the database engine, type 4 drivers talk directly to the database using Java sockets. This is the most direct pure Java solution. In nearly every case, this type of driver will come only from the database vendor.

Table 4-1 lists the driver vendors that were public at the time of this book's publication. See http://splash.javasoft.com/jdbc/jdbc.vendors.html for a current list of JDBC vendors.

Table 4-1: A List of JDBC Driver Vendors

Vendor

Type

Supported Databases

Agave Software Design

3

Oracle, Sybase, Informix, ODBC supported databases

Asgard Software

3

Unisys A series DMSII database

Borland

4

InterBase 4.0

Caribou Lake Software

3

CA-Ingres

Center for Imaginary Environments

4

mSQL

Connect Software

4

Sybase, MS SQL Server

DataRamp

3

ODBC supported databases

IBM

2/3

IBM DB2 Version 2

IDS Software

3

Oracle, Sybase, MS SQL Server, MS Access, Informix, Watcom, ODBC supported databases

InterSoft

3

Essentia

Intersolv

2

Oracle, Sybase

JavaSoft

1

ODBC supported databases

OpenLink

3

CA-Ingres, Postgres95, Progress, Unify

SAS

4

SAS, and via SAS/ACCESS, Oracle, Informix, Ingres, and ADABAS

SCO

3

Informix, Oracle, Ingres, Sybase, Interbase

StormCloud Development

3

ODBC supported databases

Sybase

3/4

Sybase SQL Server, SQL Anywhere, Sybase IQ, Replication Server

Symantec

3

Oracle, Sybase, MS SQL Server, MS Access, Watcom, ODBC supported databases

Visigenic

3

ODBC supported databases

WebLogic

2/3

Oracle, Sybase, MS SQL Server/ODBC supported databases

Alternatives to JDBC

Without JDBC, only disparate, proprietary database access solutions exist. These proprietary solutions force the developer to build a layer of abstraction on top of them in order to create database independent code. Only after that abstraction layer is complete can the developer move to actually writing the application. In addition, the experience you have with that abstraction layer does not translate immediately to other projects or other employers who are almost certainly using their own abstraction layers to provide access to a variety of database engines.

Of course, the ODBC specification exists to provide this universal abstraction layer for languages like C and C++ as well as popular development tools such as Delphi, PowerBuilder, and VisualBasic. Unfortunately, ODBC does not enjoy the platform independence of Java. Using the JDBC interface design, however, your server application can pick the database at runtime based on which client is connecting. The ATM front-end of the banking application, for example, could have some legacy data stored in an Oracle system that is not yet converted to the Informix system against which the rest of the application is running. You write the application without writing special access code for the legacy data. The ATM client just passes the Oracle URL when requesting the connect. Once its data has been converted to Informix, all you have to do to switch the application to the new database is tell the ATM machine about the new database URL. No new code needs to be written for the migration.

Connecting to the Database

Now I am going to dive into the details about JDBC calls and how to use them. Any JDBC application we write needs to be able to run from start to finish without ever referencing a specific JDBC implementation. Figure 4-2 shows how an application uses JDBC to talk to one or more databases without knowing any of the details concerning the driver implementation for that database. An application uses JDBC as an interface through which it passes all of its databases requests.

Figure 4-2. JDBC shields an application from the specifics of individual database implementations

 

When you write a Java database applet or application, the only driver-specific information JDBC requires from you is the database URL. You can even build your application so that it derives the URL at runtime--based on user input or applet parameters.

Using the database URL, a user name, and password, your application will first requests a java.sql.Connection implementation from the DriverManager. The DriverManager in turn will search through all of the known java.sql.Driver implementations for one that will connect with the URL you provided. If it exhausts all of the implementations without finding a match, it throws an exception back to your application.

Once a Driver recognizes your URL, it creates a database connection using the user name and password you specified. It then provides the DriverManager with a java.sql.Connection implementation representing that database connection. The DriverManager then passes that Connection object back to the application. In your code, the entire database connection process is handled by this one-liner:

Connection con = DriverManager.getConnection(url, uid, password);

Of course, you are probably wondering just how the JDBC DriverManager learns about a new driver implementation. The DriverManager actually keeps a list of classes that implement the java.sql.Driver interface. Somehow, somewhere, your application needs to load the Driver implementations for any potential database drivers it might require. JDBC requires a Driver class to register itself with the DriverManager when it gets loaded. The very act of loading a Driver class thus enters it in the DriverManager's list. Your only task is thus to determine the somehow and somewhere of loading those Driver implementations. You have several alternatives:

Explicitly call new to load your driver's implementation of Driver
In other words, you hard code the loading of a Driver implementation in your application. This alternative is the least desirable since it requires a rewrite and recompile if your database or database driver changes.

Use the jdbc.drivers property
The DriverManager will load all classes listed in this property automatically. This alternative works well for applications with a command-line interface, but might not be so useful in GUI applications and applets. This is because you can specify properties at the command line or in environment variables. While environment variables do work for GUI applications, you cannot rely on them in Java applets.

Load the class using Class.forName("DriverImplementationClass");
You can use this Java mechanism for loading classes dynamically based on a String with the class name. This static method in the Class class returns the Java class represented by String you pass. A side-effect of this behavior is that the static constructor in that class will be executed. JDBC requires that the static constructor for a Driver implementation load an instance of the Driver. As I said earlier, when you load a Driver, it registers itself with the DriverManager.

I use the third alternative almost exclusively in the examples in this book since it requires no hard-coded class names and runs well in all Java environments.

The JDBC Classes for Creating a Connection

As you can see from the process flow above, JDBC uses one class (java.sql.DriverManager) and two interfaces (java.sql.Driver and java.sql.Connection) for connecting to a database.

java.sql.Driver
Unless you are writing your own custom JDBC implementation, you should never have to deal with this class from your application. It simply gives JDBC a launching point for database connectivity by responding to DriverManager connection requests and providing information about the implementation in question.

java.sql.DriverManager
Unlike most other parts of JDBC, DriverManager is a class instead of an interface. Its main responsibility is to maintain a list of Driver implementations and present an application with one that matches a requested URL. The DriverManager provides registerDriver() and deregisterDriver() methods, which allow a Driver implementation to register itself with the DriverManager or remove itself from that list. You can get an enumeration of registered drivers through the getDrivers() method.

java.sql.Connection
The Connection class represents a single logical database transaction. In other words, you use the Connection class for sending a series of SQL statements to the database and managing the committing or aborting of those statements.

Example 4-2 puts the process of connecting to the database into a more concrete format.

Example 4-2: A Simple Database Connection

package example.sql;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
 
/**
 * The SimpleConnection class is a command line application that accepts 
 * the following command line:
 * java SimpleConnection DRIVER URL UID PASSWORD 
 * If the URL fits the specified driver, it will then load the driver and
 * get a connection.
 */
public class SimpleConnection {
  static public void main(String args[]) {
    Connection connection = null;
 
    // Process the command line
    if( args.length != 4 ) {
      System.out.println("Syntax: java SimpleConnection " +
                         "DRIVER URL UID PASSWORD");
      return;
    }
    try { // load the driver 
      Class.forName(args[0]);
 
 
    }
    catch( Exception e ) { // problem loading driver, class not exist?
      e.printStackTrace();
      return;
    }
    try {
      connection = DriverManager.getConnection(args[1], args[2], args[3]);
      System.out.println("Connection successful!");
      // Do whatever queries or updates you want here!!!
    }
    catch( SQLException e ) {
      e.printStackTrace();
    }
    finally {
        try {
            connection.close();
        }
        catch( SQLException e ) {
            e.printStackTrace();
        }
    }
}

In connecting to the database, this example catches an SQLException. This is a sort of catch-all exception for database errors. Just about any time something goes wrong between JDBC and the database, JDBC throws an SQLException. In addition to the information you commonly find in Java exceptions, SQLException also provides database specific error information, such as the SQLState value and vendor error code. JDBC SQLExceptions may be chained together so that you can find out everything that went wrong with a catastrophic database call.

Basic Database Access

Now that you are connected to the database, you can begin making updates and queries. The most basic kind of database access involves writing JDBC code where you know ahead of time whether the statements you are sending are updates (INSERT, UPDATE, or DELETE) or queries (SELECT). In the next chapter, we will discuss more complex database access that allows you to execute statements of unknown types.

Basic database access starts with the Connection object you created in the previous section. When this object first gets created, it is simply a direct link to the database. You use a Connection object to generate implementations of java.sql.Statement tied to the same database transaction. After you have used one or more Statement objects generated by your Connection, you can use it to commit or rollback the Statement objects associated with that Connection.

A Statement is very much what its name implies--an SQL statement. Once you get a Statement object from a Connection, you have what amounts to a blank check that you can write against the transaction represented by that Connection. You do not actually assign SQL to the Statement until you are ready to send the SQL to the database.

This is where it becomes important to know what type of SQL you are sending to the database, because JDBC uses a different method for sending queries than for sending updates. The key difference is the fact that the method for queries returns an instance of java.sql.ResultSet while the method for non-queries returns an integer. A ResultSet provides you with access to the data retrieved by a query.

Basic JDBC Database Access Classes

java.sql.Statement
The Statement class is the most basic of three JDBC classes representing SQL statements. It performs all of the basic SQL statements we have discussed so far. In general, a simple database transaction uses only one of the three statement execution methods in the Statement class. The first such method, executeQuery(), takes an SQL String as an argument and returns a ResultSet object. This method should be used for any SQL calls that expect to return data from the database. Update statements, on the other hand, are executed using the executeUpdate() method. This method returns the number of affected rows.

Finally, the Statement class provides an execute() method for situations in which you do not know whether the SQL being executed is a query or update. This usually happens when the application is executing dynamically created SQL statements. If the statement returns a row from the database, the method returns true. Otherwise it returns false. The application can then use the getResultSet() method to get the returned row.

java.sql.ResultSet
A ResultSet is a row of data returned by a database query. The class simply provides a series of methods for retrieving columns from the results of a database query. The methods for getting a column all take the form:

type get type(int | String)

where the argument represents either the column number or column name desired. A nice side effect of this design is that you can store values in the database as one type and retrieve them as a completely different type. For example, if you need a Date from the database as a String, you can get it as a String by calling result_set.getString(1) instead of calling result_set.getDate(1).

Because the ResultSet class handles only a single row from the database at any given time, the class provides the next() method for making it reference the next row of a result set. If next() returns true, you have another row to process and any subsequent calls you make to the ResultSet object will be in reference to that next row. If there are no rows left, it returns false.

Please note that ResultSet objects allow only one-way navigation through rows from a query--there is no previous() counterpart to the next() method. JavaSoft is considering the addition of a RowSet class for Java 1.2 that will allow you to scroll through result sets in a manner similar to database cursors.

Clean Up

In the examples provided so far, you may have noticed many of the objects being closed through a close() method. The Connection, Statement, and ResultSet classes all have close(). A given JDBC implementation may or may not require you to close these objects before reusing. But some might, since they likely are holding precious database resources. It is therefore always a good idea to close any instance of the above objects when you are done with them. If you do manage to close a Connection before committing with auto-commit off, any uncommitted transactions will be lost.

Modifying the Database

In Example 4-1, we used JDBC to perform a simple SELECT query. Of course, we cannot really retrieve data from the database before we have put it there. Example 4-3 shows the simple UpdateApp class supplied with the Imaginary JDBC Implementation for mSQL.

Example 4-3: UpdateApp from the Imaginary JDBC Implementation for mSQL

import java.sql.*;
  
class UpdateApp {
  public static void main(String args[]) {
    Connection connection = null;
 
    if( args.length != 2 ) {
      System.out.println("Syntax: <java UpdateApp [number] [string]>");
      return;
    }
    try {
      Class.forName("imaginary.sql.iMsqlDriver");
      String url = "jdbc:msql://athens.imaginary.com:4333/Testdb";
      con = DriverManager.getConnection(url, "borg", "");
      Statement s = con.createStatement();
      String test_id = args[0];
      String test_val = args[1];
      int update_count = 
        s.executeUpdate("INSERT INTO t_test (test_id, test_val) " +
                        "VALUES(" + test_id + ", '" + test_val + "')");
 
      System.out.println(update_count + " rows inserted.");
      s.close();
    }
    catch( Exception e ) {
      e.printStackTrace();
    }
    finally {
       try { con.close(); }
       catch( SQLException e ) { e.printStackTrace(); }
    }
  }
}

Again, making a database call is nothing more than creating a Statement and passing it SQL via one of its execute methods. Unlike executeQuery(), however, executeUpdate() does not return a ResultSet (you should not be expecting any results). Instead, it returns the number of rows affected by the UPDATE, INSERT, or DELETE.

By default, JDBC commits each SQL statement as it is sent to the database; this is called autocommit. However, for more robust error handling, you can set up a Connection object so it issues a series of changes that have no effect on the database until you expressly send a commit. Each Connection is separate, and a commit on one has no effect on the statements on the other. The Connection class provides the setAutoCommit() method so you can turn autocommit off. Example 4-4 shows a simple application that turns autocommit off and commits two statements together or not at all.

Example 4-4: UpdateLogic Application That Commits Two Updates Together

import java.sql.*;
  
class UpdateLogic {
  public static void main(String args[]) {
    Connection connection = null;
 
    if( args.length != 2 ) {
      System.out.println("Syntax: <java UpdateLogic [number] [string]>");
      return;
    }
    try {
      Class.forName("imaginary.sql.iMsqlDriver");
      String url = "jdbc:msql://athens.imaginary.com:4333/db_test";
      Statement s;
 
      con = DriverManager.getConnection(url, "borg", "");
      con.setAutoCommit(false);     // make sure auto commit is off!
      s = con.createStatement();    // create the first statement
      s.executeUpdate("INSERT INTO t_test (test_id, test_val) " +
                      "VALUES(" + args[0] + ", '" + args[1] + "')");
      s.close();                    // close the first statement
      s = con.createStatement();    // create the second statement
      s.executeUpdate("INSERT into t_test_desc (test_id, test_desc) " +
                      "VALUES(" + args[0] + 
                      ", `This describes the test.')");
      con.commit();                 // commit the two statements
      System.out.println("Insert succeeded.");
      s.close();                    // close the second statement
    }
    catch( SQLException e ) {
      if( con != null ) {
        try { con.rollback(); }        // rollback on error 
        catch( SQLException e ) { }
      }
      e.printStackTrace();
    }
    finally {
      try { con.close(); }
      catch( SQLException e ) { e.printStackTrace(); }
    }
  }
}

The JDBC Support Classes

JDBC provides a handful of other classes and interfaces that support JDBC's core functionality. Many of them are more SQL-friendly extensions of java.util classes like java.sql.Date and java.sql.Numeric. Others are exception classes that get thrown by JDBC calls.

java.sql.Types

The Types class provides constants that identify SQL data types. Each constant that represents an SQL data type that is mapped to an integer is defined by the XOPEN SQL specification. You will see this class used extensively in the next chapter.

java.sql.SQLException

The SQLException class extends the general java.lang.Exception class that provides extra information about a database error. The information provided by a SQLException includes:

java.sql.SQLWarning and java.sql.DataTruncation

Depending on the driver you are using, non-fatal errors might occur that should not halt application processing. JDBC provides an extension to the SQLException class called SQLWarning. When a JDBC object--like a ResultSet--encounters a warning situation internally, it creates an SQLWarning object and adds it to a list of warnings that it keeps. At any point, you can get the warnings for any JDBC object by repeatedly calling the getWarnings() method until it returns null.

The DataTruncation class is a special kind of warning that a JDBC implementation throws when JDBC unexpectedly truncates a data value. A DataTruncation object is chained as a warning on a read operation and thrown as an exception on a write.

java.sql.Date, java.sql.Time, and java.sql.Timestamp

Portable date handling among database engines can be very complex--each relational database management system (RDBMS) seems to have its own unique way of representing date information. These three classes all extend the functionality of other Java objects to provide a portable representation of their SQL counterparts. The Date and Time classes represent different levels of granularity as well as different means of expressing information already found in the java.util.Date class. The java.sql.Date class, for example, provides methods to express just the date, month, and year, while the Time class works in terms of hours, minutes, and seconds. And finally the Timestamp class takes the java.util.Date class down to nanosecond granularity.

java.sql.DriverPropertyInfo

I can almost guarantee that you will never use this class. It is designed for Rapid Application Development (RAD) tools like Symantec VisualCafe and Borland JBuilder. In order to provide a graphical user interface for rapid prototyping, these tools need to know what properties are required by a given JDBC implementation in order to connect to the database. Most drivers, for example, need to know the user name and password of the user connecting to the database. That and anything else the driver needs in order to connect to the database will be returned as an array of DriverPropertyInfo objects from the java.sql. Driver getPropertyInfo() method. Development tools can call this method to find out what information they should prompt the user for before connecting to the database.


1. mSQL stands for Mini-SQL. It is a small database that supports a subset of SQL and is ideal for systems that need a database that can operate with few system resources. You can get more information on it at http://Hughes.com.au.

Back to: Database Programming with JDBC and Java


O'Reilly Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies

© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com