Book Image

JDBC 4.0 and Oracle JDeveloper for J2EE Development

Book Image

JDBC 4.0 and Oracle JDeveloper for J2EE Development

Overview of this book

Table of Contents (20 chapters)
JDBC 4.0 and Oracle JDeveloper for J2EE Development
Credits
About the Author
About the Reviewer
Preface

New Features in JDBC 4.0


JDBC 4.0 specification was made available in December 2006. Most databases provide at least a partial support for the JDBC 4.0 specification, in their JDBC drivers. JDBC 4.0 specification is implemented in JDK 6.0. Some of the new features of JDBC 4.0 specification, and the database support for JDBC 4.0 specification are discussed in the following sections.

Automatic SQL Driver Loading

JDBC 4.0 has facilitated the loading of a JDBC driver. In JDBC 3.0, a JDBC driver is loaded with the Class.forName(String) method. The Oracle JDBC driver is loaded in the following manner:

Class.forName("oracle.jdbc.OracleDriver");

In JDBC 4.0, a JDBC driver is loaded automatically with the Java Standard Edition Service Provider mechanism. The JDBC driver is loaded when the java.sql.DriverManager.getConnection() method is invoked. To load a JDBC driver with the Service Provider mechanism, JDBC 4.0 drivers should include the META-INF/services/java.sql.Driver file. In the java.sql.Driver file, specify the JDBC driver class to load. If the oracle.jdbc.OracleDriver is to be loaded then specify the following line in the java.sql.Driver file:

oracle.jdbc.OracleDriver

Multiple driver classes can be specified in a java.sql.Driver file, each on a separate line. A list of JDBC drivers available to a DriverManager can be obtained with the getDrivers() method:

Enumeration<Driver> drivers=DriverManager.getDrivers();

A JDBC connection can be obtained using the getConnection() method of the DriverManager class:

String url="jdbc:oracle:thin:@localhost:1521:ORCL";
Connection connection = DriverManager.getConnection(url,"oe", "pw");

Enhanced Data Type Support

JDBC 4.0 has added support for some new SQL data types. The ROWID SQL data type, which identifies a row in a table, is mapped to the java.sql.RowId Java data type. The Reader method, readRowId() has been added to the SQLInput interface, and the writer method, writeRowId(), has been added to the SQLOutput interface to read, and write ROWID values.

In JDBC 3.0, JDBC drivers supported only Unicode character set. SQL: 2003 standard has added support for SQL types, NCAHR, NVARCHAR, LONGVARCHAR, and NCLOB in which values are encoded using the National Character Set (NCS). The National Character Set SQL data type values were converted to the Unicode Character Set values with a JDBC 3.0 driver. The NCS data types can be more suitable if extensive character processing operations are required. Support for National Character Set database data types, NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB have been added in JDBC 4.0.

Setter methods, setNString(), setNCharacterStream(), and setNClob() have been added to the PreparedStatement and CallableStatement interfaces. Getter method, getNString(), getNCharacterStream(), and getNClob() have been added to the CallableStatement and ResultSet interfaces. Updater methods, updateNString(), updateNCharacterStream(), and updateNClob() have been added to the ResultSet interface. To create a NClob object, createNClob() method has been added to the Connection interface. Reader methods, readNString() and readNClob() have been added to the SQLInput interface to read the NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB values. Writer methods, writeNClob() and writeNString() have been added to the SQLOutput interface to write the NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB values.

In JDBC 4.0, support for BLOB and CLOB SQL data types have been enhanced. To create java.sql.Blob and java.sql.Clob objects, methods such as createBlob() and createClob() have been added to the Connection interface. In the PreparedStatement and CallableStatement interfaces, setBlob() method has been overloaded to set the Blob values from an InputStream, and setClob() method has been overloaded to set the Clob values from a Reader. In the ResultSet interface, the updater method, updateBlob(), has been overloaded to update a column from an InputStream and the updater method, updateClob(), has been overloaded to update a column from a Reader. To free resources in Blob and Clob objects, a method, free(), has been added to the Blob and Clob interfaces.

The setAsciiStream, setBinaryStream, and setCharacterStream methods in the CallableStatement and PreparedStatement interfaces have been overloaded. These interfaces have been overloaded to support the length parameter of type long in addition to the length parameter of type int. The length parameter specifies the length in bytes or characters of the InputStream or Reader object. Also, the setAsciiStream, setBinaryStream, and setCharacterStream methods in the CallableStatement and PreparedStatement interfaces have been overloaded with versions without the length parameter.

The setBlob() method in the CallableStatement and PreparedStatement interfaces has been overloaded with the other two methods to set parameter values from the InputStream object, one with a length parameter for the length of the binary stream, and the other without a length parameter. If the InputStream length does not match the specified length, an SQLException is generated. The setClob() method in the CallableStatement and PreparedStatement interfaces has been overloaded with other two methods to set parameter values from the Reader object, one with a length parameter for the number of characters in the Reader object and the other without a length parameter.

If the number of characters in the Reader object does not match the specified length, an SQLEception is generated. Similar to the setter methods in the PreparedStatement/CallableStatement, the updateAsciiStream, updateBinaryStream, updateBlob, updateCharacterStream, and updateClob methods in the ResultSet interface have been overloaded. Unlike the setBlob and setClob methods of the PreparedStatement and CallableStatement interfaces, the updateBlob and updateClob methods of the ResultSet interface do not generate an SQLException, if the InputStream/Reader length does not match the specified length.

SQL: 2003 XML Data Type Support

The SQL: 2003 standard supports a new data type, XML, for storing XML documents. With the XML data type, an XML document can be stored in a database table column similar to the other data types. JDBC 4.0 supports the SQL: 2003 standard. The java.sql.SQLXML object is the Java mapping for the database type, XML. Prior to the SQLXML Java data type, an XML type column value could be retrieved only as a String or CLOB, which did not include the functionality to access different nodes in an XML document.

An XML type database column can be mapped to a Java data type with the help of SQLXML data type. In JDBC 4.0 specification, a java.sql.Connection object has the provision to create an SQLXML object that initially does not have any data. The data can be added with the setString() method or the setBinaryStream(), setCharacterStream(),and setResult() methods. An SQLXML object can be retrieved from a ResultSet or a CallableStatement by using the overloaded getSQLXML() method. The data in an SQLXML object can be retrieved by using the getString() method or the getBinaryStream(), getCharacterStream(), and getSource() methods. An SQLXML object can be stored in a database table column of type XML, which is similar to any other data type using the setSQLXML() method of the PreparedStatement interface.

SQL Server 2005 EXPRESS supports the XML data type whereas, SQL Server 2000 does not. IBM's DB2 UDB V 9 also supports the XML data type. To find out if a database supports the XML data type, obtain the database metadata from the Connection object:

DatabaseMetaData metadata= connection.getMetaData();

The data types are supported with the getTypeInfo() method, as shown below:

ResultSet rs=metadata.getTypeInfo();

Iterate over the data type result set and output the TYPE_NAME column, as shown below:

System.out.println("TYPE_NAME:"+rs.getString("TYPE_NAME"));

For SQL Server 2005 and IBM's DB2 UDB v9, the XML TYPE_NAME is output:

TYPE_NAME: XML

In the following subsections, the procedures to create an XML document, store it in a database that supports the XML data type, and retrieve it from the database will be discussed.

Generating an XML Document

We will discuss the procedure to create and initialize an SQLXML object. Import the java.sql package, and the javax.xml.stream package:

import java.sql.*;
import javax.xml.stream.*;

The Java representation of an XML document in a database table is the SQLXML object. Create an SQLXML object from the Connection object with the createSQLXML() method, as shown below:

SQLXML sqlXML=connection.createSQLXML();

An SQLXML object can be initialized using one of the setString(), setBinaryStream(), setCharacterStream(), or setResult() methods. An SQLXML object can be initiated using the setResult() method and the StAXResult class. Create an XMLStreamWriter object from a StAXResult object, as shown below:

StAXResult staxResult = sqlXML.setResult(StAXResult.class);
XMLStreamWriter xmlStreamWriter = staxResult.getXMLStreamWriter();

The SQLXML object becomes non-writable after the setResult()method is invoked. Add the start of an XML document with the writeStartDocument(String,String) method, as shown below:

xmlStreamWriter.writeStartDocument("UTF-8","1.0");

The encoding and version of the XML document is specified in the writeStartDocument method. Add the start of an element with the writeStartElement(String localName) method, as shown below:

xmlStreamWriter.writeStartElement("catalog");

Add the element attributes by using the writeAttribute(String localName, String value) method. Add an element of text by using the writeCharacters(String text) method. Each start element would have a corresponding end element tag. Add an end element by using the writeEndElement() method. The writeEndElement() method does not specify the element name as the writeStartElement(String) method:

xmlStreamWriter.writeEndElement();

Add end of the document by using the writeEndDocument() method:

xmlStreamWriter.writeEndDocument();

A SQLXML object can also be initiated using the SAXResult class. Create a SAXResult object using the setResult() method of the SQLXML interface. Subsequently, obtain the ContentHandler result using the getHandler() method:

SAXResult saxResult = sqlXML.setResult(SAXResult.class);
ContentHandler contentHandler= saxResult.getHandler();

Specify the start of an XML document using the startDocument() method:

contentHandler.startDocument();

Specify the start of an element using the startElement(String uri,String localName,String qName,Attributes atts) method in which the parameter uri specifies the element namespace, parameter localName specifies the element local name, parameter qName specifies the element qualified name and parameter atts of type Attributes specifies the element attributes. An Attributes object can be created using the org.xml.sax.helpers.AttributesImpl class, which implements the Attributes interface. An attribute can be added to the AttributesImpl object using the addAttribute(String uri, String localName, String qName, String type, String value) method:

AttributesImpl.AttributesImpl() attrs=new AttributesImpl();
attrs.addAttribute("","","journal","StringType","OracleMagazine");
contentHandler.startElement("","","catalog",attrs);

The end of an element is specified with the endElement(String uri,String localName,String qName) method. Also specify the end of the document with the endDocument() method:

contentHandler.endElement("","","catalog");
contentHandler.endDocument();

An SQLXML object can also be initiated using the setCharacterStream() method. Create a Writer object from the SQLXML object using the setCharacterStream() method. Create a BufferedReader object from an input XML file. Read from the BufferedReader, and output to the Writer object:

Writer writer= sqlXML.setCharacterStream();
BufferedReader bufferedReader = new BufferedReader(new FileReader(new File("C:/catalog.xml")));
String line= null;
while((line = bufferedReader.readLine() != null) {
writer.write(line);
}

The SQLXML object becomes non-writable after the setCharacterStream() method is invoked. An XML document can also be added to an SQLXML object with the setString() method, as shown below:

sqlXML.setString("xmlString");

The SQLXML object becomes non-writable after invoking the setString() method. If the setString(), setBinaryStream(), setCharacterStream(), or setResult() method is invoked on an SQLXML object that has been previously initiated, a SQLException is generated. If any of the setBinaryStream(), setCharacterStream(), or setResult() methods are invoked more than once, a SQLException is generated, and the previously returned InputStream, Writer, or Result object is not effected.

Storing an XML Document

The SQLXML Java data type is stored in an XML document, just like any other Java data type. Create a database table with an XML type column. Run the SQL statement to create a database table, and obtain a Statement object from the Connection object, as shown below:

Statement stmt=connection.createStatement();

Create a database table, Catalog with an XML type column, as shown below:

stmt.executeUpdate("CREATE Table Catalog(CatalogId int, Catalog XML)");

Create a PreparedStatement object to add values to a database table, as shown in the following listing:

PreparedStatement statement=connection.prepareStatement("INSERT INTO CATALOG(catalogId, catalog) VALUES(?,?)");

Set the int value with the setInt() method and the SQLXML value with the setSQLXML() method, as shown below:

stmt.setInt(1, 1);
stmt.setSQLXML(2, sqlXML);

Update the database with the executeUpdate() method:

stmt.executeUpdate();

Retrieving an XML Document

An XML database data type row is retrieved as an SQLXML Java data type. Create a PreparedStatement for a SELECT query, as shown below:

PreparedStatement stmt=connection.prepareStatement("SELECT * FROM CATALOG WHERE catalogId=?");

Specify the catalogId value for which an XML document is to be retrieved:

stmt.setInt(1, 1);

Obtain a result set with the executeQuery() method:

ResultSet rs=stmt.executeQuery();

Obtain the SQLXML object for the catalog column of type XML, as shown below:

SQLXML sqlXML=rs.getSQLXML("Catalog");

Output the XML document in the SQLXML object by using the getString() method:

System.out.println(sqlXML.getString());

Accessing an XML Document Data

The XMLStreamReader interface can be used to read an XML document with an event iterator. An XMLStreamReader object is obtained from a SQLXML object, as shown below:

InputStream binaryStream = sqlXML.getBinaryStream();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader xmlStreamReader = factory.createXMLStreamReader(binaryStream);

The SQLXML object becomes non-readable after calling the getBinaryStream() method. The next event is obtained by using the next() method, as shown below:

while(xmlStreamReader.hasNext())
{
int parseEvent=xmlStreamReader.next();
}

The next() method returns an int value that corresponds to an XMLStreamConstants constant, which represents an event type. Some of the return values of the next() method are listed in following table:

Event Type

Description

ATTRIBUTE

Specifies an attribute.

CDATA

Specifies a Cdata.

CHARACTERS

Text.

COMMENT

An XML document comment.

NOTATION_DECLARATION

Specifies a notation declaration.

START_DOCUMENT

Specifies the start of a document

START_ELEMENT

Specifies the start of an element.

END_ELEMENT

Specifies the end of an element.

ENTITY_DECLARATION

Specifies an entity declaration.

ENTITY_REFERENCE

Specifies an entity reference.

NAMESPACE

Specifies a namespace declaration.

SPACE

Specifies an ignorable white space.

If the return value is ELEMENT, then the local name, prefix, and namespace can be obtained by using the getLocalName(), getPrefix(), and getNamespaceURI() methods, as shown below:

System.out.println("Element Local Name: "+xmlStreamReader.getLocalName());
System.out.println("Element Prefix: "+xmlStreamReader.getPrefix());
System.out.println("Element Namespace:"+xmlStreamReader.getNamespaceURI());

The attribute count in an element is obtained by using the getAttributeCount() method. Iterate over the attributes and obtain the attribute local name by using the getAttributeLocalName() method, the attribute value with the getAttributeValue() method, the attribute prefix with the getAttributePrefix() method, and the attribute namespace with the getAttributeNamespace() method:

for(int i=0; i<xmlStreamReader.getAttributeCount();i++){
System.out.println("Attribute Prefix:"+xmlStreamReader.getAttributePrefix(i));
System.out.println("Attribute Namespace:"+xmlStreamReader.getAttributeNamespace(i));
System.out.println("Attribute Local Name:"+xmlStreamReader.getAttributeLocalName(i));
System.out.println("Attribute Value:"+xmlStreamReader.getAttributeValue(i));
SQL 2003 XML data type supportXML document data, accessing}

Support for Wrapper Pattern

Some vendor-specific JDBC resources that provide nonstandard JDBC methods are wrapped for architectural reasons. Such JDBC resources can be unwrapped to access instances with the wrapper pattern. Support for wrapper pattern is implemented in the Wrapper interface. With the Wrapper interface, resources that are wrapped as proxy classes can be accessed. The objective of the Wrapper interface is to provide a standard method to access vendor-specific extensions inside standard JDBC objects, such as, Connections, Statements, and ResultSets. The Wrapper interface is extended by the following interfaces:

  • java.sql.Connection

  • java.sql.DataSource

  • java.sql.ResultSet

  • java.sql.Statement

  • java.sql.DatabaseMetaData

  • java.sql.ResultSetMetaData

  • java.sql.ParameterMetaData

The Wrapper interface provides the methods isWrapperFor(Class<?>) and unwrap(Class<?>). The unwrap() method takes an interface as a parameter, and returns an Object that implements the interface. The object that is returned is either the object found to implement the specified interface, or a proxy for that object. The isWrapperFor() method returns a boolean. This method is used to find out if an instance implements the specified interface, or if an instance is a wrapper for an object that implements the specified interface. If the object implements the specified interface the value returned is true. If the object is a wrapper for the specified interface, the isWrapperFor()method is invoked recursively on the wrapped object. If the object does not implement the interface and is not a wrapper for the interface, the value returned is false. The unwrap() method should be invoked, if the isWrapperFor() method returns true.

Create an object of type, java.sql.PreparedStatement and check if the object is a wrapper for the Oracle JDBC specific interface, oracle.jdbc.OraclePreparedStatement using the isWrapperFor() method. If the object is a wrapper for the interface, create an instance of the oracle.jdbc.OraclePreparedStatement JDBC interface using the unwrap() method:

String url="jdbc:oracle:thin:@localhost:1521:ORCL";
Connection connection = DriverManager.getConnection(url,"oe", "pw");
String sql="INSERT INTO CATALOG(catalogId, journal) VALUES(?,?)"
java.sql.PreparedStatement stmt = connection.prepareStatement(sql);
Class class = Class.forName("oracle.jdbc.OraclePreparedStatement");
if(stmt.isWrapperFor(class))
{
OraclePreparedStatement ops = (OraclePreparedStatement)stmt.unwrap(class);
ops.defineColumnType(2, oracle.jdbc.OracleTypes.VARCHAR,4000);
}

Enhancements in SQLException

An error in interaction with the datasource is represented with the SQLException class. JDBC 4.0 has enhanced support for navigation of chained SQLExceptions with the iterator() method in the SQLException class. A chained SQLException is an Exception that is linked with other Exceptions. The iterator() method iterates over the chained exceptions and the chained causes. Chained exceptions can be retrieved and iterated over (without having to invoke the getNextException() and getCause() methods recursively) using the enhanced For-Each loop introduced in J2SE 5. When an SQLException is generated using the For-Each loop, the chained exceptions can be output as shown below:

catch(SQLException sqlException)
{
for(Throwable e : sqlException )
{
System.out.println("Error encountered: " + e);
}
}

In JDBC 4.0, four constructors have been added to the SQLException class with the Throwable cause as one of the parameters. The getCause() method can return non-SQLExceptions. In JDBC 4.0, three new categories of SQLExceptions have been added, which are as follows:

  • SQLTransientException

  • SQLNonTransientException

  • SQLRecoverableException

Categorization of the SQLExceptions facilitates the portability of error handling code. SQLTransientException and SQLNonTransientException classes have subclasses, which map to common SQLState class values. SQLState class provides JDBC application's return code information about the most recently executed SQL statement. The return code is sent by the database manager after the completion of each SQL statement. The SQLState class values are defined in the SQL: 2003 specification.

A SQLTransientException indicates that the operation that generates the exception could succeed, if retried. Subclasses of the SQLTransientException class are discussed in following table:

SQLException

SQLState Class Value

Description

SQLTransient

ConnectionException.

08

Represents that a connection operation that failed could succeed, if the operation is retried.

SQLTransaction

RollbackException.

40

Represents that a current Statement was rolled back.

SQLTimeoutException.

Does not correspond to a standard SQLState.

Represents that a Statement has timed out.

SQLNonTransientException indicates the operation, which generates the exception that will not succeed without the cause of the SQLException being rectified. Subclasses of the SQLNonTransientException are discussed in following table:

SQLException

SQLState Class Value

Description

SQLFeatureNotSupported Exception.

0A

Represents that a JDBC driver does not support a feature.

SQLNonTransientConnection Exception.

08

Represents that a connection operation that failed will not succeed if retried, without the cause of the exception being corrected.

SQLDataException.

22

Represents various data errors including non allowable conversion and division by 0.

SQLIntegrityConstraint

ViolationException.

23

Represents an integrity constraint exception.

SQLInvalidAuthorization SpecException.

28

Represents an authorization exception.

SQLSyntaxErrorException.

42

Represents an error in the SQL syntax.

The SQLRecoverableException indicates that the operation that throws the Exception can succeed, if the application performs some recovery steps and retries the entire transaction(or the transaction branch in the case of a distributed transaction). The recovery steps include at the least, closing the current connection and obtaining a new connection.

A new subclass of the SQLException class, SQLClientInfoException, has been added in the JDBC 4.0 specification. The SQLClientInfoException is generated, if one or more client info properties could not be set on a Connection. The SQLClientInfoException also lists the client info properties, which were not set. Some databases that do not allow multiple client info properties to be set atomically can generate the SQLClientInfoException exception after one or more client info properties have been set. The client info properties that were not set can be retrieved by using the getFailedProperties() method.

Connection Management

Connection pooling improves the performance and scalability of the connections by providing a cache of the connections that are reusable across client sessions. Connection pooling reduces the overhead of opening, initializing and closing connections. One of the drawbacks of the connection pooling is that when a connection in a connection pool becomes stale and unusable, the application performance is reduced. JDBC 3.0 specification did not have the provision to track connection state. Connection state tracking has been added to the Connection interface in the JDBC 4.0 to find out if a connection is valid. The isValid(int timeout) method returns true, if the connection is valid. The isValid() method validates a connection with a SQL query, or another mechanism. If a connection is not valid, the connection can be closed, thus reducing the accumulation of unusable connections. The Connection object conn can be closed, if it is not in use:

if(!conn.isClosed())
if(!conn.isValid())
conn.close();

Connection state tracking and closing of invalid connections are implemented by the connection pool manager. Another drawback of connection pooling has been that one or more connections assigned from a connection pool in a web or application server can bog down an application. JDBC 3.0 does not have the provision to identify the connections that use the excess of CPU time. JDBC 4.0 has added the setClientInfo() and getClientInfo() methods to the Connection interface using which, client specific information can be specified on a Connection object, when a Connection is assigned to an application. Client specification information includes user name and application name. The DatabaseMetaData interface in JDBC 4.0 provides a new method, getClientInfoProperties(). Client info properties supported by a JDBC driver can be obtained using the getClientInfoProperties() method. When one or more connections bog down the application, the getClientInfo() method can be used to identify which connections could be causing the reduction in performance. Some standard client info properties that a JDBC driver can support are discussed in the following table:

Client Info Property

Description

ApplicationName.

The name of the application that is using the connection.

ClientUser.

The name of the user.

ClientHostname.

The hostname on which the application is running.

Similar to connection pooling, JDBC 4.0 provides Statement pooling to reduce the overheads of opening, initiating, and closing Statement objects. Frequently used Statement objects can be pooled using the setPoolable(boolean poolable) method. The isPoolable() method is used to check if a Statement object is poolable. The Statement object, stmt can be pooled, if poolable:

if(stmt.isPoolable())
stmt.setPoolable(true);

Scalar Functions

Most databases support numeric, string, time, date, system, and conversion functions on the scalar values. SQL statements run using the Statement object, and can include the scalar functions using the JDBC escape syntax. JDBC 4.0 provides some new scalar function, which are discussed in the following table:

Scalar Function

Description

CHAR_LENGTH CHARACTER_LENGTH

Returns the length of a string expression.

CURRENT_DATE

Returns the current date.

CURRENT_TIME

Returns the current time.

CURRENT_TIMESTAMP

Returns the current timestamp.

EXTRACT

Extracts a field from a datetime value.

OCTET_LENGTH

Returns the length of a string expression in octets (bytes).

JDBC 4.0 support in Oracle Database

Support for JDBC 4.0 specification is a JDBC driver feature, and not a database feature. Oracle Database 11g JDBC drivers support JDBC 4.0 specification. Add the ojdbc6.jar file to the CLASSPATH environment variable to use the JDBC 4.0 features. JDK 6.0 is required for JDBC 4.0 support. Oracle database 11g JDBC drivers can be used with the Oracle database 9i and the later versions. Oracle database 11g JDBC drivers support all the JDBC 4.0 features except the SQLXML Java data type that is used to access the SQL data type XML. Oracle database 11g JDBC drivers support the wrapper pattern to access non-standard Oracle JDBC resources. Oracle extensions to the JDBC are available in the oracle.jdbc package.

The oracle.jdbc.OracleStatement interface can be unwrapped using the unwrap() method to create a oracle.jdbc.OracleStatement object. As the Statement interface extends the Wrapper interface, create a Statement object from a Connection object, conn. Check if the Statement object is a wrapper for the oracle.jdbc.OracleStatement interface using the isWrapperFor() method. Obtain a OracleStatement object from the interface using the unwrap() method to use the methods of the OracleStatement interface:

Statement stmt = conn.createStatement();
Class class = Class.forName("oracle.jdbc.OracleStatement");
if(stmt.isWrapperFor(class))
{
OracleStatement oracleStmt = (OracleStatement)stmt.unwrap(class);
oracleStmt.defineColumnType(1, Types.NUMBER);
}

Oracle database 11g JDBC drivers support the enhanced chained exceptions in the JDBC 4.0 SQLException class. JDBC 4.0 has added a distinction between the permanent errors and transient errors. Permanent errors are errors that occur in the correct operation of the database system and continue to recur, until the cause of the error is removed. Transient errors are errors occurring due to the failure of some segment of the system, or due to timeouts, and these may not recur if the operation that generated the error is retried. Oracle database 11g JDBC drivers support the different categories of SQLException.

Oracle database 11g JDBC drivers support the ROWID SQL data type. Each table in an Oracle database has a ROWID pseudocolumn that identifies a row in a table. The SQL data type of the ROWID column is ROWID. Usually a rowid uniquely identifies a row in a database. But rows in different tables that are stored in a cluster may have the same rowid. Rowids should not be used as the primary key for a database table. If a row is deleted and reinserted using an Import or Export utility, its rowid may get modified. If a row is deleted, its rowid can be assigned to a row added later. The ROWID pseudocolumn can be used in the SELECT and WHERE clauses. Rowid values have the following applications:

  1. 1. Rowids are the fastest way to access a row in a database table.

  2. 2. Rowids are unique identifiers for rows in a table.

  3. 3. Rowids represent how rows are stored in a table.

A ROWID column value can be retrieved using the getter methods in the ResultSet and CallableStatement interfaces. Retrieve the ROWID column value for the current row in a ResultSet object, rs, as shown below:

java.sql.RowId rowid=rs.getRowId();

A RowId object is valid till the identified row is not deleted. A RowId duration of the validity can be obtained using the getRowIdLifetime() method of the DatabaseMetaData interface. The duration of validity can be one of the int values in the following table:

int Value

Description

ROWID_UNSUPPORTED

Databases do not support the ROWID SQL data type.

ROWID_VALID_TRANSACTION

Valid for the duration of transaction in which it is created.

ROWID_VALID_SESSION

Valid for the duration of a session in which it is created across all transactions.

ROWID_VALID_FOREVER

Valid across all sessions.

ROWID_VALID_OTHER

Validity not known.

A RowId value can be used with a parameterized PreparedStatement to set a parameter value with a RowId object. A RowId value can also be used with an updatable ResultSet to update a column with a RowId object.

Oracle database 11g JDBC drivers support the National Character Set (NCS) data types NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB. Oracle database 11g drivers also support Large Object data types (LOBs). The Connection interface provides createBlob, createClob, and createNClob methods to create Blob, Clob, and NClob objects. Create a Blob object as shown below:

String url="jdbc:oracle:thin:@localhost:1521:ORCL";
Connection connection = DriverManager.getConnection(url,"oe", "pw");
Blob aBlob = connection.createBlob();

The LOB objects created do not contain any data. Data can be added using the setter methods in the Blob, Clob, and NClob interfaces. To add data to the Blob object, obtain an OutputStream object from the Blob object:

OutputStream outputStream=aBlob.setBinaryStream(1);

LOB objects can be used as input parameters with a PreparedStatement object using the setBlob, setClob, and setNClob methods. The Blob object created previously can be set as a parameter value on a PreparedStatement object, pstmt, as follows:

pstmt.setBlob(2,aBlob);

For an updatable ResultSet, the updateBlob, updateClob, and updateNClob methods can be used to update a Blob, Clob, or NClob column value. Update a ResultSet object, rs, of column type, BLOB, with the Blob object already created:

rs.updateBlob(3,aBlob);

Blob, Clob, and NClob data can be retrieved using the getBlob, getClob, and getNClob methods in the ResultSet and CallableStatement interfaces. Retrieve a Blob object corresponding to a BLOB column from a ResultSet object, rs :

Blob blob=rs.getBlob(2);

Either the entire data in a Blob object can be retrieved using the getBinaryStream() method, or the partial data in the Blob object can be retrieved using the getBinaryStream(long pos,long length) method. Here, the parameter, pos, specifies the offset position for start of data retrieval and the length parameter specifies the length in bytes of the data to be retrieved. Retrieve 100bytes of data from the Blob object that was created previously with an offset position of 200:

InputStream inputStream = aBlob.getBinaryStream(200, 100);

LOBs are valid at least for the duration of the transaction in which it is created. For long running transactions, it can be better to release LOB resources using the free() method:

aBlob.free();

JDBC 4.0 support in MySQL Database

MySQL database server provides support for the JDBC 4.0 specification in the Connector/J 5.1 JDBC drivers. MySQL's Connector/J 5.1 supports the JDBC 4.0 features, listed below:

  1. 1. Auto-registration of the JDBC driver with the DriverManager via the J2SE Service Provider mechanism.

  2. 2. Connection validity check using the isValid() method of the Connection interface.

  3. 3. Categorized SQLExceptions based on recoverability or retry-ability, and class of the underlying error.

  4. 4. Unwrapping of MySQL-specific extensions for JDBC.

  5. 5. Support for SQLXML. MySQL database does not support the SQL: 2003 SQL data type XML. JDBC 4.0 specification does not specify that the SQL data type to store a SQLXML object is required to be the SQL: 2003 XML data type. MySQL's Connector/J 5.1 JDBC driver supports the SQLXML Java data type.

  6. 6. Support for setting per-connection client info using the setClientInfo() method of the Connection interface.

  7. 7. Support for National Character Set data types NCHAR, NVARCHAR, LONGNVARCHAR, and NCLOB.

JDBC 4.0 support in IBM's DB2 UDB

IBM Data Server Driver for JDBC and SQLJ Version 4.0 supports the JDBC 4.0 specification. To use the JDBC 4.0 features, add the db2jcc4.jar file to the CLASSPATH environment variable. The JDBC 4.0 driver name is,"IBM Data Server Driver for JDBC and SQLJ" instead of the previous, "IBM DB2 JDBC Universal Driver Architecture". IBM Data Server Driver for JDBC and SQLJ supports most of the JDBC 4.0 features.

JDBC support has been added for the JDBC 4.0 java.sql.RowId interface for updating and retrieving data in ROWID columns. JDBC support has also been added for the java.sql.SQLXML interface for storing, updating, and retrieving data in XML columns. The IBM Data Server Driver for JDBC and SQLJ supports the following client info properties to identify the client connections:

  1. 1. ApplicationName

  2. 2. ClientAccountingInformation

  3. 3. ClientHostname

  4. 4. ClientUser

IBM Data Server Driver for JDBC and SQLJ supports the new SQLException subclasses, in the JDBC 4.0 specification. It also supports chained exceptions. The wrapper pattern is supported to access vendor-specific resources. The following IBM Data Server Driver for JDBC and SQLJ-specific interfaces in the com.ibm.db2.jcc package extend the Wrapper interface:

  1. 1. DB2Connection

  2. 2. DB2BaseDataSource

  3. 3. DB2SimpleDataSource

  4. 4. DB2Statement

  5. 5. DB2ResultSet

  6. 6. DB2DatabaseMetaData