Richard G Baldwin (512) 223-4758, baldwin@austin.cc.tx.us, http://www2.austin.cc.tx.us/baldwin/

JDBC, Introduction to JDBC and Database Access

Java Programming, Lecture Notes # 660, Revised 2/7/99.

Preface

Introduction

Brief Description of mSQL

Sample Program

Interesting Code Fragments
Program Listing


Preface

Students in Prof. Baldwin's Advanced Java Programming classes at ACC will be responsible for knowing and understanding all of the material in this lesson beginning with the spring semester of 1999.

This lesson was originally written on December 31, 1998. The sample program was tested using the JDK 1.2 download package from JavaSoft along with the Windows version of the database known as mSQL from http://blnet.com/msqlpc/downloads.htm#win. The program was also tested using the JDK 1.2 download package from JavaSoft along with a Linux version of mSQL from http://www.Hughes.com.au/.

In addition, the sample program was tested using the JDK 1.1 download package from JavaSoft along with the Windows version of the mSQL database.

The JDBC interface classes for mSQL for both the JDK 1.1 and the JDK 1.2 versions of the JVM were downloaded from http://www.Imaginary.com/Java/.

This lesson is being provided to introduce you to the use of JDBC for database access in Java. Because of the compatibility between JDBC and servlets, many aspects of JDBC and database access will be presented in the series of lessons on servlets rather than being presented in independent lessons on JDBC.

Introduction

Half the battle in experimenting with JDBC is getting everything set up in the first place. The mSQL database was originally developed for UNIX and has been ported to Windows. As of 12/31/98, the UNIX version was available for downloading from http://www.Hughes.com.au/ and the Windows version was available for downloading from http://blnet.com/msqlpc/downloads.htm#win.

The JDBC interface for JDK 1.1 is significantly different from the JDBC interface for JDK 1.2. As of 12/31/98, both versions of the JDBC interface for mSQL were available for downloading from http://www.Imaginary.com/Java/.

JDBC class files are product specific. If you elect to use some database server other than mSQL, you will need to obtain the JDBC interface class files for that particular database product. Except for possible minor differences in the construction of the SQL statements, the sample program in this lesson should run successfully using any modern SQL database for which JDBC interface class files are available. Just make certain that you match the JDBC class files to your version of the JDK.

Although JDBC capability is available for both JDK 1.1 and JDK 1.2, this lesson will concentrate on the use of JDBC with JDK 1.2. Comments in the listing of the sample program near the end of the lesson also explain how to run it under JDK 1.1.

Brief Description of mSQL

This section is intended to provide a very brief introduction to the use of mSQL. It is strongly recommended that you visit the Hughes URL given above and examine the full User's Guide available at that site. The material in this section is based heavily on that document.

According to the mSQL User's Guide: "Mini SQL, or mSQL as is it often called, is a light-weight relational database management system. It has been designed to provide rapid access to data sets with as little system overhead as possible. The system itself is comprised of a database server and various tools that allow a user or a client application to communicate with the server."

mSQL uses the Structured Query Language (SQL) as its query language. However, it does not provide a complete implementation of the ANSI standard SQL. Several features of SQL that are found in more recent versions of the ANSI standard are not provided by mSQL.

The database engine in mSQL 2.0 has been designed to handle large data sets and to provide consistent and rapid access to data sets having millions of records.

mSQL allows a program to store, manipulate and retrieve data in table structures. It does not support some relational capabilities such as views and nested queries. Although it does not support all the relational operations defined in the ANSI specification, mSQL provides a significant subset of the ANSI SQL standard and is capable of supporting the vast majority of applications.

The data types supported by mSQL for storage in a mSQL database are:

You will see examples of some of these types in the sample program in this lesson.

The following SQL keywords are supported by mSQL. The User's Guide mentioned above provides numerous examples of the use of these keywords in constructing mSQL statements. You will also see simple usage in the sample program in this lesson.

The purpose of this lesson is to teach you how to apply Java JDBC to a SQL database for the manipulation of the data in the database. There is no intention of trying to teach you how to use SQL. If you don't already have a rudimentary knowledge of SQL, you should review a good book on the subject. The mSQL User's Guide will be a good place for you to start.

The mSQL distribution contains several programs and utilities to allow you to use and manage your databases. The tools provided allow you to communicate with the database server, import data, export data, submit queries and view your database structures.

The monitor program named msql is an interactive interface to the mSQL server. It allows you to submit SQL commands directly to the server.

The schema viewer program named relshow is used to display the structure of the contents of mSQL databases.

The admin program named msqladmin is used to perform administrative operations on a mSQL database server. Such tasks include the creation of databases, performing server shutdowns, etc. The available commands for msqladmin are:

The program named msqldump produces an ASCII text file containing valid SQL commands that will recreate the table or database dumped when piped through the mSQL monitor program.

The data exporter program named msqlexport produces an ASCII export of the data from the specified table.

The data importer program named msqlimport loads a flat ASCII data file into a mSQL database table.

The program named msql2d is the database itself. Executing this program will cause your database engine to start running. As mentioned above, the shutdown command of msqladmin can be used to terminate it.

mSQL provides many other features, such as a C-programmers interface, and a built-in scripting language that are not mentioned here because they are not germane to the topic at hand: the use of JDBC for manipulating data in an SQL database.

Sample Program

The purpose of this program is to demonstrate the ability to use JDBC to access a remote mSQL database server.

The TCP/IP server named webserver, used in this sample program, provides access to the database server program named mSQL. You can download mSQL and install it on the server of your choice.

When this program is executed, the database server must be ready to communicate with clients, and a database named JunkDB must have already been created and ready for use. The mSQL server program must be started and a database named JunkDB must be created on that database server using a console command before the program is executed.

This program

As a precaution, before attempting to create the new table named myTable, the program attempts to delete a table having the same name. If a table having the same name already exists as residue from a previous run, it is deleted. If it doesn't already exist when the attempt is made to delete it, an exception is thrown. This exception is simply caught and ignored.

There are significant differences between the versions of JDBC that support JDK 1.1 and JDK 1.2. As of 12/31/98, a description of the differences was available at http://java.sun.com/products/jdk/1.2/docs/guide/jdbc/spec2/jdbc2.0.frame.html.

By removing and adding comment indicators, this sample program can be made to operate properly under either of the JDK/JDBC combinations. The details of operating under either combination are shown as comments in the listing of the program. This lesson will concentrate on the JDK 1.2 version.

As of 12/31/98, both versions of the JDBC for mSQL were available for downloading from the imaginary.com URL given earlier. In both cases, the download includes a jar file and some sparse documentation. Extensive documentation is not required from the JDBC vendor because the functionality of the JDBC interface is described in the JavaSoft documentation for either JDK 1.1 or JDK 1.2 in the package named java.sql.

To install the JDBC interface classes, I simply copied the jar file downloaded from imaginary.com into the lib directory for the corresponding JDK 1.1 or JDK 1.2 installation on my machine. The lib directory also contains standard zip files or jar files that are included in the JDK download packages. If you take the same approach, be aware that when JDK 1.2 is upgraded to a later version, it will be necessary to copy the JDBC jar file named msql-jdbc-2-0a1.jar (or whatever the current name of the jar file happens to be) into the lib directory for the new version of the JDK before deleting the old version.

It is necessary to manually start the mSQL database server running on the remote server machine. This is accomplished by running the program named msql2d on the server machine.

You can administer the mSQL database by running the program named msqladmin. Simply running the program with no command-line parameters produces the following output, which identifies the administration options:

usage : msqladmin [-h host] [-f conf] [-q] <Command>

where command = 
	drop DatabaseName
	create DatabaseName
	copy FromDB ToDB
	move FromDB ToDB
	shutdown
	reload
	version
	stats

	-q Quiet mode. No verification of commands.

These options were described in more detail in an earlier section. Full details are available in the mSQL User's Guide available at the Hughes web site.

To create the new database, start the mSQL database program running in one process window (by executing msql2d in that window) and then enter the following command in a separate process window used for database administration:

msqladmin create JunkDB

To shut down the mSQL database server, enter the following command in the administration window:

msqladmin shutdown

To delete a database, execute the drop command passing the name of the database as a command-line argument. DO NOT delete database files manually. This will cause the mSQL database program to become very confused and you may have to remove and reinstall it to get it cleaned up.

For my records only (so that I can reproduce things later), the Win95 version of mSQL was downloaded from the URL given earlier and is stored in my Download files under the name msql-2041-b20.zip. A UNIX version named msql-2_0_5_tar.tar was downloaded from the URL given earlier and successfully tested by installing it on a Linux server. In both cases, the sample Java program was executed under Win95.

The JDK 1.2 version of the sample program produced the following output.

URL: jdbc:msql://webserver:1114/JunkDB
Connection: com.imaginary.sql.msql.MsqlConnection@eb0064a4
com.imaginary.sql.msql.MsqlException: known table "myTable"
No existing table to delete
Display all results:
test_id= 1 str = One
test_id= 2 str = Two
test_id= 3 str = Three
test_id= 4 str = Four
test_id= 5 str = Five
Display row number 2:
test_id= 2 str = Two

Note the missing characters "un" in the display of the exception that should read "unknown table". This could lead to confusion.

The output produced by the JDK 1.1 version is shown in the complete program listing near the end of this lesson.

There are five critical steps in using JDBC to manipulate a database:

I will highlight these steps in the discussion of the sample program in the next section.

Interesting Code Fragments

This section highlights code fragments that are important in gaining an understanding of how to use JDBC to access a remote database server and to manipulate the data stored in the database. The first fragment is provided simply to remind you of the requirement to import the java.sql package.

import java.sql.*;

The next fragment shows the beginning of the main() method and the declaration of a two local variables that will be used later.

  public static void main(String args[]) {
    try {
      Statement stmt;
      ResultSet rs;

The next fragment shows the first critical step in the use of JDBC: registration of the JDBC driver for the database engine that you intend to use. This statement loads the driver class and makes the driver available for use later when it is needed to open a connection to the database server. When the driver is loaded into memory, it registers itself with the java.sql.DriverManager class as an available database driver.

      Class.forName("com.imaginary.sql.msql.MsqlDriver");

There are other ways to accomplish this registration as well. The FAQ that is available with the mSQL JDBC drivers suggests that the driver be registered using a statement such as the following when the program is started:

java -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver Jdbc01

I haven't tried this, but I assume that it works. The advantage is that it further disconnects the program from a specific database engine. In theory, JDBC programs that you write should be compatible with any modern SQL database engine.

Another approach uses the registerDriver() method to register the JDBC driver software.

mSQL and other similar database engines behave as servers on a network. They are identified by a URL much as other types of servers (such as HTTP servers and FTP servers) are identified. The next fragment defines the URL for the database server that I used in this sample program.

This statement defines the URL of the database server for a database named JunkDB. I believe that port 1114 is the standard database server port, but as of 12/31/98, I haven't been able to confirm that. The port number along with the user name and some other information is specified in a configuration file named msql.conf in the Hughes directory, which is the installation directory for the mSQL database.

This fragment actually shows two statements. One statement can be used to access the database when it is running on a remote TCP/IP server named webserver. The other statement can be used to access the database when it is running in a separate process on the same machine (localhost). Although I haven't mentioned this earlier, this sample program will run on a single machine with the database server program running in one process and the sample program running in another process.

Note that in these statements, the "//" shown to the right of "msql:" form part of the URL. They are not comment indicators.

      String url = "jdbc:msql://webserver:1114/JunkDB";
//      String url = "jdbc:msql://localhost:1114/JunkDB";

The second critical statement in the use of JDBC, as shown in the next fragment, gets a connection to the database.

      Connection con = DriverManager.getConnection(url,
                                            "baldwin", "");

The DriverManager class provides the basic services for managing a set of JDBC drivers. The DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property (recall the expression shown earlier that can be used to set this property when the program is started).

A program can also explicitly load JDBC drivers at any time using the forName() method shown earlier in this sample program. There is also a static method of the DriverManager class named registerDriver() that can be used for this purpose.

getConnection() is a static method of the DriverManager class. When getConnection() is called, the DriverManager will attempt to locate a suitable driver from among those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application. (Note that DriverManager can use the first two terms of the URL (jdbc:msql) to identify a suitable driver.)

There are several overloaded versions of getConnection(). The following is a description of the version used in the above fragment.

public static Connection getConnection(String url,
                                       String user,
                                       String password)
                                 throws SQLException

Attempts to establish a connection to the given database URL. 
The DriverManager attempts to select an appropriate driver 
from the set of registered JDBC drivers.

Parameters:
  url - a database url of the form jdbc:subprotocol:subname
  user - the database user on whose behalf the Connection 
         is being made
  password - the user's password

Returns:
  a Connection to the URL
Throws:
  SQLException - if a database access error occurs

If the attempt to get a connection to the database server is successful, the method returns an object of type Connection. In this program, a reference to the Connection object is stored in the reference variable named con.

If the attempt is not successful, an exception of type SQLException is thrown. Each SQLException object provides several kinds of information:

For example, you might use code such as the following in the exception handler to obtain and display the information encapsulated in a SQLException object.

catch(SQLException ex) {
  while (ex != null) {
    System.out.println("Message:   " + ex.getMessage ());
    System.out.println("SQLState:  " + ex.getSQLState ());
    System.out.println("ErrorCode: " + ex.getErrorCode ());
    ex = ex.getNextException();
    System.out.println("");
  }//end while loop
}//end catch block

The code in the next fragment is not critical to the use of JDBC. This code simply displays the URL and Connection objects.

      System.out.println("URL: " + url);
      System.out.println("Connection: " + con);

The next fragment shows the third critical step in the use of JDBC.

      stmt = con.createStatement();

Recall that con is a reference to an object of type Connection. A Connection object defines a connection (session) with a specific database. SQL statements are executed and results are returned within the context of a connection.

Here we are concerned with the createStatement() method of the Connection class. This method creates a Statement object for sending SQL statements to the database.

According to the JavaSoft documentation, a Statement object is "The object used for executing a static SQL statement and obtaining the results produced by it."

The results are returned in the form of a ResultSet object. Only one ResultSet per Statement can be open at any point in time. Therefore, if the reading of one ResultSet is interleaved with the reading of another, each must have been generated by different Statement objects. All Statement executeXXX methods (such as executeUpdate()) implicitly close a statement's current ResultSet if an open one exists.

The Statement class provides many methods that are used to manipulate the data in the database. One of those methods is executeUpdate(). This method has a single String parameter, which must be a valid SQL statement. It is used to execute SQL INSERT, UPDATE or DELETE statements. In addition, other SQL statements that return nothing can be executed using this method.

This sample program will create a table named myTable. However, if a table having that name already exists in the database, the attempt to create the table will throw an exception, which if not caught, will terminate the program. As a precaution, the following fragment uses the executeUpdate() method to delete a table having that name if it exists. If a table having that name doesn't already exist, the attempt to delete the table throws an exception. The exception handler for this exception simply displays some text and continues with the normal flow of the program.

The next fragment illustrates the fourth critical step in the use of JDBC: use of a Statement object to manipulate the database.

Since this fragment contains the first statement in the program that attempts to use JDBC to manipulate the database, the single statement in the fragment used for that purpose is highlighted in boldface.

      try{
        stmt.executeUpdate("DROP TABLE myTable");
      }catch(Exception e){
        System.out.print(e);
        System.out.println("No existing table to delete");
      }//end catch

As you can surmise from the above discussion and code, the SQL DROP statement causes the table to be deleted from the database.

The next fragment uses the executeUpdate() method to create a table named myTable. I don't plan to provide an extensive discussion of the SQL statements used in this program. Suffice it to say that this table will contain two columns. The first column is named test_id and contains data of type int. The second column is named test_val and contains a string up to 15 characters in length.

      stmt.executeUpdate("CREATE TABLE myTable ("
              + "test_id int,test_val char(15) not null)");

The next fragment uses the executeUpdate() method to insert data into five new rows in the table. You should be able examine the syntax of the SQL statements and surmise what is going on here.

      stmt.executeUpdate("INSERT INTO myTable ("
                   + "test_id, test_val) VALUES(1,'One')");
      stmt.executeUpdate("INSERT INTO myTable ("
                   + "test_id, test_val) VALUES(2,'Two')");
      stmt.executeUpdate("INSERT INTO myTable ("
                 + "test_id, test_val) VALUES(3,'Three')");
      stmt.executeUpdate("INSERT INTO myTable ("
                  + "test_id, test_val) VALUES(4,'Four')");
      stmt.executeUpdate("INSERT INTO myTable ("
                  + "test_id, test_val) VALUES(5,'Five')");

The next fragment gets another Statement object initialized as shown. Refer to the JDK 1.2 documentation for the createStatement() method and the ResultSet class for a description of the parameters passed to the method in this case. The ResultSet class provides about eight symbolic constants that can be used as parameters to this method. The values of the parameters exercise control over the behavior of the ResultSet object returned by later queries based on the Statement object.

      stmt = con.createStatement(ResultSet.
                               TYPE_SCROLL_INSENSITIVE,
                               ResultSet.CONCUR_READ_ONLY);

The executeQuery() method of the Statement class executes an SQL statement that returns a single ResultSet object. The parameter to the method is a String that typically represents a static SQL SELECT statement. The ResultSet object that is returned contains the data produced by the query;

      rs = stmt.executeQuery(
               "SELECT * from myTable ORDER BY test_id");

A ResultSet object provides access to a table of data. The object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next() method moves the cursor to the next row (similar to an iterator or an enumerator in Java).

The getXXX methods (such as getString()) retrieve column values for the current row. You can retrieve values using either the index number of the column or the name of the column. In general, using the column index is more efficient. Columns are numbered beginning with 1 (not with 0).

For the getXXX methods, the JDBC driver attempts to convert the underlying data to the specified Java type and returns a suitable Java value.

A ResultSet is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.

The next fragment uses several methods of the ResultSet class in a while loop to display all of the data in the ResultSet object produced by the earlier query.

      System.out.println("Display all results:");
      while(rs.next()) {
        int theInt= rs.getInt("test_id");
        String str = rs.getString("test_val");
        System.out.println("\ttest_id= " + theInt 
                                       + "\tstr = " + str);
      }//end while loop

The next fragment uses the absolute() method of the ResultSet class to move the cursor to row 2 in the result table and then displays the data in the two columns of that row. Row numbers begin with 1 (not with 0).

      System.out.println("Display row number 2:");
      if( rs.absolute(2) ) {
        int theInt= rs.getInt("test_id");
        String str = rs.getString("test_val");
        System.out.println("\ttest_id= " + theInt 
                                       + "\tstr = " + str);
      }//end if

The final fragment, which illustrates the fifth critical step in the use of JDBC,deletes the table and closes the connection to the database.

      stmt.executeUpdate("DROP TABLE myTable");
      con.close();               

This fragment is followed by an exception handler (not shown) which ends the program.

Program Listing

A complete listing of the program with additional comments follows. This listing also contains some information about the differences between JDK 1.1 and JDK 1.2 insofar as JDBC is concerned.

/*File Jdbc01.java, Copyright 1999, R.G.Baldwin
Rev 12/31/98
The purpose of this program is to test the ability to use
JDBC to access a remote mSQL database server.

The remote TCP/IP server named webserver provides access 
to a database server program named mSQL.  The mSQL 
database server program was started and a database named 
JunkDB was created on that database server using a console
command before this program was run.

This program accesses the database named JunkDB, creates a
table named myTable, puts five rows of data into the table,
displays the data, and then deletes the table.  

As a precaution, before attempting to create the new table,
the program attempts to delete a table having the same 
name.  If a table having the same name already exists as 
residue from a previous run, it is deleted.  If it doesn't
already exist when the attempt is made to delete it, an 
exception is thrown.  This exception is simply caught and
ignored.

There are major differences between the versions of JDBC
that support JDK 1.1 and JDK 1.2.  By removing and adding
comment indicators, this program can be made to operate
properly under either version of the JDK/JDBC combination.
This assumes that you have both versions of JDBC for mSQL
properly installed on your classpath.

As of 12/31/98, both versions of the JDBC for mSQL can be
downloaded from http://www.imaginary.com/Java.  In both
cases, the download includes a jar file and some sparse
documentation.  However, the functionality of the JDBC
interface is described in the JavaSoft documentation for
either JDK 1.1 or JDK 1.2 in the java.sql package.

To install the JDBC interface classes, I simply copied the
jar file obtained from imaginary.com into the lib directory
for the corresponding JDK 1.1 or JDK 1.2 installation on
my machine, which also contains standard zip files or jar 
files that are included in the JDK download package.  This
was easier than messing with the classpath environment
variable.  However, when JDK 1.2 is upgraded to a later 
version, it will be necessary for me to copy the JDBC jar 
file named msql-jdbc-2-0a1.jar into the lib directory for 
the new version of the JDK.

Note that it is necessary to manually start the mSQL 
database server running on the remote server machine. This
is accomplished by running the program named msql2d.  

You can administer the mSQL database by running the program
named msqladmin.  Simply running the program with no
command-line parameters produces the following output
that identifies the administration options:

usage : msqladmin [-h host] [-f conf] [-q] <Command>

where command =   
     drop DatabaseName
     create DatabaseName
     copy FromDB ToDB
     move FromDB ToDB
     shutdown
     reload
     version
     stats

 -q  Quiet mode.  No verification of commands.

To create the new database, start the mSQL database program
running in one process window and then enter the following
command in a separate process window:
  
msqladmin create JunkDB

To shut down the mSQL database server, enter the following
command:
  
  msqladmin shutdown
  
To delete the database, execute the drop command.  DO NOT 
delete database files manually.  This will cause the mSQL
database program to be come very confused.

For my records only, the Win95 version of mSQL is stored 
in my Download files under the name msql-2041-b20.zip.  
The Win95 version was downloaded from 
http://blnet.com/msqlpc/downloads.htm. A UNIX version named
msql-2_0_5_tar.tar was downloaded from 
http://www.Hughes.com.au/ and successfully tested by
installing it on a LINUX server.  In both cases, the java
program was executed under Win95.

The JDK 1.1 version of the program, created by removing and
adding comment indicators as shown in the source code
produced the following output:
  
URL: jdbc:msql://webserver:1114/JunkDB
Connection: com.imaginary.sql.msql.MsqlConnection@1cc8be
java.sql.SQLException: :Unknown table "myTable"
No existing table to delete
Display all results:
  test_id= 1  str = One
  test_id= 2  str = Two
  test_id= 3  str = Three
  test_id= 4  str = Four
  test_id= 5  str = Five
  
  
The JDK 1.2 version, also created by removing and adding
comment indicators as shown in the source code produced the
following output. Note the missing characters "un" in the 
display of the exception that should read "unknown table".
This could lead to considerable confusion.
  
URL: jdbc:msql://webserver:1114/JunkDB
Connection: com.imaginary.sql.msql.MsqlConnection@eb0064a4
com.imaginary.sql.msql.MsqlException: known table "myTable"
No existing table to delete
Display all results:
  test_id= 1  str = One
  test_id= 2  str = Two
  test_id= 3  str = Three
  test_id= 4  str = Four
  test_id= 5  str = Five
Display row number 2:
  test_id= 2  str = Two
  
**********************************************************/
import java.sql.*;

public class Jdbc01 {
  public static void main(String args[]) {
    try {
      Statement stmt;
      ResultSet rs;
      
      //Register the JDBC driver
      Class.forName("com.imaginary.sql.msql.MsqlDriver");
      
      //Define URL of database server for database named 
      // JunkDB by selecting one of the following
      // statements.  I believe that port 1114 is the
      // standard database server port, but I'm not
      // certain.  This value along with the user name and
      // some other information is specified in a file 
      // named msql.conf in the Hughes directory which is
      // the installation directory for the mSQL database.
      String url = "jdbc:msql://webserver:1114/JunkDB";
//      String url = "jdbc:msql://localhost:1114/JunkDB";

      
      //Get a connection to the database
      Connection con = DriverManager.getConnection(url,
                                            "baldwin", "");
      //Display URL and connection information
      System.out.println("URL: " + url);
      System.out.println("Connection: " + con);
      
      //Get a Statement object
      stmt = con.createStatement();
      
      //As a precaution, delete myTable if it already 
      // exists as residue from a previous run.  Otherwise,
      // if the table already exists and an attempt is made
      // to create it, an exception will be thrown.
      try{
        stmt.executeUpdate("DROP TABLE myTable");
      }catch(Exception e){
        System.out.print(e);
        System.out.println("No existing table to delete");
      }//end catch

      //Create a table in the database named myTable.
      stmt.executeUpdate("CREATE TABLE myTable ("
              + "test_id int,test_val char(15) not null)");
      
      //Insert some values into the table
      stmt.executeUpdate("INSERT INTO myTable ("
                   + "test_id, test_val) VALUES(1,'One')");
      stmt.executeUpdate("INSERT INTO myTable ("
                   + "test_id, test_val) VALUES(2,'Two')");
      stmt.executeUpdate("INSERT INTO myTable ("
                 + "test_id, test_val) VALUES(3,'Three')");
      stmt.executeUpdate("INSERT INTO myTable ("
                  + "test_id, test_val) VALUES(4,'Four')");
      stmt.executeUpdate("INSERT INTO myTable ("
                  + "test_id, test_val) VALUES(5,'Five')");

      //Get another statement object.  This version is 
      // compatible with either JDK 1.1 or JDK 1.2, but 
      // does not support the rs.absolute(2) statement used
      // later in the JDK 1.2 version.
      stmt = con.createStatement();


/*
      //Get another statement object initialized as shown.
      // This version is compatible with JDK 1.2 but is not
      // compatible with JDK 1.1.  This version is required
      // to support the rs.absolute(2) statement later.
      stmt = con.createStatement(ResultSet.
                               TYPE_SCROLL_INSENSITIVE,
                               ResultSet.CONCUR_READ_ONLY);
*/
      //Query the database, storing the result in an object
      // of type ResultSet
      rs = stmt.executeQuery(
               "SELECT * from myTable ORDER BY test_id");

      //Use the methods of class ResultSet in a loop
      // to display all of the data in the database.
      System.out.println("Display all results:");
      while(rs.next()) {
        int theInt= rs.getInt("test_id");
        String str = rs.getString("test_val");
        System.out.println("\ttest_id= " + theInt 
                                       + "\tstr = " + str);
      }//end while loop

/*
      //This block of code only works under JDK 1.2.  
      // The absolute() method is not supported by JDK 1.1.
      System.out.println("Display row number 2:");
      if( rs.absolute(2) ) {
        int theInt= rs.getInt("test_id");
        String str = rs.getString("test_val");
        System.out.println("\ttest_id= " + theInt 
                                       + "\tstr = " + str);
      }//end if
      //End block supported only by JDK 1.2.  
*/
      //Delete the table and close the connection to the
      // database      
      stmt.executeUpdate("DROP TABLE myTable");
      con.close();
    }catch( Exception e ) {
      e.printStackTrace();
    }//end catch
  }//end main
}//end class Jdbc01

-end-