JDBC


Based on Chapter 26 and 27 from the book "Just Java 2" by Peter van der Linden (5th. Edition).

You can find a good tutorial about JDBC in the Java site at:
http://java.sun.com/docs/books/tutorial/jdbc/

A Review of Relational Databases

A short tutorial on relational databases can be found here.
The Relational Model for Databases was proposed by Edgar F. Codd in 1970. He won the Turing award for his work: ACM site for Codd. The ideas he proposed were implemented in a prototype by IBM (System-R) and later implemented by Oracle and other DBMS vendors.
The gist of Relational Data Bases is that data are stored in tables. These tables are logical entities, they might be implemented internally in a different format.
A single row of data is known as a tuple, a record or row. The name of the data in a column is called an attribute. An attribute is an individual field of a reord. A domain is the set of allowable values for an attribute. A relation is a table with columns and rows. The number of attributes in a relation is called its degree. The number of tuples in a relation is called its cardinality.

Every table must have an attribute (or group of attributes together) that uniquely identifies a record. This is called the primary key to the table.
Many tables contain foreign keys: Attributes in one table that are a primary key in some other table. When a table contains a certain value in a foreign key, that value must occur in the table for which it is the primary key. If the key exists, there is referential integrity.
If one does not have a value for some attribute, the value "null" can be assigned. Null should not be used in any column that is part of a primary or foreign key. This is entity integrity.
The relationship between a foreign key and the table where it is a primary key might be: Because it is difficult to make queries in the case of many-to-many relationships, an additional table can be created to express the relationship in terms of two 1-many tables. In the example in the book: There is a "Person" table and there is a "MusicGroup" table. The relationship between them is many-to-many. To simplify the process of making queries, a new table called "ListensTo" is created. The relationship between Name in "Person" and Name in "ListensTo" is one-to-many and likewise the relationship between "MusicGroupName" in "MusicGroup" and "MusicGroupName" in "ListensTo" is also one-to-many.
When designing databases, the normal forms (at least the first three) are good guidelines to structure the tables correctly. This is a topic that is covered in depth in the Data Base track.. Briefly

SQL

A good source of resources about SQL is available: here.
SQL is a language that contains the operations that one is likely to perform on a database. By convention, the SQL keywords are written in uppercase. There are four categories of SQL statements: JDBC issues SQL command by putting them in a String and passing that String to various methods in the JDBC library. A key observation in the processing of SELECT statements is the fact that a SELECT statement may return a set of records, not just one record, and therefore it is important to be able to iterate through the set of records in the result.

JDBC

JDBC is the Java library that supports access to databases. The classes that make up JDBC are in the package java.sql.

The DBMS (data base management system) works as server, it responds to requests from the clients. The client connects to the DBMS using a database driver. The drivers are usually provided by the vendors of the DBMS. The driver is called in the program with an instruction similar to this:

Class.forName("com.mckoi.JDBCDriver");

Once the driver is available, a connection to the DBMS can be established. The method that will establish the connection expects a pseudo-url as a parameter. The code is similar to:

String url = "jdbc:mckoi:local://ExamapleDB.conf?create=true";
connection = java.sql.DriverManager.getConnection(url,user,passwd);

In this particular example, the url is specifying to the DBMS that new database will be created. connection is an object of the class (actually an interface) java.sql.Connection. There are more sophisticated (and more complex) alternatives to connect to the DBMS: Using a DataSource object that is registered with a naming service.

The connection object can be used to pass requests to the DBMS and to receive results back. One uses Statements. The code is similar to this:

Statement myStmt = connection.createStatement();
ResultSet myResult;
myResult = myStmt.executeQuery( "SELECT Dictionary.meaning FROM Dictionary WHERE Dictionary.word = 'cat';" );

The executeQuery() method takes a string as an argument. The string contains the SQL SELECT statement that you want to execute. There are other methods that are appropriate for other kinds of SQL statements: JDBC interactions with a database may throw exceptions. It is important to surround the code with the appropriate try catch clauses to be able to catch the exceptions.

The ResultSet may contain several tuples and each of those tuples may contain several attributes. To iterate through the tuples and to access the different attributes, the code will be: Statement myStmt = connection.createStatement();
ResultSet myResult;
myResult = myStmt.executeQuery( "SELECT Person.name , Person.age FROM Person;" );
while (myResult.next()) { // Iterate through all the tuples in myResult
String p = myResult.getString(1); // Access the first attribute in this tuple
int a = myResult.getInt(2); // Access the second attribute in this tuple
System.out.println(p+" is "+a+" years old.");
}
In the previous code one can observe that one iterates through the tuples in the ResultSet by using next(), which will return false when there are no more elements to process. It can also be observed that the different attributes in the tuple can be accessed by using the number that corresponds to the attribute and that one needs to use a method that is appropriate for the kind of attribute that one is retrieving. In this case the first attribute has number 1. When a Statement is no longer needed, it should be closed.
myStmt.close();
To improve performance it is possible to create a group of SQL statements (as long as they are not SELECT statements) and send them into one single batch to be executed. This will improve performance.
In databases, transactions should be atomic. A transaction may involve several individual updates. If the integrity of the database is to be kept, then either the entire transaction (including all updates) succeeds or the entire transaction fails. If a transaction succeeds, then the program should commit the changes. If a transaction fails, then the results of the transaction are rolled back. This is supported in JDBC by the Connection object, which has methods to either commit or rollback. By default, the Connection automatically commits changes after executing each individual statement. This default can be overridden and the programmer can have selective control over commits and rollbacks. To deactivate the default, the code is:
boolean savedCommitValue = conn.getAutoCommit(); // save current value
conn.setAutoCommit(false); // disable statement by statement commit
Then it is possible to execute a batch of commands and commit only after all the transactions in the batch have finished:
int [] res = myStmt.executeBatch();
conn.commit();
If an exception took place, one can rollback the effect of the batc with the following instruction: conn.rollback();
This will rollback all the statements issued on this connection since the previous commit() or rollback();
The following program is one of the two sample programs avaialble with mckoi:

/**
 * Demonstrates how to create a database through the JDBC driver.  This
 * will create a database in the local directory, create three tables and
 * fill them with sample data.
 * 

* This demo distribution should contain a created database in the local * directory. If the 'data' directory doesn't exist or was deleted then it * can be recreated by running this. */ import java.sql.*; public class SimpleDatabaseCreateDemo { /** * Application start method. */ public static void main(String[] args) { System.out.println(); // Register the Mckoi JDBC Driver try { Class.forName("com.mckoi.JDBCDriver").newInstance(); } catch (Exception e) { System.out.println( "Unable to register the JDBC Driver.\n" + "Make sure the classpath is correct.\n" + "For example on Win32; java -cp ../../mckoidb.jar;. SimpleApplicationDemo\n" + "On Unix; java -cp ../../mckoidb.jar:. SimpleApplicationDemo"); return; } // This URL specifies we are creating a local database. The // configuration file for the database is found at './ExampleDB.conf' // The 'create=true' argument means we want to create the database. If // the database already exists, it can not be created. String url = "jdbc:mckoi:local://ExampleDB.conf?create=true"; // The username/password for the database. This will be the username/ // password for the user that has full control over the database. // ( Don't use this demo username/password in your application! ) String username = "user"; String password = "pass1212"; // Make a connection with the database. This will create the database // and log into the newly created database. Connection connection; try { connection = DriverManager.getConnection(url, username, password); } catch (SQLException e) { System.out.println( "Unable to create the database.\n" + "The reason: " + e.getMessage()); return; } // --- Set up the database --- try { // Create a Statement object to execute the queries on, Statement statement = connection.createStatement(); ResultSet result; System.out.println("-- Creating Tables --"); // Create a Person table, statement.execute( " CREATE TABLE Person ( " + " name VARCHAR(100) NOT NULL, " + " age INTEGER, " + " lives_in VARCHAR(100) ) " ); // Create a ListensTo table (which person listens to what music) statement.execute( " CREATE TABLE ListensTo ( " + " person_name VARCHAR(100) NOT NULL, " + " music_group_name VARCHAR(250) NOT NULL ) "); // Create a MusicGroup table statement.execute( " CREATE TABLE MusicGroup ( " + " name VARCHAR(250) NOT NULL, " + " country_of_origin VARCHAR(100) ) "); // Insert records into the tables, System.out.println("-- Inserting Data --"); System.out.println("-- Adding to Person Table --"); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Robert Bellamy', 24, 'England' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Grayham Downer', 59, 'Africa' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Timothy French', 24, 'Africa' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Butch Fad', 53, 'USA' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Judith Brown', 34, 'Africa' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Elizabeth Kramer', 24, 'USA' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Yamnik Wordsworth', 14, 'Australia' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Domonic Smith', 25, 'England' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Ivan Wilson', 23, 'England' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Lisa Williams', 24, 'England' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'Xenia, Warrior Princess', 32, 'Rome' ) "); statement.execute( " INSERT INTO Person ( name, age, lives_in ) VALUES " + " ( 'David Powell', 25, 'New Zealand' ) "); System.out.println("-- Adding to MusicGroup Table --"); statement.execute( " INSERT INTO MusicGroup " + " ( name, country_of_origin ) VALUES " + " ( 'Oasis', 'England' ), " + " ( 'Fatboy Slim', 'England' ), " + " ( 'Metallica', 'USA' ), " + " ( 'Nirvana', 'USA' ), " + " ( 'Beatles', 'England' ), " + " ( 'Fela Kuti', 'Africa' ), " + " ( 'Blur', 'England' ), " + " ( 'Muddy Ibe', 'Africa' ), " + " ( 'Abba', 'Sweden' ), " + " ( 'Madonna', 'USA' ), " + " ( 'Cure', 'England' ) " ); // Who listens to what music? System.out.println("-- Adding to ListensTo Table --"); statement.execute( " INSERT INTO ListensTo " + " ( person_name, music_group_name ) VALUES " + " ( 'David Powell', 'Metallica' ), " + " ( 'David Powell', 'Cure' ), " + " ( 'Xenia, Warrior Princess', 'Madonna' ), " + " ( 'Lisa Williams', 'Blur' ), " + " ( 'Lisa Williams', 'Cure' ), " + " ( 'Lisa Williams', 'Beatles' ), " + " ( 'Ivan Wilson', 'Cure' ), " + " ( 'Ivan Wilson', 'Beatles' ), " + " ( 'Yamnik Wordsworth', 'Abba' ), " + " ( 'Yamnik Wordsworth', 'Fatboy Slim' ), " + " ( 'Yamnik Wordsworth', 'Fela Kuti' ), " + " ( 'Elizabeth Kramer', 'Nirvana' ), " + " ( 'Judith Brown', 'Fela Kuti' ), " + " ( 'Judith Brown', 'Muddy Ibe' ), " + " ( 'Butch Fad', 'Metallica' ), " + " ( 'Timothy French', 'Blur' ), " + " ( 'Timothy French', 'Oasis' ), " + " ( 'Timothy French', 'Nirvana' ), " + " ( 'Grayham Downer', 'Fela Kuti' ), " + " ( 'Grayham Downer', 'Beatles' ), " + " ( 'Robert Bellamy', 'Oasis' ), " + " ( 'Robert Bellamy', 'Beatles' ), " + " ( 'Robert Bellamy', 'Abba' ), " + " ( 'Robert Bellamy', 'Blur' ) " ); System.out.println("--- Complete ---"); // Close the statement and the connection. statement.close(); connection.close(); } catch (SQLException e) { System.out.println( "An error occured\n" + "The SQLException message is: " + e.getMessage()); } // Close the the connection. try { connection.close(); } catch (SQLException e2) { e2.printStackTrace(System.err); } } }

The following program shows how to query the database created with the previous program:

/**
 * This demonstrates a simple stand-alone database application.  This will
 * start up the database that's found in this directory and perform some
 * queries on the data.
 * 

* The demo distribution should contain the database data files already * prepared. However, if the 'data' directory was removed then run * 'SimpleDatabaseCreateDemo' to remake it. */ import java.sql.*; public class SimpleApplicationDemo { /** * The demonstation 'main' method. */ public static void main(String[] args) { System.out.println(); // Register the Mckoi JDBC Driver try { Class.forName("com.mckoi.JDBCDriver").newInstance(); } catch (Exception e) { System.out.println( "Unable to register the JDBC Driver.\n" + "Make sure the classpath is correct.\n" + "For example on Win32; java -cp ../../mckoidb.jar;. SimpleApplicationDemo\n" + "On Unix; java -cp ../../mckoidb.jar:. SimpleApplicationDemo"); return; } // This URL specifies we are connecting with a local database. The // configuration file for the database is found at './ExampleDB.conf' String url = "jdbc:mckoi:local://ExampleDB.conf"; // The username/password for the database. This is set when the database // is created (see SimpleDatabaseCreateDemo). String username = "user"; String password = "pass1212"; // Make a connection with the database. Connection connection; try { connection = DriverManager.getConnection(url, username, password); } catch (SQLException e) { System.out.println( "Unable to make a connection to the database.\n" + "The reason: " + e.getMessage()); return; } // --- Do some queries --- System.out.println(); try { // Create a Statement object to execute the queries on, Statement statement = connection.createStatement(); ResultSet result; // How many rows are in the 'Person' table? result = statement.executeQuery("SELECT COUNT(*) FROM Person"); if (result.next()) { System.out.println("Rows in 'Person' table: " + result.getInt(1)); } System.out.println(); // What's the average age of the people stored? result = statement.executeQuery("SELECT AVG(age) FROM Person"); if (result.next()) { System.out.println("Average age of people: " + result.getDouble(1)); } System.out.println(); // List the names of all the people that live in Africa ordered by name result = statement.executeQuery( "SELECT name FROM Person WHERE lives_in = 'Africa' ORDER BY name"); System.out.println("All people that live in Africa:"); while (result.next()) { System.out.println(" " + result.getString(1)); } System.out.println(); // List the name and music group of all the people that listen to // either 'Oasis' or 'Beatles' result = statement.executeQuery( " SELECT Person.name, MusicGroup.name " + " FROM Person, ListensTo, MusicGroup " + " WHERE MusicGroup.name IN ( 'Oasis', 'Beatles' ) " + " AND Person.name = ListensTo.person_name " + " AND ListensTo.music_group_name = MusicGroup.name " + " ORDER BY MusicGroup.name, Person.name "); System.out.println("All people that listen to either Beatles or Oasis:"); while (result.next()) { System.out.print(" " + result.getString(1)); System.out.print(" listens to "); System.out.println(result.getString(2)); } System.out.println(); // Close the statement and the connection to end, statement.close(); connection.close(); } catch (SQLException e) { System.out.println( "An error occured\n" + "The SQLException message is: " + e.getMessage()); return; } } }