Chapter 5 JDBC
Chapter 5 JDBC
Java offers several benefits to the developer creating a front-end application for a database
server. Java is ‘Write Once Run Everywhere’ language. This means that Java programs may be
deployed without recompilation on any computer architectures and operating systems that possesses
a Java Virtual Machine.
In addition there is a cost associated with deployment and maintenance of the hardware and
software of any system (client) the corporation owns Systems such as Windows PC, Macintosh and
Unix desktop centric clients (fat clients) can cost corporations between $10,000 to $15,000 per
installation seat. Java technology has made it possible for any company to use smaller system
footprint. These systems are based on Java chip set and run any and all Java programs from built-in
Java operating system.
Java based clients (thin clients) that operate with minimum of hardware resources, yet run the
complete Java environment are expected to cost around $70 per seat. According to studies, saving
for the corporations moving 10,000 fat clients to thin clients systems could be much as $100 million
annually.
There are many industrial-strength DBMS available in the market. These include Oracle
DB2, Sybase and many other popular brands. The challenge to Sun Microsystems faced in the late
1990s was to develop a way for Java developer to write a high level code that accesses all popular
DBMSs.
The Sun Microsystems met the challenge in 1996 with the creation of JDBC driver for JDBC
API. Both were created out of necessity, because until then Java wasn’t industrial strength
programming language since Java was unable to access the DBMS.
The JDBC driver developed by Sun wasn’t driver at all. It was specification that described
the detail functionality of JDBC driver. DBMS manufacturers and third-party vendors encouraged to
build JDBC drivers that confirmed to Sun’s specifications. Those firm that built JDBS drivers for
their product could tap into growing Java applications market.
The specifications required a JDBC driver to be a translator that converted low-level
proprietary DBMS messages to low-level messages understood by JDBC API and vice-versa. This
meant that Java programmer could use high-level Java data-objects defined in the JDBC API to
write a routine that interacted with the DBMS. Java data objects convert the routine into low-level
message that conform to the JDBC driver specification and send them to the JDBC driver. The
JDBC driver translates the routine into low-level messages that understood and processed by DBMS.
Relational databases are the most common DBMS. A main characteristic of a relational
database is the absolute separation between physical and logical data. Data is accessed through the
associated logical model to avoid supplying
Relational databases allow the definition of relations and integrity rules between data
sets. E.F. Codd developed this model at the IBM San Jose Research Lab in the 1970s. A
language to handle, define, and control data was also developed at the IBM lab: SQL. SQL
stands for Structured Query Language. SQL is a query language that interacts with a DBMS.
It allows data access without supplying physical access plans, data retrieval as sets of records,
and the performing of complex computations on the data.
Software Architectures
What is JDBC?
The JDBC stands for Java Database Connectivity. What is this JDBC besides a nifty
acronym? It refers to several things, depending on context:
• It’s a specification for using data sources in Java applets and applications.
• It’s an API for using low-level JDBC drivers.
• It’s an API for creating the low-level JDBC drivers, which do the actual
connecting/transacting with data sources.
• It’s based on the X/Open SQL Call Level Interface (CLI) that defines how
client/server interactions are implemented for database systems.
The JDBC defines every aspect of making data-aware Java applications and applets.
The low-level JDBC drivers perform the database-specific translation to the high-level JDBC
interface. This interface is used by the developer so he doesn’t need to worry about the
database-specific syntax when connecting to and querying different databases. The JDBC is a
package, much like other Java packages such as java.awt. It’s not currently a part of the
standard Java Developer’s Kit (JDK) distribution, but it is slated to be included as a standard
part of the general Java API as the java.sql package. Soon after its official incorporation into
the JDK and Java API, it will also become a standard package in Java-enabled Web browsers,
though there is no definite timeframe for this inclusion. The exciting aspect of the JDBC is
that the drivers necessary for connection to their respective databases do not require any pre-
installation on the clients: A JDBC driver can be downloaded along with an applet!
The JDBC project was started in January of 1996, and the specification was frozen in
June of 1996. Javasoft sought the input of industry database vendors so that the JDBC would
be as widely accepted as possible when it was ready for release. And, as we can see from this
list of vendors who have already endorsed the JDBC, it’s sure to be widely accepted by the
software industry:
• Borland International, Inc.
• Bulletproof
• Cyber SQL Corporation
• DataRamp
• Dharma Systems, Inc.
• Gupta Corporation
• IBM’s Database 2 (DB2)
• Imaginary (mSQL)
• Informix Software, Inc.
• Intersoft
• Intersolv
• Object Design, Inc.
• Open Horizon
• OpenLink Software
• Oracle Corporation
• Persistence Software
• Presence Information Design
• PRO-C, Inc.
• Recital Corporation
• RogueWave Software, Inc.
• SAS Institute, Inc. ™
• SCO
The JDBC is heavily based on the ANSI SQL-92 standard, which specifies that a
JDBC driver should be SQL-92 entry-level compliant to be considered a 100 percent JDBC-
compliant driver. This is not to say that a JDBC driver has to be written for an SQL-92
database; a JDBC driver can be written for a legacy database system and still function
perfectly. Even though the driver does not implement every single SQL-92 function, it is still
a JDBC driver. This flexibility will be a major selling point for developers who are bound to
legacy database systems but who still want to extend their client applications.
The JDBC is two-dimensional. The reasoning for the split is to separate the low-level
programming from the high-level application interface. The low-level programming is the
JDBC driver. The idea is that database vendors and third-party software vendors will supply
pre-built drivers for connecting to different databases. JDBC drivers are quite flexible: They
can be local data sources or remote database servers. The implementation of the actual
connection to the data source/database is left entirely to the JDBC driver. The structure of the
JDBC includes these key concepts:
• The goal of the JDBC is a DBMS independent interface, a “generic SQL database
access framework,” and a uniform interface to different data sources.
• The programmer writes only one database interface; using JDBC, the program can
access any data source without recoding.
JDBC drivers
Sun has defined four categories of JDBC drivers. The categories delineate the
differences in architecture for the drivers. One difference between architectures lies in
whether a given driver is implemented in native code or in Java code. Native code means
whatever machine code is supported by a particular hardware configuration. For example, a
driver may be written in C and then compiled to run on a specific hardware platform. Another
difference lies in how the driver makes the actual connection to the database. The four driver
types are as follows:
A type 1 JDBC driver consists of a Java part that translates the JDBC interface calls to
ODBC calls. An ODBC bridge then calls the ODBC driver of the given database i.e. the
driver converts JDBC method calls into ODBC function calls. The driver is platform-
dependent as it makes use of ODBC which in turn depends on native libraries of the
underlying operating system the JVM is running upon. Also, use of this driver leads to other
installation dependencies; for example, ODBC must be installed on the computer having the
A type 2 JDBC driver is like a type 1 driver, except the ODBC part is replaced with a
native code part instead. The native code part is targeted at a specific database product i.e.
uses the client-side libraries of the database product. The driver converts JDBC method calls
into native calls of the database native API.
This architecture eliminated the need for the ODBC driver and instead directly called the
native client libraries shipped by the database vendors. This was quickly adopted by the DB
vendors as it was quick and inexpensive to implement since they could reuse the existing C/
C++ based native libraries.
Type 3 drivers sought to be a 100% Java solution but never really gained much traction. Type
3 drivers had a Java client component and a Java server component, where the latter actually
talked to the database. Although this was technically a full Java solution, the database
vendors did not like this approach as it was costly – they would have to rewrite their native
client libraries which were all C/C++. In addition, this didn’t increase the architectural
efficiency as we are really still a 3 tier architecture so it is easy to see why this was never a
popular choice.
The JDBC type 4 driver, also known as the Direct to Database Pure Java Driver, is a database
driver implementation that converts JDBC calls directly into a vendor-specific database
protocol. It is implemented for a specific database product. Today, most JDBC drivers are
type 4 drivers.
Written completely in Java, type 4 drivers are thus platform independent. They install inside
the Java Virtual Machine of the client. This provides better performance than the type 1 and
type 2 drivers as it does not have the overhead of conversion of calls into ODBC or database
API calls. Unlike the type 3 drivers, it does not need associated software to work.
This architecture encapsulates the entirety of the JDBC API implementation along with all
the logic for communicating directly with the database in a
This type includes, for example, the widely used Oracle thin driver.
The JDBC API is contained in two packages named java.sql and javax.sql. The
java.sql package contains core Java objects of JDBC API. There are two distinct layers within
the JDBC API: the application layer, which database-application developers use and driver
layer which the drivers vendors implement. The connection between application and driver
layers is illustrated in figure below:
The java.sql package contains the JDBC API that provides database independent front-end
commands for applications. It relies on a database driver to implement a set of Java
interfaces. The driver translates the standard JDBC calls into the specific calls required by the
database it supports.
java.sql is a small API package. One of its main classes is DriverManager which is
responsible for loading and unloading drivers and making connections and logins through
drives. Interfaces Driver, Connection, Statement, and ResultSet are essential to JDBC
applications.
There are four main interfaces that every driver layer must implement and one class
that bridges the Application and driver layers. The four interfaces are Driver, Connection,
Statement and ResultSet. The Driver interface implementation is where the connection to the
database is made. In most applications, Driver is accessed through DriverManager class.
Before actual performing the Java database application, we associate the connection
of database source using JDBC – ODBC Bridge. The steps are as follows:
1. Go to Control Panel -> Administrative Tools -> Data Sources.
2. Open Data Sources ODBC icon.
3. Select the tab with heading “User DSN”.
4. Click on ‘Add’ button.
5. Select the appropriate driver as per the database to be used. (e.g. Microsoft
ODBC driver for Oracle to access Oracle Database
6. Click finish button and the corresponding ODBC database setup window will
appear.
7. Type DSN name and provide the required information such as user name and
password for the database (.mdb files) of Microsoft Access Database etc. and click
on OK button.
8. Our DSN name will get appeared in user data sources.
There are six different steps to use JDBC in our Java application program.
These can be shown diagrammatically as below:
The JDBC drivers must be loaded before the Java application connects to the DBMS.
The Class.forName() is used to load the JDBC driver. The developer must write routine that
loads the JDBC / ODBC Bridge. The bridge driver called sun.jdbc.odbc.JdbcOdbcDriver. It
is done in following way:
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
After loading the driver the application must get connected to DBMS. For this we use
DriverManager.getConnection() method. The DriverManager is highest class in Java.sql
hierarchy and is responsible for managing driver related information.
<protocol>:<subprotocol>:<dsn-name>
The ‘protocol’ is a JDBC protocol that is used to read the URL. The ‘subprotocol’ is
JDBC driver name and ‘dsn-name’ is the name of the database that we provided while
creating JDBC Bridge though control panel. We use the following URL for our application:
jdbc:odbc:customer
here, ‘customer’ is an example of DSN name given to our database. The user name
and password are also provided at the time of creating DSN. It is not compulsory to provide
the username and password. For example:
Conncetion con;
con = DriverManager.getConnection(“jdbc:odbc:customer”, “micro”, “pitch”);
Statement createStatement()
For example:
Statement st = con.createStatement();
The executeQuery() method of Statement object is used execute and process the query
which returns the ResultSet object. ResultSet is the object which actually contains the result
returned by the query. For example:
Here, the ‘customer’ is neither database name nor DSN name but it is a table name.
The ResultSet object is assigned the results received from the DBMS after the query
is processed. The ResultSet object consists of methods used to interact with data that is
returned by the DBMS to Java application program. For example, the next() method is used
to proceed throughout the result set. It returns true, if the data is available in result set to read.
The ResultSet also contains several getXxx( ) methods to read the value from
particular column of current row. For example, getString(“name”) will read the value from
column ‘name’ in the form of string. Instead of passing column name as parameter, we can
pass column as parameter also. Such as, getString(1). For example:
String
name; int
age;
do
{
name = rs.getString(“name”); age = rs.getInt(“age”);
System.out.println(name+“=”+age);
} while(rs.next());
Terminate the Connection
The Connection to the DBMS is terminated by using the close() method of the
Connection object once Java program has finished accessing the DBMS. The close( ) method
throws as exception if problem is encountered when disengaging the DBMS. For example:
con.close();
The close() method of Statement object is used to close the statement object to stop
the further processing.
Statement Objects
Once the connection to the database is opened, the Java application creates and sends
a query to access data contained in the database. One of three type of statement objects is
used to execute the query immediately. A PreparedStatement is used to execute the compiled
query and CallableStetement is used to execute the stored procedure.
1. executeQuery()
This method returns the ResultSet object that contains rows, columns and metadata
that represent data requested by the query. Its signature is:
Generally, this method is used to execute only the ‘SELECT’ query of the SQL.
2. executeUpdate()
This method is used to execute the queries that contain INSERT, DELETE and
UPDATE statements. This method returns integer indicating the number of rows that
were updated by the query. Its signature is:
For example:
It executes the given SQL statement, which may return multiple results. In some
(uncommon) situations, a single SQL statement may return multiple result sets and/or
update counts we must then use the methods getResultSet( ) or getUpdateCount( ) to
retrieve the result, and getMoreResults( ) to move to any subsequent result(s). Signature
is as follows:
For example:
if(st.execute())
rs = st.getResultSet();
A SQL query must be compiled before the DBMS processes the query. Compiling
occurs after one of the Statement object’s execution method is called. Compiling a query is
an overhead that is acceptable if the query is called once. However, compiling process can
become an expensive overhead if the query is executed several times by the same program
during the same session.
A SQL query can be precompiled and executed by using the PreparedStatement
object. In such cases a query is created similar to other queries. However, a question mark is
given on the place for the value that is inserted into the query after it is compiled. It is the
value that changes each time the query is executed.
For doing this process, we need to construct the query with question marks such as,
Such type of the query is passed as the parameter to the prepareStatement( ) method
of the Connection object which then returns the PreparedStatement object.
PreparedStatement prepareStatement()
For example:
ps.setInt(1, 100000);
This method requires two parameters. First parameter is an integer that identifies
position of the question mark placeholder and second is the value that replaces the question
mark. If the query contains two question marks we have to pass second value also using
setXxx() method.
Now, we need to use appropriate execute method depending upon type of the query
without any parameters. Such as,
ResultSet rs = ps.executeQuery();
This will generate the ResultSet object as the execution of the query. The
PreparedStatement contain all three execute methods but without any parameters as given
below:
ResultSet executeQuery( )
int executeUpdate( )
boolean execute( )
import java.sql.*;
class StudentData
{
public static void main(String args[])
{
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con =
DriverManager.getConnection("jdbc:odbc:stud");
PreparedStatement ps = con.prepareStatement("select *
from Student where Marks > ?");
ps.setInt(1,70); //set question marks place holder
ResultSet rs = ps.executeQuery(); //execute
System.out.println("Students having marks > 70 are:");
while(rs.next())
System.out.println(rs.getString(2));
con.close();
}
catch(Exception e){ }
}
}
Output:
Students having marks > 70 are:
Rakhee
Rahul
Karthik
The CallableStatement is used to call the stored procedures from within a JDBC
application program. A stored procedure is a block of code and is identified by a unique
name. The type style of code depends upon the DBMS vendor and can be written in PL/SQL,
Transact-SQL, C or another programming language. The stored procedure is executed by
invoking name of the stored procedure. For example, a stored procedure written in PL/SQL
as given below:
CREATE PROCEDURE
sp_interest (id IN INTEGER,
bal IN OUT FLOAT)
IS BEGIN
SELECT
balance
INTO bal
FROM account
WHERE account_id = id;
UPDATE account
SET balance = bal
WHERE account_id = id;
END;
The CallableStatement object uses three types of parameters when calling a stored
procedure. These parameters are IN, OUT, INOUT. The IN parameter contains the data that
needs to be passed to the stored procedure whose value is assigned using setXxx() method.
Whereas, OUT parameter contains the value returned by the stored procedure, if any. The
OUT parameter must be registered using registerOutParameter() method and afterwards this
is retrieved by using getXxx() method. The INOUT parameter is a single parameter that is
used to both pass information and retrieve information from a stored procedure.
Consider above example, the name of the stored procedure is given as, sp_interest. Its
definition is very similar to those of Java method definition. The variable ‘id’ is an input
integer parameter passed to this procedure and variable ‘bal’ is the float parameter acting as
input and output both. The stored procedure contains the SQL query code to perform certain
operations depending upon input value to the stored procedure and it returns the value in
variable ‘bal’. We can now write our code to call this procedure to pass the parameters and to
here, parameterIndex refers to the index of the parameter passed to that stored
procedure. And sqlType is type of the value which is expected to retrieve from stored
procedure. Generally, sqlType is the value of type java.sql.Types.
The syntax for invoking a stored procedure using the JDBC API is shown here. Note that the
square brackets indicate that what is between them is optional; they are not themselves part of
the syntax.
{call procedure_name}
Example :
try
{
CallableStatement statement;
statement = c.prepareCall("{call sp_interest(?,?)}");
statement.registerOutParameter(2, java.sql.Types.FLOAT);
statement.setInt(1, 310);
statement.execute( );
System.out.println("New balance:" + statement.getFloat(2));
}
statement.close( );
c.close( );
ResultSet
The ResultSet class provides methods to access data generated by a table query. This includes
a series of get methods which retrieve data in any one of the JDBC SQL type formats, either
by column number or by column name. The ResultSet object contains methods that are used
to copy data from the ResultSet into Java collection object or variable for further processing.
Data in ResultSet object is logically organized into virtual table consisting of rows and
columns. In addition to the data, the ResultSet object also contains metadata such as column
names, column size, and column data type.
import java.sql.*;
class StudentData
{
public static void main(String args[])
{
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con =
DriverManager.getConnection("jdbc:odbc:stud");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from Student");
System.out.println("The Database is:-");
System.out.println("Roll\tName\t\tMarks Pass Birth-Date");
System.out.println("=====================================");
while(rs.next())
{
int roll = rs.getInt(1);
String name = rs.getString(2);
int marks = rs.getInt("Marks");
boolean pass = rs.getBoolean(4);
Date d = rs.getDate(5);
System.out.printf("%-5d",roll);
System.out.printf("%-10s",name);
System.out.printf("%-6d",marks);
Scrollable ResultSet
The addition to the next() method, the ResultSet can also be moved backward or any other
position inside it. For doing these scrolling, we can use the following methods:
The first() method moves the virtual cursor to the first row of the ResultSet. Likewise, last()
method moves the virtual cursor to the last row of the ResultSet. The previous() method
moves the virtual cursor to the previous row of the ResultSet from current position. The
absolute() method positions virtual cursor at the row number specified by integer passed as
parameter to this method. The relative() method moves the virtual cursor the specified
number of rows virtual cursor. If this parameter is positive, virtual cursor moves forward by
that number of rows. Similarly, negative number moves the cursor backward direction by that
number of rows.
The Statement object that is created using createStatement() of Connection object must be set
up to handle a scrollable ResultSet by passing createStatement method one of three constants
given below:
TYPE_FORWARD_ONLY
TYPE_SCROLL_INSENSITIVE
TYPE_SCROLL_SENSITIVE
Updatable ResultSet
The rows contained in the ResultSet can be updatable similar to how rows in the current table
can be updated. This is made possible by passing the createStatement() method of the
Connection object the CONCUR_UPDATABLE. Alternatively, the
CONCUR_READ_ONLY constant can be passed to the createStatement() method to prevent
the ResultSet from being updated. There are three ways in which the ResultSet can be
changed. These are updating values in a row and inserting a new row. All these changes are
accomplished by using methods of Statement object.
Updating ResultSet
Once the executeQuery() method of the Statement object returns the ResultSet, the
updateXxx() method is used to change the value of column in the current row of the
ResultSet. The xxx is replaced by any data type of the column that is to be updated.
The updateXxx() method requires two parameters. The first is either the number or the name
of the ResultSet that is being updated and the second parameter is the value in the column of
the ResultSet. Such as,
For example:
s.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
r.updateString(“Name”, “Alisha”);
r.updateRow();
In above code, the current row’s column ‘Name’s value will be replaced by ‘Alisha’.
Deleting a Row The deleteRow() method is used to remove a row from ResultSet. This
method directly deletes the contents on the current row and the virtual cursor will be moved
to the next row automatically. For example:
rs.deleteRow();
Inserting a Row
Inserting a row in the ResultSet is accomplished using basically the same technique as is used
to update the ResultSet. That is, the updateXxx() method is used to specify the column and
the value that will be placed into the column of the ResultSet.
The updateXxx() requires two parameters. The first is either name of the column or number
s.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE );
r.updateString(“Name”, “Aneeta”);
r.updateInt(“Roll”, 12);
r.insertRow();
Metadata
Metadata is nothing but data about data. Database name, table name, column name, column
attributes, and other information that describes database components are known as Metadata.
For Example, the size of client’s first name column describes the data contained within the
column and therefore is referred to as metadata.
Metadata is used by JDBC application to identify database components without needing to
know details of a column, the table or the database. For example, a J2EE component can
request from the DBMS the data type of a specific column. The column type is used by a
JDBC application to copy data retrieved from the DBMS into a Java collection.
JDBC provides two meta-data interfaces:
• java.sql.ResultSetMetaData
• java.sql.DatabaseMetaData.
The meta-data described by these classes was included in the original JDBC ResultSet and
Connection classes. The extra functionality could be served by creating meta-data classes to
provide the often esoteric information required by a minority of developers.
DatabaseMetaData
This interface provides methods that tell us about the database for a given Connection object,
including:
• What tables exist in the database visible to the user?
• Is this database connection read-only?
• What keywords are used by the database, that are not SQL2?
• Does the database support column aliasing?
• Are multiple result sets from a single execute() call supported?
• Are outer joins supported?
• What are the primary keys for a table?
The JDBC application program retrieves the object of DatabaseMetaData by using the
getMetaData of the Connection object. Such as,
DatabaseMetaData dm = con.getMetaData();
Then we can use the following methods of DatabaseMetaData interface to retrieve the
metadata from the database.
ResultSetMetaData:
The ResultSetMetaData class provides extra information about ResultSet objects returned
from a database query. This class provides us with answers to the following questions:
Metadata that describes the ResultSet is retrieved by calling the getMetaData() method of
ResultSet object. This returns a ResultSetMetaData object as,
ResultSetMetaData rm = Result.getMetaData()
Once the ResultSetMetaData is retrieved, the JDBC application can call methods of
ResulSetMetaData object to retrieve specific kind of metadata. The more commonly called
methods are as follows:
1. getColumnCount()
It returns no. of columns contained in ResultSet.
2. getColumnName(int number)
It returns the name of column specified by column number.
3. getColumnType(int no)
It returns the data type of column specified by column number.
SQL Exceptions
There are three kinds of exceptions that are thrown by JDBC methods.
These are:
• SQLException
• SQLWarnings
• DataTruncation
SQLException
It commonly reflects the SQL syntax error in the query and is thrown many of the methods
contained in java.sql package. This exception is most commonly caused by connectivity
issues with the database. It can also caused by subtle coding errors like trying to access an
object that is been closed. Following SQLException class specific methods listed
below:
1. getMessage()
It gives the description of the error.
2. getSQLState()
It returns SQLState (Open Group SQL specification) identifying the
exception.
3. getErrorCode()
It returns a vendor-specific integer error code.
4. getNextException()
If more than one error occurs, they are chained together. This method is used chain to
the next exception.
For example:
try
{
... // JDBC statement
} catch (SQLException sqle) {
while (sqle != null) {
System.out.println("Message: " + sqle.getMessage());
System.out.println("SQLState: " + sqle.getSQLState());
System.out.println("Vendor Error: " +
sqle.getErrorCode());
sqle.printStackTrace(System.out);
sqle = sqle.getNextException();
}