JDBC Developers Guide - Oracle - 11g
JDBC Developers Guide - Oracle - 11g
July 2008
This book describes how to use Oracle JDBC drivers to
develop powerful Java database applications.
Oracle Database JDBC Developer's Guide and Reference, 11g Release 1 (11.1)
B31224-04
Primary Author: Tulika Das, Venkatasubramaniam Iyer, Elizabeth Hanes Perry, Brian Wright, Thomas
Pfaeffle
Contributor: Kuassi Mensah, Douglas Surber, Paul Lo, Ed Shirk, Tong Zhou, Jean de Lavarene, Rajkumar
Irudayaraj, Ashok Shivarudraiah, Angela Barone, Rosie Chen, Sunil Kunisetty, Joyce Yang, Mehul
Bastawala, Luxi Chidambaran, Srinath Krishnaswamy, Longxing Deng, Magdi Morsi, Ron Peterson,
Ekkehard Rohwedder, Catherine Wong, Scott Urman, Jerry Schwarz, Steve Ding, Soulaiman Htite, Anthony
Lai, Prabha Krishna, Ellen Siegal, Susan Kraft, Sheryl Maring
The Programs (which include both the software and documentation) contain proprietary information; they
are provided under a license agreement containing restrictions on use and disclosure and are also protected
by copyright, patent, and other intellectual and industrial property laws. Reverse engineering, disassembly,
or decompilation of the Programs, except to the extent required to obtain interoperability with other
independently created software or as specified by law, is prohibited.
The information contained in this document is subject to change without notice. If you find any problems in
the documentation, please report them to us in writing. This document is not warranted to be error-free.
Except as may be expressly permitted in your license agreement for these Programs, no part of these
Programs may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any
purpose.
If the Programs are delivered to the United States Government or anyone licensing or using the Programs on
behalf of the United States Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS Programs, software, databases, and related documentation and technical data
delivered to U.S. Government customers are "commercial computer software" or "commercial technical data"
pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As
such, use, duplication, disclosure, modification, and adaptation of the Programs, including documentation
and technical data, shall be subject to the licensing restrictions set forth in the applicable Oracle license
agreement, and, to the extent applicable, the additional rights set forth in FAR 52.227-19, Commercial
Computer Software--Restricted Rights (June 1987). Oracle USA, Inc., 500 Oracle Parkway, Redwood City, CA
94065.
The Programs are not intended for use in any nuclear, aviation, mass transit, medical, or other inherently
dangerous applications. It shall be the licensee's responsibility to take all appropriate fail-safe, backup,
redundancy and other measures to ensure the safe use of such applications if the Programs are used for such
purposes, and we disclaim liability for any damages caused by such use of the Programs.
Oracle, JD Edwards, PeopleSoft, and Siebel are registered trademarks of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective owners.
The Programs may provide links to Web sites and access to content, products, and services from third
parties. Oracle is not responsible for the availability of, or any content provided on, third-party Web sites.
You bear all risks associated with the use of such content. If you choose to purchase any products or services
from a third party, the relationship is directly between you and the third party. Oracle is not responsible for:
(a) the quality of third-party products or services; or (b) fulfilling any of the terms of the agreement with the
third party, including delivery of products or services and warranty obligations related to purchased
products or services. Oracle is not responsible for any loss or damage of any sort that you may incur from
dealing with any third party.
Contents
Part I Overview
1 Introducing JDBC
Overview of Oracle JDBC Drivers ........................................................................................................ 1-1
Common Features of Oracle JDBC Drivers .................................................................................... 1-2
Choosing the Appropriate Driver.................................................................................................... 1-4
Feature Differences Between JDBC OCI and Thin Drivers.......................................................... 1-4
Environments and Support .................................................................................................................... 1-4
Supported JDK and JDBC Versions................................................................................................. 1-5
JNI and Java Environments .............................................................................................................. 1-5
JDBC and IDEs.................................................................................................................................... 1-5
Feature List ................................................................................................................................................ 1-5
2 Getting Started
Version Compatibility for Oracle JDBC Drivers................................................................................ 2-1
Verification of a JDBC Client Installation........................................................................................... 2-2
Check the Installed Directories and Files ....................................................................................... 2-2
Check the Environment Variables ................................................................................................... 2-3
Ensure that the Java Code Can Be Compiled and Run ................................................................ 2-4
Determine the Version of the JDBC Driver .................................................................................... 2-5
Test JDBC and the Database Connection........................................................................................ 2-5
Basic Steps in JDBC ................................................................................................................................. 2-7
Importing Packages ........................................................................................................................... 2-8
iii
Opening a Connection to a Database .............................................................................................. 2-8
Creating a Statement Object ............................................................................................................. 2-9
Running a Query and Retrieving a Result Set Object................................................................... 2-9
Processing the Result Set Object ................................................................................................... 2-10
Closing the Result Set and Statement Objects............................................................................. 2-10
Making Changes to the Database ................................................................................................. 2-11
Committing Changes...................................................................................................................... 2-13
Closing the Connection .................................................................................................................. 2-13
Sample: Connecting, Querying, and Processing the Results........................................................ 2-13
Stored Procedure Calls in JDBC Programs....................................................................................... 2-14
PL/SQL Stored Procedures ........................................................................................................... 2-15
Java Stored Procedures................................................................................................................... 2-15
Processing SQL Exceptions ................................................................................................................. 2-15
4 Oracle Extensions
Overview of Oracle Extensions ............................................................................................................. 4-1
Features of the Oracle Extensions ........................................................................................................ 4-2
Database Management Using JDBC................................................................................................ 4-2
Support for Oracle Data Types......................................................................................................... 4-2
Support for Oracle Objects................................................................................................................ 4-3
Support for Schema Naming ............................................................................................................ 4-4
DML Returning .................................................................................................................................. 4-4
Accessing PL/SQL Index-by Tables................................................................................................ 4-5
iv
Oracle JDBC Packages............................................................................................................................. 4-5
Package oracle.sql .............................................................................................................................. 4-5
Package oracle.jdbc ......................................................................................................................... 4-10
Oracle Character Data Types Support ............................................................................................... 4-10
SQL CHAR Data Types .................................................................................................................. 4-10
SQL NCHAR Data Types............................................................................................................... 4-10
Class oracle.sql.CHAR.................................................................................................................... 4-11
Additional Oracle Type Extensions ................................................................................................... 4-13
Oracle ROWID Type....................................................................................................................... 4-13
Oracle REF CURSOR Type Category ........................................................................................... 4-14
Oracle BINARY_FLOAT and BINARY_DOUBLE Types ......................................................... 4-16
Oracle SYS.ANYTYPE and SYS.ANYDATA Types ................................................................... 4-16
The oracle.jdbc Package ................................................................................................................. 4-19
Interface oracle.jdbc.OracleConnection ................................................................................ 4-21
Interface oracle.jdbc.OracleStatement................................................................................... 4-22
Interface oracle.jdbc.OraclePreparedStatement .................................................................. 4-22
Interface oracle.jdbc.OracleCallableStatement .................................................................... 4-22
Interface oracle.jdbc.OracleResultSet .................................................................................... 4-23
Interface oracle.jdbc.OracleResultSetMetaData................................................................... 4-23
Class oracle.jdbc.OracleTypes................................................................................................ 4-23
Method getJavaSqlConnection............................................................................................... 4-25
DML Returning ..................................................................................................................................... 4-26
Oracle-Specific APIs........................................................................................................................ 4-26
Running DML Returning Statements........................................................................................... 4-27
Example of DML Returning .......................................................................................................... 4-27
Limitations of DML Returning...................................................................................................... 4-28
Accessing PL/SQL Index-by Tables ................................................................................................... 4-28
Overview .......................................................................................................................................... 4-29
Binding IN Parameters ................................................................................................................... 4-29
Receiving OUT Parameters............................................................................................................ 4-31
Type Mappings................................................................................................................................ 4-32
v
CODE, HEIGHT, and WIDTH .................................................................................................. 5-8
CODEBASE.................................................................................................................................. 5-9
ARCHIVE..................................................................................................................................... 5-9
vi
Bequeath Connection and SYS Logon............................................................................................. 8-9
Properties for Oracle Performance Extensions ........................................................................... 8-10
Database URLs and Database Specifiers.......................................................................................... 8-11
10 Proxy Authentication
About Proxy Authentication ............................................................................................................... 10-1
Types of Proxy Connections ................................................................................................................ 10-2
Creating Proxy Connections................................................................................................................ 10-3
Closing a Proxy Session ....................................................................................................................... 10-4
Caching Proxy Connections ................................................................................................................ 10-5
vii
Standard getObject Method........................................................................................................... 11-6
Oracle getOracleObject Method.................................................................................................... 11-6
Summary of getObject and getOracleObject Return Types ...................................................... 11-7
Other getXXX Methods .................................................................................................................. 11-9
Return Types of getXXX Methods ......................................................................................... 11-9
Special Notes about getXXX Methods ................................................................................ 11-10
Data Types For Returned Objects from getObject and getXXX ............................................. 11-10
The setObject and setOracleObject Methods............................................................................. 11-11
Other setXXX Methods................................................................................................................. 11-11
Input Data Binding ................................................................................................................ 11-12
Method setFixedCHAR for Binding CHAR Data into WHERE Clauses....................... 11-13
Using Result Set Metadata Extensions............................................................................................ 11-14
Using SQL CALL and CALL INTO Statements ............................................................................ 11-15
viii
Understanding the ORAData Interface ..................................................................................... 13-14
Reading and Writing Data with a ORAData Implementation ............................................... 13-16
Additional Uses for ORAData..................................................................................................... 13-18
The Deprecated CustomDatum Interface.................................................................................. 13-19
Object-Type Inheritance .................................................................................................................... 13-19
Creating Subtypes ......................................................................................................................... 13-20
Implementing Customized Classes for Subtypes..................................................................... 13-20
Use of ORAData for Type Inheritance Hierarchy ............................................................. 13-21
Use of SQLData for Type Inheritance Hierarchy .............................................................. 13-23
JPublisher Utility.................................................................................................................... 13-25
Retrieving Subtype Objects.......................................................................................................... 13-26
Creating Subtype Objects............................................................................................................. 13-28
Sending Subtype Objects.............................................................................................................. 13-28
Accessing Subtype Data Fields ................................................................................................... 13-29
Inheritance Metadata Methods ................................................................................................... 13-30
Using JPublisher to Create Custom Object Classes ..................................................................... 13-30
JPublisher Functionality ............................................................................................................... 13-30
JPublisher Type Mappings .......................................................................................................... 13-31
Describing an Object Type ................................................................................................................ 13-33
Functionality for Getting Object Metadata................................................................................ 13-33
Steps for Retrieving Object Metadata......................................................................................... 13-34
ix
Retrieving and Passing an Object Reference................................................................................... 15-3
Retrieving an Object Reference from a Result Set ...................................................................... 15-3
Retrieving an Object Reference from a Callable Statement ...................................................... 15-4
Passing an Object Reference to a Prepared Statement............................................................... 15-4
Accessing and Updating Object Values Through an Object Reference ..................................... 15-5
Custom Reference Classes with JPublisher ..................................................................................... 15-5
17 Result Set
Overview of JDBC 2.0 Result Set ....................................................................................................... 17-1
Result Set Functionality and Result Set Categories Supported in JDBC 2.0........................... 17-1
Oracle JDBC Implementation Overview for Result Set Enhancements .................................. 17-3
Creating Scrollable or Updatable Result Sets ................................................................................. 17-5
Specifying Result Set Scrollability and Updatability ................................................................. 17-5
Result Set Limitations and Downgrade Rules ............................................................................ 17-6
Positioning and Processing in Scrollable Result Sets.................................................................... 17-8
Positioning in a Scrollable Result Set ........................................................................................... 17-8
Processing a Scrollable Result Set ............................................................................................... 17-10
Updating Result Sets .......................................................................................................................... 17-11
Performing a DELETE Operation in a Result Set ..................................................................... 17-11
Performing an UPDATE Operation in a Result Set ................................................................. 17-12
Performing an INSERT Operation in a Result Set.................................................................... 17-13
Avoiding Update Conflicts.......................................................................................................... 17-14
Fetch Size .............................................................................................................................................. 17-15
x
Setting the Fetch Size .................................................................................................................... 17-15
Refetching Rows.................................................................................................................................. 17-16
Seeing Database Changes Made Internally and Externally........................................................ 17-16
Seeing Internal Changes............................................................................................................... 17-17
Seeing External Changes .............................................................................................................. 17-17
Visibility versus Detection of External Changes ...................................................................... 17-18
Summary of Visibility of Internal and External Changes ....................................................... 17-18
Oracle Implementation of Scroll-Sensitive Result Sets............................................................ 17-19
18 JDBC RowSets
Overview of JDBC RowSets................................................................................................................ 18-1
RowSet Properties ........................................................................................................................... 18-2
Events and Event Listeners............................................................................................................ 18-3
Command Parameters and Command Execution...................................................................... 18-4
Traversing RowSets ........................................................................................................................ 18-4
CachedRowSet ....................................................................................................................................... 18-6
JdbcRowSet ............................................................................................................................................ 18-9
WebRowSet........................................................................................................................................... 18-10
FilteredRowSet .................................................................................................................................... 18-12
JoinRowSet ........................................................................................................................................... 18-13
19 Globalization Support
Providing Globalization Support ...................................................................................................... 19-1
NCHAR, NVARCHAR2, NCLOB and the defaultNChar Property in JDK 1.5 ......................... 19-3
New Methods for National Character Set Type Data in JDK 1.6 ................................................. 19-4
xi
21 Implicit Connection Caching
The Implicit Connection Cache .......................................................................................................... 21-2
Using the Connection Cache ............................................................................................................... 21-3
Turning Caching On ....................................................................................................................... 21-3
Opening a Connection.................................................................................................................... 21-4
Setting Connection Cache Name .................................................................................................. 21-4
Setting Connection Cache Properties ........................................................................................... 21-5
Closing a Connection...................................................................................................................... 21-5
Implicit Connection Cache Example ............................................................................................ 21-5
Connection Attributes .......................................................................................................................... 21-6
Getting Connections ....................................................................................................................... 21-7
Setting Connection Attributes ....................................................................................................... 21-7
Checking Attributes of a Returned Connection ......................................................................... 21-8
Connection Attribute Example ..................................................................................................... 21-8
Connection Cache Properties .............................................................................................................. 21-8
Limit Properties ............................................................................................................................... 21-9
TIMEOUT Properties.................................................................................................................... 21-10
Other Properties ............................................................................................................................ 21-11
Connection Property Example .................................................................................................... 21-11
Connection Cache Manager API ...................................................................................................... 21-12
Advanced Topics.................................................................................................................................. 21-13
Attribute Weights and Connection Matching........................................................................... 21-13
Connection Cache Callbacks ....................................................................................................... 21-13
Use Cases for TimeToLiveTimeout and AbandonedConnectionTimeout ........................... 21-14
23 Performance Extensions
Update Batching .................................................................................................................................... 23-1
Overview of Update Batching Models......................................................................................... 23-2
Oracle Update Batching ................................................................................................................. 23-3
Oracle Update Batching Characteristics and Limitations .................................................. 23-3
Setting the Connection Batch Value ...................................................................................... 23-4
Setting the Statement Batch Value......................................................................................... 23-4
Checking the Batch Value....................................................................................................... 23-5
Overriding the Batch Value ................................................................................................... 23-5
Committing the Changes in Oracle Batching ...................................................................... 23-6
Update Counts in Oracle Batching ........................................................................................ 23-6
Error Reporting in Oracle Update Batching......................................................................... 23-8
Standard Update Batching............................................................................................................. 23-8
Limitations in the Oracle Implementation of Standard Batching..................................... 23-8
Adding Operations to the Batch ............................................................................................ 23-9
Processing the Batch .............................................................................................................. 23-10
Committing the Changes in the Oracle Implementation of Standard Batching........... 23-10
xii
Clearing the Batch.................................................................................................................. 23-10
Update Counts in the Oracle Implementation of Standard Batching ............................ 23-11
Error Handling in the Oracle Implementation of Standard Batching............................ 23-12
Intermixing Batched Statements and Nonbatched Statements ....................................... 23-13
Premature Batch Flush ................................................................................................................. 23-14
Additional Oracle Performance Extensions ................................................................................... 23-15
Oracle Row-Prefetching Limitations .......................................................................................... 23-15
Defining Column Types ............................................................................................................... 23-16
DatabaseMetaData TABLE_REMARKS Reporting.................................................................. 23-19
xiii
27 Transparent Application Failover
Overview of Transparent Application Failover............................................................................... 27-1
Failover Type Events............................................................................................................................. 27-1
TAF Callbacks ........................................................................................................................................ 27-2
Java TAF Callback Interface ................................................................................................................ 27-2
28 Distributed Transactions
Overview of Distributed Transactions.............................................................................................. 28-1
Distributed Transaction Components and Scenarios ................................................................ 28-2
Distributed Transaction Concepts ................................................................................................ 28-2
Switching Between Global and Local Transactions ................................................................... 28-4
Oracle XA Packages ........................................................................................................................ 28-5
XA Components..................................................................................................................................... 28-5
XADatasource Interface and Oracle Implementation................................................................ 28-6
XAConnection Interface and Oracle Implementation ............................................................... 28-6
XAResource Interface and Oracle Implementation ................................................................... 28-7
OracleXAResource Method Functionality and Input Parameters ........................................... 28-8
Xid Interface and Oracle Implementation ................................................................................. 28-12
Error Handling and Optimizations.................................................................................................. 28-13
XAException Classes and Methods............................................................................................ 28-13
Mapping Between Oracle Errors and XA Errors ...................................................................... 28-14
XA Error Handling........................................................................................................................ 28-14
Oracle XA Optimizations ............................................................................................................. 28-15
Implementing a Distributed Transaction ....................................................................................... 28-15
Summary of Imports for Oracle XA ........................................................................................... 28-15
Oracle XA Code Sample............................................................................................................... 28-15
Native-XA in Oracle JDBC Drivers.................................................................................................. 28-20
OCI Native XA............................................................................................................................... 28-20
Thin Native XA.............................................................................................................................. 28-21
29 Database Management
Database Startup and Shutdown ....................................................................................................... 29-1
Database Change Notification............................................................................................................ 29-4
30 Diagnosability in JDBC
Logging.................................................................................................................................................... 30-1
Enabling and Using JDBC Logging .............................................................................................. 30-2
Configuring the CLASSPATH Environment Variable ....................................................... 30-2
Enabling Logging..................................................................................................................... 30-2
Configuring Logging ............................................................................................................... 30-3
Using Loggers........................................................................................................................... 30-5
xiv
An Example............................................................................................................................... 30-6
Performance, Scalability, and Security Issues............................................................................. 30-7
Diagnosability Management............................................................................................................... 30-8
Part IX Appendixes
A Reference Information
Valid SQL-JDBC Data Type Mappings............................................................................................... A-1
Supported SQL and PL/SQL Data Types............................................................................................ A-3
Embedded SQL92 Syntax ...................................................................................................................... A-6
Time and Date Literals ..................................................................................................................... A-7
Date Literals................................................................................................................................ A-7
Time Literals ............................................................................................................................... A-7
Timestamp Literals .................................................................................................................... A-8
Scalar Functions................................................................................................................................. A-9
LIKE Escape Characters ................................................................................................................... A-9
Outer Joins........................................................................................................................................ A-10
Function Call Syntax....................................................................................................................... A-10
SQL92 to SQL Syntax Example ..................................................................................................... A-10
Oracle JDBC Notes and Limitations.................................................................................................. A-11
CursorName..................................................................................................................................... A-11
SQL92 Outer Join Escapes.............................................................................................................. A-11
PL/SQL TABLE, BOOLEAN, and RECORD Types .................................................................. A-11
IEEE 754 Floating Point Compliance............................................................................................ A-12
Catalog Arguments to DatabaseMetaData Calls........................................................................ A-12
SQLWarning Class .......................................................................................................................... A-12
Binding Named Parameters .......................................................................................................... A-12
B Coding Tips
JDBC and Multithreading ..................................................................................................................... B-1
Performance Optimization .................................................................................................................... B-1
Disabling Auto-Commit Mode ....................................................................................................... B-1
Standard Fetch Size and Oracle Row Prefetching ........................................................................ B-2
Standard and Oracle Update Batching .......................................................................................... B-2
Statement Caching ............................................................................................................................ B-3
Mapping Between Built-in SQL and Java Types .......................................................................... B-3
Transaction Isolation Levels and Access Modes ............................................................................... B-4
xv
C JDBC Error Messages
General Structure of JDBC Error Messages ....................................................................................... C-1
General JDBC Messages ........................................................................................................................ C-1
JDBC Messages Sorted by ORA Number ...................................................................................... C-1
JDBC Messages Sorted in Alphabetic Order ................................................................................. C-5
Native XA Messages ............................................................................................................................... C-9
Native XA Messages Sorted by ORA Number ............................................................................. C-9
Native XA Messages Sorted in Alphabetic Order ........................................................................ C-9
TTC Messages ........................................................................................................................................ C-10
TTC Messages Sorted by ORA Number ...................................................................................... C-10
TTC Messages Sorted in Alphabetic Order ................................................................................. C-11
D Troubleshooting
Common Problems.................................................................................................................................. D-1
Memory Consumption for CHAR Columns Defined as OUT or IN/OUT Variables ............ D-1
Memory Leaks and Running Out of Cursors................................................................................ D-2
Boolean Parameters in PL/SQL Stored Procedures..................................................................... D-2
Opening More Than 16 OCI Connections for a Process.............................................................. D-2
Using statement.cancel ..................................................................................................................... D-3
Using JDBC with Firewalls .............................................................................................................. D-3
Basic Debugging Procedures ................................................................................................................ D-4
Oracle Net Tracing to Trap Network Events ................................................................................ D-4
Client-Side Tracing ................................................................................................................... D-4
TRACE_LEVEL_CLIENT ................................................................................................. D-4
TRACE_DIRECTORY_CLIENT ....................................................................................... D-5
TRACE_FILE_CLIENT ...................................................................................................... D-5
TRACE_UNIQUE_CLIENT ............................................................................................. D-5
Server-Side Tracing ................................................................................................................... D-6
TRACE_LEVEL_SERVER ................................................................................................. D-6
TRACE_DIRECTORY_SERVER ...................................................................................... D-6
TRACE_FILE_SERVER ...................................................................................................... D-6
Third Party Debugging Tools ......................................................................................................... D-6
Index
xvi
xvii
List of Tables
1–1 Feature Differences Between JDBC OCI and JDBC Thin Drivers....................................... 1-4
1–2 Feature List.................................................................................................................................. 1-5
2–1 Import Statements for JDBC Driver ........................................................................................ 2-8
3–1 Key Areas of JDBC 3.0 Functionality ...................................................................................... 3-2
3–2 BLOB Method Equivalents ....................................................................................................... 3-5
3–3 CLOB Method Equivalents....................................................................................................... 3-6
4–1 Oracle Data Type Classes ......................................................................................................... 4-5
4–2 Key Interfaces and Classes of the oracle.jdbc Package...................................................... 4-19
4–3 PL/SQL Types and Corresponding JDBC Types............................................................... 4-29
4–4 Arguments of the setPlsqlIndexTable Method................................................................... 4-30
4–5 Arguments of the registerIndexTableOutParameter Method .......................................... 4-31
4–6 Argument of the getPlsqlIndexTable Method .................................................................... 4-32
4–7 Argument of the getOraclePlsqlIndexTable Method ........................................................ 4-33
4–8 Arguments of the getPlsqlIndexTable Method .................................................................. 4-33
6–1 OCI Instant Client Shared Libraries ........................................................................................ 6-3
6–2 Data Shared Library for Instant Client and Instant Client Light (English) ....................... 6-9
8–1 Standard Data Source Properties............................................................................................. 8-3
8–2 Oracle Extended Data Source Properties................................................................................ 8-4
8–3 Supported Database Specifiers ............................................................................................. 8-11
9–1 Client/Server Negotiations for Encryption or Integrity ...................................................... 9-7
9–2 OCI Driver Client Parameters for Encryption and Integrity ............................................... 9-8
9–3 Thin Driver Client Parameters for Encryption and Integrity .............................................. 9-8
11–1 Default Mappings Between SQL Types and Java Types................................................... 11-2
11–2 getObject and getOracleObject Return Types..................................................................... 11-7
12–1 LONG and LONG RAW Data Conversions ....................................................................... 12-3
13–1 JPublisher SQL Type Categories, Supported Settings, and Defaults ............................ 13-33
17–1 Visibility of Internal and External Changes for Oracle JDBC......................................... 17-19
18–1 The JDBC and Cached Row Sets Compared....................................................................... 18-9
20–1 Comparing Methods Used in Statement Caching.............................................................. 20-3
20–2 Methods Used in Statement Allocation and Implicit Statement Caching ...................... 20-7
20–3 Methods Used to Retrieve Explicitly Cached Statements................................................. 20-8
23–1 Valid Column Type Specifications ..................................................................................... 23-19
26–1 onsctl Commands ................................................................................................................... 26-4
28–1 Connection Mode Transitions ............................................................................................... 28-4
28–2 Oracle-XA Error Mapping ................................................................................................... 28-14
29–1 Supported Database Startup Options .................................................................................. 29-2
29–2 Supported Database Shutdown Options............................................................................. 29-2
29–3 Database Change Notification Registration Options......................................................... 29-6
A–1 Valid SQL Data Type-Java Class Mappings ......................................................................... A-1
A–2 Support for SQL Data Types ................................................................................................... A-3
A–3 Support for ANSI-92 SQL Data Types ................................................................................... A-4
A–4 Support for SQL User-Defined Types.................................................................................... A-4
A–5 Support for PL/SQL Data Types ............................................................................................ A-5
B–1 Mapping of SQL Data Types to Java Classes that Represent SQL Data Types ............... B-3
xviii
Preface
This preface introduces you to the Oracle Database JDBC Developer's Guide and Reference
discussing the intended audience, structure, and conventions of this document. A list
of related Oracle documents is also provided.
Audience
The Oracle Database JDBC Developer's Guide and Reference is intended for developers of
Java Database Connectivity (JDBC)-based applications and applets. This book can be
read by anyone with an interest in JDBC programming, but assumes at least some
prior knowledge of the following:
■ Java
■ PL/SQL
■ Oracle databases
Documentation Accessibility
Our goal is to make Oracle products, services, and supporting documentation
accessible, with good usability, to the disabled community. To that end, our
documentation includes features that make information available to users of assistive
technology. This documentation is available in HTML format, and contains markup to
facilitate access by the disabled community. Accessibility standards will continue to
evolve over time, and Oracle is actively engaged with other market-leading
technology vendors to address technical obstacles so that our documentation can be
accessible to all of our customers. For more information, visit the Oracle Accessibility
Program Web site at
http://www.oracle.com/accessibility/
xix
TTY Access to Oracle Support Services
Oracle provides dedicated Text Telephone (TTY) access to Oracle Support Services
within the United States of America 24 hours a day, 7 days a week. For TTY support,
call 800.446.2398. Outside the United States, call +1.407.458.2479.
Related Documents
The following books are also available from the Oracle Java Platform group:
■ Oracle Database Java Developer's Guide
This book introduces the basic concepts of Java and provides general information
about server-side configuration and functionality. Information that pertains to the
Oracle Java platform as a whole, rather than to a particular product (such as JDBC)
is in this book. This book also discusses Java stored procedures, which were
formerly discussed in a standalone book.
■ Oracle Database JPublisher User's Guide
This book describes how to use the Oracle JPublisher utility to translate object
types and other user-defined types to Java classes. If you are developing JDBC
applications that use object types, VARRAY types, nested table types, or object
reference types, then JPublisher can generate custom Java classes to map to them.
The following OC4J documents, for Oracle Application Server releases, are also
available from the Oracle Java Platform group:
■ Oracle Application Server Containers for J2EE User’s Guide
This book provides some overview and general information for OC4J; primer
chapters for servlets, JSP pages, and EJBs; and general configuration and
deployment instructions.
■ Oracle Application Server Containers for J2EE Support for JavaServer Pages Developer’s
Guide
This book provides information for JSP developers who want to run their pages in
OC4J. It includes a general overview of JSP standards and programming
considerations, as well as discussion of Oracle value-added features and steps for
getting started in the OC4J environment.
■ Oracle Application Server Containers for J2EE JSP Tag Libraries and Utilities Reference
This book provides conceptual information and detailed syntax and usage
information for tag libraries, JavaBeans, and other Java utilities provided with
OC4J.
■ Oracle Application Server Containers for J2EE Servlet Developer’s Guide
This book provides information for servlet developers regarding use of servlets
and the servlet container in OC4J. It also documents relevant OC4J configuration
files.
■ Oracle Application Server Containers for J2EE Services Guide
This book provides information about basic Java services supplied with OC4J,
such as JTA, JNDI, and the Oracle Application Server Java Object Cache.
■ Oracle Application Server Containers for J2EE Enterprise JavaBeans Developer’s Guide
This book provides information about the EJB implementation and EJB container
in OC4J.
The following documents are from the Oracle Server Technologies group:
xx
■ Oracle Database Advanced Application Developer's Guide
■ Oracle Database PL/SQL Packages and Types Reference
■ Oracle Database PL/SQL Language Reference
■ Oracle Database SQL Language Reference
■ Oracle Database Net Services Administrator's Guide
■ Oracle Database Advanced Security Administrator's Guide
■ Oracle Database Reference
■ Oracle Database Error Messages
The following documents from the Oracle Application Server group may also be of
some interest:
■ Oracle Application Server 10g Administrator’s Guide
■ Oracle Fusion Middleware Administrator's Guide for Oracle HTTP Server
■ Oracle Application Server 10g Performance Guide
■ Oracle Application Server 10g Globalization Guide
■ Oracle Application Server Web Cache Administrator’s Guide
■ Oracle Application Server 10g Upgrading to 10g (9.0.4)
The following are available from the JDeveloper group:
■ Oracle JDeveloper online help
■ Oracle JDeveloper documentation on the Oracle Technology Network:
http://otn.oracle.com/products/jdev/content.html
xxi
We recommend that you request only the daily digest of the posted e-mails. To do
this add the following line to the message body as well:
set jdbc-interest digest
Conventions
This section describes the conventions used in the text and code examples of this
documentation set. The following table describes those conventions and provides
examples of their use.
xxii
What’s New
The changes in Oracle Database 11g Release 1 (11.1) can be divided into the following
categories:
■ New Features for Release 1 (11.1)
■ Desupported Features
■ Interface Changes
Oracle SecureFiles
Java/JDBC applications get richer SecureFiles LOB data manipulation API and
performance enhancements such as versioning, sliding inserts, sliding delete, fragment
move, in-place data replacement, compression, encryption, sharing, and client-side
read. This feature is covered in "Oracle SecureFiles" on page 14-19.
xxiii
Native Streams AQ Protocol
This release of Oracle JDBC drivers provides a Java interface to Oracle Streams
Advanced Queuing (AQ). This feature is covered in Chapter 25, "Oracle Advanced
Queuing".
Database Diagnosability
In this release the JDBC drivers have been enhanced by including new diagnosabilty
features and improving existing diagnosabilty features. These features enable users to
diagnose problems in the applications that use Oracle JDBC drivers and the problems
in the drivers themselves. This feature is covered in detail in Chapter 30,
"Diagnosability in JDBC".
Result Cache
This release of Oracle JDBC drivers provide support for Result Cache feature, which is
very different from traditional caching and presummarization mechanisms. For more
information refer "Result Set Caching" on page 20-9.
Desupported Features
From this release onwards, Oracle JDBC drivers will not support JDK versions earlier
than 1.5.
Interface Changes
In this release, the oracle.jdbc.OracleConnection interface has been enhanced.
For better visibility and clarity, all connection properties are defined as constants in
this interface.
xxiv
The oracle.jdbc.driver package, which was deprecated in Oracle Database
release 9.0.1, is desupported in this release. Code having references to this package
will not compile and run. You can use oracle.jdbc package instead of this package.
xxv
xxvi
Part I
Overview
The chapters in this part introduce the concept of Java Database Connectivity (JDBC)
and provide an overview of the Oracle implementation of JDBC. This part provides
basic information about installation and configuration of the Oracle client with
reference to JDBC drivers. This part also covers the basic steps in creating and running
any JDBC application.
Part I contains the following chapters:
■ Chapter 1, "Introducing JDBC"
■ Chapter 2, "Getting Started"
1
Introducing JDBC
Java Database Connectivity (JDBC) is a Java standard that provides the interface for
connecting from Java to relational databases. The JDBC standard is defined by Sun
Microsystems and implemented through the standard java.sql interfaces. This
allows individual providers to implement and extend the standard with their own
JDBC drivers. JDBC is based on the X/Open SQL Call Level Interface (CLI). JDBC 4.0
complies with the SQL 2003 standard.
This chapter provides an overview of the Oracle implementation of JDBC, covering the
following topics:
■ Overview of Oracle JDBC Drivers
■ Environments and Support
■ Feature List
Oracle Database
JDBC Server-Side
JDBC OCI Driver SOL Engine Internal Driver
Oracle Database
The JDBC Thin driver allows a direct connection to the database by providing an
implementation of SQL*Net on top of Java sockets. The driver supports the TCP/IP
protocol and requires a TNS listener on the TCP/IP sockets on the database server.
The JDBC server-side internal driver is fully consistent with the client-side drivers and
supports the same features and extensions.
Table 1–1 Feature Differences Between JDBC OCI and JDBC Thin Drivers
JDBC OCI Driver JDBC Thin Driver
OCI connection pooling Default support for Native XA
Transparent Application Failover (TAF)
OCI Client Result Cache
Note:
■ The OCI optimized fetch and client-side object cache features are
internal to the JDBC OCI driver and are not applicable to the
JDBC Thin driver.
■ Most JDBC OCI driver features are not available in the JDBC Thin
driver because they are inherited from OCI.
Feature List
Table 1–2 lists the features and the versions in which they were first supported for each
of the three Oracle JDBC drivers: server-side internal driver, JDBC OCI driver, and
JDBC Thin driver.
Note:
■ In the table, NA means that the feature is not applicable for the
corresponding Oracle JDBC driver.
■ The ConnectionCacheImpl connection cache feature is
deprecated since Oracle Database 10g and Implicit Connection
Cache replaces this.
This chapter discusses the compatibility of Oracle Java Database Connectivity (JDBC)
driver versions, database versions, and Java Development Kit (JDK) versions. It also
describes the basics of testing a client installation and configuration and running a
simple application. This chapter contains the following sections:
■ Version Compatibility for Oracle JDBC Drivers
■ Verification of a JDBC Client Installation
■ Basic Steps in JDBC
■ Sample: Connecting, Querying, and Processing the Results
■ Stored Procedure Calls in JDBC Programs
■ Processing SQL Exceptions
Backward Compatibility
The JDBC drivers are certified to work with the currently supported versions of Oracle
Database. For example, the JDBC Thin drivers in Oracle Database 11g Release 1 (11.1)
are certified to work with the 10.2.x, 10.1.x, 9.2.x, and 9.0.1.x Oracle Database releases.
However, they are not certified to work with older, unsupported database releases,
such as 8.0.x and 7.x.
Forward Compatibility
Existing and supported JDBC drivers are certified to work with Oracle Database 11g
Release 1 (11.1).
Note:
■ In Oracle Database 11g Release 1 (11.1), Oracle JDBC drivers no
longer support JDK 1.4.x or earlier versions.
■ You can find a complete, up-to-date list of supported databases
at
http://www.oracle.com/technology/tech/java/sqlj
_jdbc/htdocs/jdbc_faq.htm.
If you have installed the JDBC Oracle Call Interface (OCI) driver, then you must also
install the Oracle client software. This includes Oracle Net and the OCI libraries.
Contain the JDBC driver classes for use with JDK 1.5 and JDK 1.6
Note:
■ In Oracle Database 11g Release 1 (11.1), support for a version of
JDK earlier than version 1.5 has been removed. Also, the
ojdbc14.jar and classes12.jar files are no longer shipped.
Instead, you can use the ojdbc5.jar and ojdbc6.jar files,
which are shipped with Oracle Database 11g.
■ If you are using JSE 6 and later, then there is no need to explicitly
load the JDBC driver. This means that the Java run-time loads the
driver when needed and you need not include
Class.forName("oracle.jdbc.OracleDriver") or new
oracle.jdbc.OracleDriver() in your code. But if you are
using J2SE 5, then you need to load the JDBC driver explicitly.
■ Readme.txt
This file contains late-breaking and release-specific information about the drivers,
which may not have been included in other documentation on the product.
Check whether or not the following directories have been created and populated in the
ORACLE_HOME /jlib directory:
■ jta.jar and jndi.jar
These files contain classes for the Java Transaction API (JTA) and the Java Naming
and Directory Interface (JNDI). These are required only if you are using JTA
features for distributed transaction management or JNDI features for naming
services.
Note: These files can also be obtained from the Sun Microsystems
Web site. However, it is recommended that you use the versions
supplied by Oracle, which have been tested with the Oracle drivers.
Note: If you use the JTA features and the JNDI features, then you
must specify jta.jar and jndi.jar in your CLASSPATH
environment variable.
commands on the command line, one after the other, to see if the Java compiler and
the Java interpreter run without error. :
javac
java
Each of the preceding commands should display a list of options and parameters and
then exit. Ideally, verify that you can compile and run a simple test program, such as
jdbc/demo/samples/generic/SelectExample.
class JDBCVersion
{
public static void main (String args[]) throws SQLException
{
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:scott/tiger@host:port:service");
Connection conn = ods.getConnection();
You can also determine the version of the JDBC driver by executing the following
commands:
■ java -jar ojdbc5.jar
■ java -jar ojdbc6.jar
// You need to import the java.sql and JDBC packages to use JDBC
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;
class JdbcCheckup
{
public static void main(String args[]) throws SQLException, IOException
{
// Create a statement
Statement stmt = conn.createStatement();
while (rset.next())
System.out.println(rset.getString(1));
// close the result set, the statement and the connection
rset.close();
stmt.close();
conn.close();
System.out.println("Your JDBC installation is correct.");
}
Importing Packages
Regardless of which Oracle JDBC driver you use, include the import statements
shown in Table 2–1 at the beginning of your program.
The Oracle packages listed as optional provide access to the extended functionality
provided by Oracle JDBC drivers, but are not required for the example presented in
this section.
The following example connects user scott with password tiger to a database with
service orcl through port 1521 of the host myhost, using the JDBC Thin driver:
OracleDataSource ods = new OracleDataSource();
String url = "jdbc:oracle:thin:@//myhost:1521/orcl",
ods.setURL(url);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
If you want to connect using the Thin driver, then you must specify the port number.
For example, if you want to connect to the database on the host myhost that has a
TCP/IP listener on port 1521 and the service identifier is orcl, then provide the
following code:
String URL = "jdbc:oracle:thin:scott/tiger@//myhost:1521/orcl");
ods.setURL(URL);
Connection conn = ods.getConnection();
Note:
■ The method used to execute a Statement object depends on the
type of SQL statement being executed. If the Statement object
represents a SQL query returning a ResultSet object, the
executeQuery method should be used. If the SQL is known to
be a DDL statement or a DML statement returning an update
count, the executeUpdate method should be used. If the type of
the SQL statement is not known, the execute method should be
used.
■ In case of a standard JDBC driver, if the SQL string being executed
does not return a ResultSet object, then the executeQuery
method throws a SQLException exception. In case of an Oracle
JDBC driver, the executeQuery method does not throw a
SQLException exception even if the SQL string being executed
does not return a ResultSet object.
To continue the example, once you create the Statement object stmt, the next step is
to run a query that returns a ResultSet object with the contents of the ename
column of a table of employees named EMP:
ResultSet rset = stmt.executeQuery ("SELECT ename FROM emp");
The next() method returns false when it reaches the end of the result set. The
employee names are materialized as Java String values.
stmt.close();
When you close a Statement object that a given Connection object creates, the
connection itself remains open.
DML Operations
To perform DML (Data Manipulation Language) operations, such as INSERT or
UPDATE operations, you can create either a Statement object or a
PreparedStatement object. PreparedStatement objects enable you to run a
statement with varying sets of input parameters. The prepareStatement method of
the JDBC Connection object lets you define a statement that takes variable bind
parameters and returns a JDBC PreparedStatement object with your statement
definition.
Use the setXXX methods on the PreparedStatement object to bind data to the
prepared statement to be sent to the database.
The following example shows how to use a prepared statement to run INSERT
operations that add two rows to the EMP table.
// Prepare to insert new names in the EMP table
PreparedStatement pstmt = null;
try{
pstmt = conn.prepareStatement ("insert into EMP (EMPNO, ENAME) values (?,
?)");
finally{
if(pstmt!=null)
DDL Operations
To perform data definition language (DDL) operations, you can create either a
Statement object or a PreparedStatement object. The following example shows
how to create a table in the database using a Statement object.
//create table EMP with columns EMPNO and ENAME
String query;
Statement stmt=null;
try{
query="create table EMP " +
"(EMPNO int, " +
"ENAME varchar(50))";
stmt = conn.createStatement();
stmt.executeUpdate(query);
}
finally{
//close the Statement object
stmt.close();
}
If your code involves reexecuting a DDL operation, then, before reexecuting the
statement, you must prepare it again. The following example shows how to prepare
your DDL statements before any reexecution:
//
PreparedStatement pstmt = null;
PreparedStatement tstmt = null;
try{
pstmt = conn.prepareStatement ("insert into EMP (EMPNO, ENAME) values (?,
?)");
tstmt.close();
tstmt = conn.prepareStatement("truncate table EMP");
tstmt.executeUpdate();
}
finally{
if(pstmt!=null)
Committing Changes
By default, data manipulation language (DML) operations are committed
automatically as soon as they are run. This is known as the auto-commit mode.
However, you can disable auto-commit mode with the following method call on the
Connection object:
conn.setAutoCommit(false);
If you disable the auto-commit mode, then you must manually commit or roll back
changes with the appropriate method call on the Connection object:
conn.commit();
or:
conn.rollback();
A COMMIT or ROLLBACK operation affects all DML statements run since the last
COMMIT or ROLLBACK.
Note:
■ If the auto-commit mode is disabled and you close the
connection without explicitly committing or rolling back your
last changes, then an implicit COMMIT operation is run.
■ Any data definition language (DDL) operation always causes
an implicit COMMIT. If the auto-commit mode is disabled, then
this implicit COMMIT will commit any pending DML operations
that had not yet been explicitly committed or rolled back.
import java.sql.Statement;
import oracle.jdbc.pool.OracleDataSource;
class JdbcTest
{
public static void main (String args []) throws SQLException
{
try
{
// Query the employee names
stmt = conn.createStatement ();
rset = stmt.executeQuery ("SELECT ename FROM emp");
finally{
if(rset!=null) rset.close();
if(stmt!=null) stmt.close();
if(conn!=null) conn.close();
}
}
}
If you want to adapt the code for the OCI driver, then replace the call to the
OracleDataSource.setURL method with the following:
ods.setURL("jdbc:oracle:oci:@MyHostString");
As an example of using the Oracle syntax, here is a PL/SQL code snippet that creates a
stored function. The PL/SQL function gets a character sequence and concatenates a
suffix to it:
create or replace function foo (val1 char)
return char as
begin
return val1 || 'suffix';
end;
The function invocation in your JDBC program should look like the following:
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@<hoststring>");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
JDBC 3.0 defines only a single exception, SQLException. However, there are large
categories of errors and it is useful to distinguish them. Therefore, in JDBC 4.0, a set of
subclasses of the SQLException exception is introduced to identify the different
categories of errors. To know more about this feature, see Support for JDBC 4.0
Standard on page 3-6.
Basic exception handling can include retrieving the error message, retrieving the error
code, retrieving the SQL state, and printing the stack trace. The SQLException class
includes functionality to retrieve all of this information, when available.
See Also:
■ Appendix C, "JDBC Error Messages"
■ Oracle Database Error Messages
This would print the output, such as the following, for an error originating in the
JDBC driver:
exception: Invalid column type
To illustrate how the JDBC drivers handle errors, assume the following code uses an
incorrect column index:
// Iterate through the result and print the employee names
// of the code
try {
Assuming the column index is incorrect, running the program would produce the
following error text:
java.sql.SQLException: Invalid column index
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at oracle.jdbc.driver.OracleResultSetImpl.getDate(OracleResultSetImpl.java:1556)
at Employee.main(Employee.java:41)
This part includes chapters that discuss the different Java Database Connectivity
(JDBC) versions that Oracle Database 11g supports. It also includes chapters that cover
features specific to JDBC Thin driver, JDBC Oracle Call Interface (OCI) driver, and the
server-side internal driver.
Part II contains the following chapters:
■ Chapter 3, "JDBC Standards Support"
■ Chapter 4, "Oracle Extensions"
■ Chapter 5, "Features Specific to JDBC Thin"
■ Chapter 6, "Features Specific to JDBC OCI Driver"
■ Chapter 7, "Server-Side Internal Driver"
3
JDBC Standards Support
The Oracle Java Database Connectivity (JDBC) drivers support different versions of
the JDBC standard features. In Oracle Database 11g Release 1 (11.1), Oracle JDBC
drivers have been enhanced to provide support for the JDBC 4.0 standards. These
features are provided through the oracle.jdbc and oracle.sql packages. These
packages support Java Development Kit (JDK) releases 1.5 and 1.6. This chapter
discusses the JDBC standards support in Oracle JDBC drivers. It contains the following
sections:
■ Support for JDBC 2.0 Standard
■ Support for JDBC 3.0 Standard
■ Support for JDBC 4.0 Standard
Note: Versions of JDK earlier than 1.5 are no longer supported. The
package oracle.jdbc2 has been removed.
See Also:
■ "Update Batching" on page 23-1
■ "Fetch Size" on page 17-15
The following JDBC 3.0 features supported by Oracle JDBC drivers are covered in this
section:
■ Transaction Savepoints
■ Retrieval of Auto-Generated Keys
■ JDBC 3.0 LOB Interface Methods
■ Result Set Holdability
Transaction Savepoints
The JDBC 3.0 specification supports savepoints, which offer finer demarcation within
transactions. Applications can set a savepoint within a transaction and then roll back
all work done after the savepoint. Savepoints relax the atomicity property of
transactions. A transaction with a savepoint is atomic in the sense that it appears to be
a single unit outside the context of the transaction, but code operating within the
transaction can preserve partial states.
Creating a Savepoint
You create a savepoint using the Connection.setSavepoint method, which
returns a java.sql.Savepoint instance.
A savepoint is either named or unnamed. You specify the name of a savepoint by
supplying a string to the setSavepoint method. If you do not specify a name, then
the savepoint is assigned an integer ID. You retrieve a name using the
getSavepointName method. You retrieve an ID using the getSavepointId
method.
Releasing a Savepoint
You remove a savepoint using the Connection.releaseSavepoint(Savepoint
svpt) method.
Savepoint Notes
When using savepoints, you must consider the following:
■ After a savepoint has been released, attempting to reference it in a rollback
operation will cause a SQLException exception to be thrown.
■ When a transaction is committed or rolled back, all savepoints created in that
transaction are automatically released and become invalid.
■ Rolling a transaction back to a savepoint automatically releases and makes invalid
any savepoints created after the savepoint in question.
Note: The Oracle server-side internal driver does not support the
retrieval of auto-generated keys feature.
java.sql.Statement
If key columns are not explicitly indicated, then Oracle JDBC drivers cannot identify
which columns need to be retrieved. When a column name or column index array is
used, Oracle JDBC drivers can identify which columns contain auto-generated keys
that you want to retrieve. However, when the
Statement.RETURN_GENERATED_KEYS integer flag is used, Oracle JDBC drivers
cannot identify these columns. When the integer flag is used to indicate that
auto-generated keys are to be returned, the ROWID pseudo column is returned as key.
The ROWID can be then fetched from the ResultSet object and can be used to retrieve
other columns.
Sample Code
The following code illustrates retrieval of auto-generated keys:
/** SQL statements for creating an ORDERS table and a sequence for generating the
* ORDER_ID.
*
* CREATE TABLE ORDERS (ORDER_ID NUMBER, CUSTOMER_ID NUMBER, ISBN NUMBER,
* DESCRIPTION NCHAR(5))
*
* CREATE SEQUENCE SEQ01 INCREMENT BY 1 START WITH 1000
*/
...
String cols[] = {"ORDER_ID", "DESCRIPTION"};
In the preceding example, a sequence, SEQ01, is created to generate values for the
ORDER_ID column starting from 1000 and incrementing by 1 each time the sequence
is processed to generate the next value. An OraclePreparedStatement object is
created to insert a row in to the ORDERS table.
Limitations
Auto-generated keys are implemented using the DML returning clause. So, they are
subjected to the following limitations:
■ You cannot combine auto-generated keys with batch update.
■ You need to access the ResultSet object returned from getGeneratedKeys
method by position only and no bind variable names should be used as columns
in the ResultSet object.
Some of the new features available in Oracle Database 11g Release 1 (11.1) JDBC
drivers are the following:
■ Wrapper Pattern Support
■ Enhanced Exception Hierarchy and SQLException
■ The RowId Data Type
■ LOB Creation
■ National Language Character Set Support
This document provides only an overview of these new features. For detailed
information about these features, see "Java 2 Platform, Standard Edition (JSE) 6.0
specification" at
http://java.sun.com/javase/6/docs/
See Also:
http://java.sun.com/javase/6/docs/api/java/sql/Wrapp
er.html
LOB Creation
In JDBC 4.0, the Connection interface has been enhanced to provide support for the
creation of BLOB, CLOB, and NCLOB objects. The interface provides the createBlob,
createClob, and createNClob methods that enable you to create Blob, Clob, and
NClob objects.
The created large objects (LOBs) do not contain any data. You can add data in these
objects by calling the appropriate setXXX methods. To retrieve the data from these
objects, you can call the getBlob, getClob, and getNClob methods defined in the
ResultSet and CallableStatement interfaces. You can either retrieve the entire
content or a part of the content from these objects. The following code snippet
illustrates how to retrieve 100 bytes of data from a BLOB object starting at offset 200:
...
Connection con = DriverManager.getConnection(url, props);
Blob aBlob = con.createBlob();
// Add data to the BLOB object.
...
// Retrieve part of the data from the BLOB object.
InputStream is = aBlob.getBinaryStream(200, 100);
...
You can also pass LOBs as input parameters to a PreparedStatement object using
the setBlob, setClob, and setNClob methods. You can use the updateBlob,
updateClob, and updateNClob methods to update a column value in an updatable
result set.
LOBs remain valid for at least the duration of the transaction in which they are
created. This may result in unwarranted use of memory during a long running
transaction. You can release LOBs by calling their free method, as follows:
...
Clob aClob = con.createClob();
int numWritten = aClob.setString(1, val);
aClob.free();
...
Oracle provides Java classes and interfaces that extend the Java Database Connectivity
(JDBC) standard implementation, enabling you to access and manipulate Oracle data
types and use Oracle performance extensions. Compared to standard JDBC, the Oracle
extensions offer greater flexibility in manipulating the data. This chapter provides an
overview of the classes and interfaces provided by Oracle that extend the JDBC
standard implementation. It also describes some of the key support features of the
extensions.
This chapter contains the following sections:
■ Overview of Oracle Extensions
■ Features of the Oracle Extensions
■ Oracle JDBC Packages
■ Oracle Character Data Types Support
■ Additional Oracle Type Extensions
■ DML Returning
■ Accessing PL/SQL Index-by Tables
See Also:
■ Package oracle.sql on page 4-5
■ "Oracle Character Data Types Support" on page 4-10
■ "Additional Oracle Type Extensions" on page 4-13
Oracle recommends the use of the Oracle JPublisher utility to create custom Java
classes to correspond to your Oracle objects. Oracle JPublisher performs this task
seamlessly with command-line options and can generate either SQLData or ORAData
interface implementations.
For SQLData interface implementations, a type map defines the correspondence
between Oracle object data types and Java classes. Type maps are objects that specify
which Java class corresponds to each Oracle object data type. Oracle JDBC uses these
type maps to determine which Java class to instantiate and populate when it retrieves
Oracle object data from a result set.
JPublisher automatically defines getXXX methods of the custom Java classes, which
retrieve data into your Java application.
See Also:
■ Chapter 13, "Working with Oracle Object Types"
■ Oracle Database JPublisher User's Guide.
Where, schema_name is the name of the schema and sql_type_name is the SQL
type name of the object. schema_name and sql_type_name are separated by a
period (.).
To specify an object type in JDBC, use its fully qualified name. It is not necessary to
enter a schema name if the type name is in the current naming space, that is, the
current schema. Schema naming follows these rules:
■ Both the schema name and the type name may or may not be within quotation
marks. However, if the SQL type name has a period in it, such as
CORPORATE.EMPLOYEE, the type name must be quoted.
■ The JDBC driver looks for the first period in the object name that is not within
quotation marks and uses the string before the period as the schema name and the
string following the period as the type name. If no period is found, then the JDBC
driver takes the current schema as default. That is, you can specify only the type
name, without indicating a schema, instead of specifying the fully qualified name
if the object type name belongs to the current schema. This also explains why you
must put the type name within quotation marks if the type name has a dot in it.
For example, assume that user Scott creates a type called person.address and
then wants to use it in his session. Scott may want to skip the schema name and
pass in person.address to the JDBC driver. In this case, if person.address is
not within quotation marks, then the period will be detected and the JDBC driver
will mistakenly interpret person as the schema name and address as the type
name.
■ JDBC passes the object type name string to the database unchanged. That is, the
JDBC driver will not change the character case even if the object type name is
within quotation marks.
For example, if Scott.PersonType is passed to the JDBC driver as an object
type name, then the JDBC driver will pass the string to the database unchanged.
As another example, if there is white space between characters in the type name
string, then the JDBC driver will not remove the white space.
DML Returning
Oracle Database supports the use of the RETURNING clause with data manipulation
language (DML) statements. This enables you to combine two SQL statements into
one. Both the Oracle JDBC Oracle Call Interface (OCI) driver and the Oracle JDBC Thin
driver support DML returning.
Package oracle.sql
The oracle.sql package supports direct access to data in SQL format. This package
consists primarily of classes that provide Java mappings to SQL data types and their
support classes. Essentially, the classes act as Java containers for SQL data.
Each of the oracle.sql.* data type classes extends oracle.sql.Datum, a
superclass that encapsulates functionality common to all the data types. Some of the
classes are for JDBC 2.0-compliant data types. These classes, as Table 4–1 indicates,
implement standard JDBC 2.0 interfaces in the java.sql package, as well as
extending the oracle.sql.Datum class.
Note: The LONG and LONG RAW SQL types and REF CURSOR type
category have no oracle.sql.* classes. Use standard JDBC
functionality for these types. For example, retrieve LONG or LONG RAW
data as input streams using the standard JDBC result set and callable
statement methods getBinaryStream and getCharacterStream.
Use the getCursor method for REF CURSOR types.
In addition to the data type classes, the oracle.sql package includes the following
support classes and interfaces, primarily for use with objects and collections:
■ oracle.sql.ArrayDescriptor
This class is used in constructing oracle.sql.ARRAY objects. It describes the
SQL type of the array.
■ oracle.sql.StructDescriptor
This class is used in constructing oracle.sql.STRUCT objects, which you can
use as a default mapping to Oracle objects in the database.
■ oracle.sql.ORAData and oracle.sql.ORADataFactory
These interfaces are used in Java classes implementing the Oracle ORAData
scenario of Oracle object support.
■ oracle.sql.OpaqueDescriptor
This class is used to obtain the metadata for an instance of the
oracle.sql.OPAQUE class.
■ oracle.sql.TypeDescriptor
This class is used to represent transient and persistent SQL types in Java.
Note:
■ Elements of the array, although of the generic Datum type,
actually contain data associated with the relevant
oracle.sql.* type appropriate for the given attribute. You
can cast the element to the appropriate oracle.sql.* type as
desired. For example, a CHAR data attribute within the STRUCT
is materialized as oracle.sql.Datum. To use it as CHAR data,
you must cast it to oracle.sql.CHAR.
■ Nested objects in the values array of a STRUCT object are
materialized by the JDBC driver as instances of STRUCT.
■ BFILEs point to the content of external files (operating system files) and are
supported by the oracle.sql.BFILE class. BFiles are read-only.
You can select a BLOB, CLOB, or BFILE locator from the database using a standard
SELECT statement. However, you receive only the locator, and not the data.
Additional steps are necessary to retrieve the data.
The following code shows how the TimeZone and Calendar objects are created for
US_PACIFIC, which is a time zone name not defined in the JDK:
TimeZone tz = TimeZone.getDefault();
tz.setID("US_PACIFIC");
GregorianCalendar gcal = new GregorianCalendar(tz);
set the session time zone. When this method is called, the JDBC driver sets the session
time zone of the connection and saves the session time zone so that any TIMESTAMP
WITH LOCAL TIME ZONE data accessed through JDBC can be adjusted using the
session time zone.
Class oracle.sql.OPAQUE
The oracle.sql.OPAQUE class gives you the name and characteristics of the OPAQUE
type and any attributes. The OPAQUE type provides access only to the uninterrupted
bytes of the instance.
Package oracle.jdbc
The interfaces of the oracle.jdbc package define the Oracle extensions to the
interfaces in java.sql. These extensions provide access to Oracle SQL-format data
and other Oracle-specific functionality, including Oracle performance enhancements.
The usage of SQL NCHAR data types is similar to that of the SQL CHAR data types.
JDBC uses the same classes and methods to access SQL NCHAR data types that are used
for the corresponding SQL CHAR data types. Therefore, there are no separate,
corresponding classes defined in the oracle.sql package for SQL NCHAR data types.
Similarly, there is no separate, corresponding constant defined in the
oracle.jdbc.OracleTypes class for SQL NCHAR data types.
The following code shows how to access SQL NCHAR data:
//
// Table TEST has the following columns:
// - NUMBER
// - NVARCHAR2
// - NCHAR
//
oracle.jdbc.OraclePreparedStatement pstmt =
(oracle.jdbc.OraclePreparedStatement)
conn.prepareStatement("insert into TEST values(?, ?, ?)");
//
// oracle.jdbc.OraclePreparedStatement.FORM_NCHAR should be used for all NCHAR,
// NVARCHAR2 and NCLOB data types.
//
Class oracle.sql.CHAR
The oracle.sql.CHAR class is used by Oracle JDBC in handling and converting
character data. This class provides the Globalization Support functionality to convert
character data. This class has two key attributes: Globalization Support character set
and the character data. The Globalization Support character set defines the encoding
of the character data. It is a parameter that is always passed when a CHAR object is
constructed. Without the Globalization Support character set information, the data
bytes in the CHAR object are meaningless. The oracle.sql.CHAR class is used for
both SQL CHAR and SQL NCHAR data types.
The only remaining use of the oracle.sql.CHAR class is to handle character data in
the form of raw bytes encoded in an Oracle Globalization Support character set. All
character data retrieved from Oracle Database should be accessed using the
java.lang.String class. When processing byte data from another source, you can
use an oracle.sql.CHAR to convert the bytes to java.lang.String.
To convert an oracle.sql.CHAR, you must provide the data bytes and an
oracle.sql.CharacterSet instance that represents the Globalization Support
character set used to encode the data bytes.
The CHAR objects that are Oracle object attributes are returned in the database
character set.
JDBC application code rarely needs to construct CHAR objects directly, because the
JDBC driver automatically creates CHAR objects as needed.
To construct a CHAR object, you must provide character set information to the CHAR
object by way of an instance of the CharacterSet class. Each instance of this class
represents one of the Globalization Support character sets that Oracle supports. A
CharacterSet instance encapsulates methods and attributes of the character set,
mainly involving functionality to convert to or from other character sets.
Each character set that Oracle supports has a unique, predefined Oracle ID.
2. Construct a CHAR object.
Pass a string, or the bytes that represent the string, to the factory method along
with the CharacterSet object that indicates how to interpret the bytes based on
the character set. For example:
String mystring = "teststring";
...
CHAR mychar = new CHAR(teststring, mycharset);
There are multiple factory methods for CHAR, which can take a String, a byte
array, or an object as input along with the CharacterSet object. In the case of a
String, the string is converted to the character set indicated by the
CharacterSet object before being placed into the CHAR object.
Note:
■ The CharacterSet object cannot be a null value.
■ The CharacterSet class is an abstract class, therefore it has
no constructor. The only way to create instances is to use the
make method.
■ The server recognizes the special value
CharacterSet.DEFAULT_CHARSET as the database character
set. For the client, this value is not meaningful.
■ Oracle does not intend or recommend that users extend the
CharacterSet class.
If you include the ROWID pseudo-column in a query, then you can retrieve the
ROWIDs with the result set getString method. You can also bind a ROWID to a
PreparedStatement parameter with the setString method. This enables in-place
updating, as in the example that follows.
Example
The following example shows how to access and manipulate ROWID data:
Statement stmt = conn.createStatement();
// Query the employee names with "FOR UPDATE" to lock the rows.
// Select the ROWID to identify the rows to be updated.
ResultSet rset =
stmt.executeQuery ("SELECT ename, rowid FROM emp FOR UPDATE");
PreparedStatement pstmt =
conn.prepareStatement ("UPDATE emp SET ename = ? WHERE rowid = ?");
To create a cursor variable, begin by identifying a type that belongs to the REF CURSOR
category. For example:
DECLARE TYPE DeptCursorTyp IS REF CURSOR
REF CURSOR, then, is a category of data types, rather than a particular data type.
Stored procedures can return cursor variables of the REF CURSOR category. This
output is equivalent to a database cursor or a JDBC result set. A REF CURSOR
essentially encapsulates the results of a query.
In JDBC, a REF CURSOR is materialized as a ResultSet object and can be accessed as
follows:
1. Use a JDBC callable statement to call a stored procedure. It must be a callable
statement, as opposed to a prepared statement, because there is an output
parameter.
2. The stored procedure returns a REF CURSOR.
3. The Java application casts the callable statement to an Oracle callable statement
and uses the getCursor method of the OracleCallableStatement class to
materialize the REF CURSOR as a JDBC ResultSet object.
4. The result set is processed as requested.
Example
This example shows how to access REF CURSOR data.
import oracle.jdbc.*;
...
CallableStatement cstmt;
ResultSet cursor;
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
cursor = ((OracleCallableStatement)cstmt).getCursor(1);
If you include a BINARY_DOUBLE column in a query, then the data is retrieved from
the database in the binary format. Also, the getDouble method will return the data in
the binary format. In contrast, for a NUMBER data type column, the number bits are
returned and converted to the Java double data type.
See Also: For information about these Oracle types, refer Oracle
Database PL/SQL Packages and Types Reference
An instance of the SYS.ANYTYPE type contains a type description of any SQL type,
persistent or transient, named or unnamed, including object types and collection
types. You can use the oracle.sql.TypeDescriptor class to access the
SYS.ANYTYPE type. An ANYTYPE instance can be retrieved from a PL/SQL procedure
or a SQL SELECT statement where SYS.ANYTYPE is used as a column type. To
retrieve an ANYTYPE instance from the database, use the getObject method. This
method returns an instance of the TypeDescriptor.
The retrieved ANYTYPE instance could be any of the following:
■ Transient object type
■ Transient predefined type
■ Persistent object type
■ Persistent predefined type
Example 4–2 Creating a Transient Object Type Through PL/SQL and Retrieving Through
JDBC
This example provides a code snippet illustrating how to retrieve a transient object
type through JDBC.
...
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall
("BEGIN ? := transient_obj_type (); END;");
cstmt.registerOutParameter(1,OracleTypes.OPAQUE,"SYS.ANYTYPE");
cstmt.execute();
TypeDescriptor obj = (TypeDescriptor)cstmt.getObject(1);
if(!obj.isTransient())
System.out.println("This must be a JDBC bug");
cstmt.close();
return obj;
...
To create an instance of the EMPLOYEE SQL object type and to insert it into
anydata_tab:
...
PreparedStatement pstmt = conn.prepareStatement("insert into anydata_table values
(?,?)");
StructDescriptor sd =
StructDescriptor.createDescriptor("EMPLOYEE",(OracleConnection)conn);
Object[] objattr = new Object[2];
objattr[0] = new BigDecimal(1120);
objattr[1] = new String("Papageno");
STRUCT myEmployeeStr = new STRUCT(sd,conn,objattr);
ANYDATA anyda = ANYDATA.convertDatum(myEmployeeStr);
pstmt.setInt(1,123);
pstmt.setObject(2,anyda);
pstmt.executeUpdate();
...
Table 4–2 (Cont.) Key Interfaces and Classes of the oracle.jdbc Package
Interface
Name or Class Key Functionality
OracleStatement Interface Provides methods to set Oracle
performance extensions for individual
statement.
Is a supertype of
OraclePreparedStatement and
OracleCallableStatement.
Implements java.sql.Statement.
OraclePreparedStatement Interface Provides setXXX methods to bind
oracle.sql.* types into a prepared
statement.
Implements
java.sql.PreparedStatement.
Extends OracleStatement.
Is a supertype of
OracleCallableStatement.
OracleCallableStatement Interface Provides getXXX methods to retrieve
data in oracle.sql format and setXXX
methods to bind oracle.sql.* types
into a callable statement.
Implements
java.sql.CallableStatement.
Extends OraclePreparedStatement.
OracleResultSet Interface Provides getXXX methods to retrieve
data in oracle.sql format.
Implements java.sql.ResultSet.
OracleResultSetMetaData Interface Provides methods to get metadata
information about Oracle result sets, such
as column names and data types.
Implements
java.sql.ResultSetMetaData.
OracleDatabaseMetaData Class Provides methods to get metadata
information about the database, such as
database product name and version, table
information, and default transaction
isolation level.
Implements
java.sql.DatabaseMetaData).
OracleTypes Class Defines integer constants used to identify
SQL types.
For standard types, it uses the same
values as the standard java.sql.Types
class. In addition, it adds constants for
Oracle extended types.
■ Interface oracle.jdbc.OracleCallableStatement
■ Interface oracle.jdbc.OracleResultSet
■ Interface oracle.jdbc.OracleResultSetMetaData
■ Class oracle.jdbc.OracleTypes
■ Method getJavaSqlConnection
Interface oracle.jdbc.OracleConnection
This interface extends standard JDBC connection functionality to create and return
Oracle statement objects, set flags and options for Oracle performance extensions,
support type maps for Oracle objects, and support client identifiers.
In Oracle Database 11g Release 1 (11.1), new methods have been added to this interface
that enable the starting up and shutting down of an Oracle Database instance. Also, for
better visibility and clarity, all connection properties are defined as constants in the
OracleConnection interface.
This interface also defines factory methods for constructing oracle.sql data values
like DATE and NUMBER. Remember the following points while using factory methods:
■ All code that constructs instances of the oracle.sql types should use the Oracle
extension factory methods. For example, ARRAY, BFILE, DATE, INTERVALDS,
NUMBER, STRUCT, TIME, TIMESTAMP, and so on.
■ All code that constructs instances of the standard types should use the JDBC 4.0
standard factory methods. For example, CLOB, BLOB, NCLOB, and so on.
■ There are no factory methods for CHAR, JAVA_STRUCT, ArrayDescriptor, and
StructDescriptor. These types are for internal driver use only.
Client Identifiers
In a connection pooling environment, the client identifier can be used to identify the
lightweight user using the database session currently. A client identifier can also be
used to share the Globally Accessed Application Context between different database
sessions. The client identifier set in a database session is audited when database
auditing is turned on.
Interface oracle.jdbc.OracleStatement
This interface extends standard JDBC statement functionality and is the superinterface
of the OraclePreparedStatement and OracleCallableStatement classes.
Extended functionality includes support for setting flags and options for Oracle
performance extensions on a statement-by-statement basis, as opposed to the
OracleConnection interface that sets these on a connectionwide basis.
The following oracle.jdbc.OracleStatement methods are Oracle-defined
extensions:
■ defineColumnType
Defines the type you will use to retrieve data from a particular database table
column
■ getRowPrefetch
Retrieves the row-prefetch value for this statement
■ setRowPrefetch
Sets the row-prefetch value for this statement
Interface oracle.jdbc.OraclePreparedStatement
This interface extends the OracleStatement interface and extends standard JDBC
prepared statement functionality. Also, the
oracle.jdbc.OraclePreparedStatement interface is extended by the
OracleCallableStatement interface. Extended functionality consists of setXXX
methods for binding oracle.sql.* types and objects to prepared statements, and
methods to support Oracle performance extensions on a statement-by-statement basis.
Interface oracle.jdbc.OracleCallableStatement
This interface extends the OraclePreparedStatement interface, which extends the
OracleStatement interface and incorporates standard JDBC callable statement
functionality.
Note:
■ The setXXX(String,...) and
registerOutParameter(String,...) methods can be used
only if all binds are procedure or function parameters only. The
statement can contain no other binds and the parameter binds
must be indicated with a question mark (?) and not :XX.
■ If you are using setXXX(int,...),
setXXXAtName(String,...) or a combination of both, then
any output parameter is bound with
registerOutParameter(int,...) and not
registerOutParameter(String,...), which is for named
parameter notation.
Interface oracle.jdbc.OracleResultSet
This interface extends standard JDBC result set functionality, implementing getXXX
methods for retrieving data into oracle.sql.* objects.
Interface oracle.jdbc.OracleResultSetMetaData
This interface extends standard JDBC result set metadata functionality to retrieve
information about Oracle result set objects.
Class oracle.jdbc.OracleTypes
The OracleTypes class defines constants that JDBC uses to identify SQL types. Each
variable in this class has a constant integer value. The oracle.jdbc.OracleTypes
class duplicates the type code definitions of the standard Java java.sql.Types class
and contains these additional type codes for Oracle extensions:
■ OracleTypes.BFILE
■ OracleTypes.ROWID
■ OracleTypes.CURSOR (for REF CURSOR types)
As in java.sql.Types, all the variable names are in uppercase text.
JDBC uses the SQL types identified by the elements of the OracleTypes class in two
main areas: registering output parameters and in the setNull method of the
PreparedStatement class.
java.sql.CallableStatement and
oracle.jdbc.OracleCallableStatement interfaces.
These are the forms that the registerOutputParameter method can take for the
CallableStatement and OracleCallableStatement interfaces
cs.registerOutParameter(int index, int sqlType);
In these signatures, index represents the parameter index, sqlType is the type code
for the SQL data type, sql_name is the name given to the data type, for user-defined
types, when sqlType is a STRUCT, REF, or ARRAY type code, and scale represents
the number of digits to the right of the decimal point, when sqlType is a NUMERIC or
DECIMAL type code.
The following example uses a CallableStatement interface to call a procedure
named charout, which returns a CHAR data type. Note the use of the
OracleTypes.CHAR type code in the registerOutParameter method.
CallableStatement cs = conn.prepareCall ("BEGIN charout (?); END;");
cs.registerOutParameter (1, OracleTypes.CHAR);
cs.execute ();
System.out.println ("Out argument is: " + cs.getString (1));
In these signatures, index represents the parameter index, sqlType is the type code
for the SQL data type, and sql_name is the name given to the data type, for
user-defined types, when sqlType is a STRUCT, REF, or ARRAY type code. If you enter
an invalid sqlType, a ParameterTypeConflict exception is thrown.
The following example uses a prepared statement to insert a null value into the
database. Note the use of OracleTypes.NUMERIC to identify the numeric object set
to NULL. Alternatively, Types.NUMERIC can be used.
PreparedStatement pstmt =
conn.prepareStatement ("INSERT INTO num_table VALUES (?)");
In this example, the prepared statement inserts a NULL STRUCT object of type
EMPLOYEE into the database.
PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO employee_table VALUES (?)");
Method getJavaSqlConnection
The getJavaSqlConnection method of the oracle.sql.* classes returns
java.sql.Connection. This method is available for the following Oracle data type
classes:
■ oracle.sql.ARRAY
■ oracle.sql.BFILE
■ oracle.sql.BLOB
■ oracle.sql.CLOB
■ oracle.sql.OPAQUE
■ oracle.sql.REF
■ oracle.sql.STRUCT
The following code snippet shows the getJavaSqlConnection method in the
Array class:
public class ARRAY
{
java.sql.Connection getJavaSqlConnection()
throws SQLException;
...
}
DML Returning
The DML returning feature provides more functionality compared to retrieval of
auto-generated keys. It can be used to retrieve not only auto-generated keys, but also
other columns or values that the application may use.
Note:
■ The server-side internal driver does not support DML returning
and retrieval of auto-generated keys.
■ You cannot use both DML returning and retrieval of
auto-generated keys in the same statement.
Oracle-Specific APIs
The OraclePreparedStatement interface is enhanced with Oracle-specific
application programming interfaces (APIs) to support DML returning. The
registerReturnParameter and getReturnResultSet methods have been
added to the oracle.jdbc.OraclePreparedStatement interface, to register
parameters that are returned and data retrieved by DML returning.
The registerReturnParameter method is used to register the return parameter
for DML returning. The method throws a SQLException instance if an error occurs.
You must pass a positive integer specifying the index of the return parameter. You
also must specify the type of the return parameter. You can also specify the maximum
bytes or characters of the return parameter. This method can be used only with char
or RAW types. You can also specify the fully qualified name of a SQL structure type.
The getReturnResultSet method fetches the data returned from DML returning
and returns it as a ResultSet object. The method throws a SQLException exception
if an error occurs.
Note: The Oracle-specific APIs for the DML returning feature are in
ojdbc5.jar for Java Development Kit (JDK) 1.5 and in ojdbc6.jar
for JDK 1.6.
The following code example also illustrates the use of DML returning. However, in
this case, the maximum size of the return parameters is not known. Therefore, the
registerReturnParameter(int paramIndex, int externalType) method
is used.
...
OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
"insert into lobtab values (100, empty_clob()) returning col1, col2 into ?, ?");
■ Type Mappings
Overview
Oracle JDBC drivers support PL/SQL index-by tables of scalar data types. Table 4–3
displays the supported scalar types and the corresponding JDBC type codes.
Note: Oracle JDBC does not support RAW, DATE, and PL/SQL
RECORD as element types.
Typical Oracle JDBC input binding, output registration, and data access methods do
not support PL/SQL index-by tables. This chapter introduces additional methods to
support these types.
The OraclePreparedStatement and OracleCallableStatement classes define
the additional methods. These methods include the following:
■ setPlsqlIndexTable
■ registerIndexTableOutParameter
■ getOraclePlsqlIndexTable
■ getPlsqlIndexTable
These methods handle PL/SQL index-by tables as IN, OUT, or IN OUT parameters,
including function return values.
Binding IN Parameters
To bind a PL/SQL index-by table parameter in the IN parameter mode, use the
setPlsqlIndexTable method defined in the OraclePreparedStatement and
OracleCallableStatement classes.
synchronized public void setPlsqlIndexTable
(int paramIndex, Object arrayData, int maxLen, int curLen, int elemSqlType,
int maxLen Specifies the maximum table length of the index-by table bind
value to be returned.
int elemSqlType Specifies the index-by table element type based on the values
defined in the OracleTypes class.
int elemMaxLen Specifies the index-by table element maximum length in case the
element type is CHAR, VARCHAR, or FIXED_CHAR. This value is
ignored for other types.
Type Mappings
This section covers the following topics:
■ JDBC Default Mappings
■ Oracle Mappings
■ Java Primitive Type Mappings
The return value is a Java array. The elements of this array are of the default Java type
corresponding to the SQL type of the elements. For example, for an index-by table
with elements of NUMERIC type code, the element values are mapped to BigDecimal
by Oracle JDBC driver, and the getPlsqlIndexTable method returns a
BigDecimal[] array. For a JDBC application, you must cast the return value to
BigDecimal[] to access the table element values.
The following code example uses the getPlsqlIndexTable method to return
index-by table elements with JDBC default mapping:
// access the value using JDBC default mapping
BigDecimal[] values =
(BigDecimal[]) procout.getPlsqlIndexTable (1);
Oracle Mappings
The getOraclePlsqlIndexTable method returns index-by table elements using
Oracle mapping.
The return value is an oracle.sql.Datum array, and the elements in the array are of
the default Datum type corresponding to the SQL type of the element. For example,
the element values of an index-by table of numeric elements are mapped to the
oracle.sql.NUMBER type in Oracle mapping, and the
getOraclePlsqlIndexTable method returns an oracle.sql.Datum array that
contains oracle.sql.NUMBER elements.
The following code example uses the getOraclePlsqlIndexTable method to
access the elements of a PL/SQL index-by table OUT parameter, using Oracle
mapping:
// Prepare the statement
OracleCallableStatement procout = (OracleCallableStatement)
conn.prepareCall ("begin procout (?); end;");
...
The following code example uses the getPlsqlIndexTable method to access the
elements of a PL/SQL index-by table of numbers. In the example, the second
parameter specifies java.lang.Integer.TYPE and the return value of the
getPlsqlIndexTable method is an int array.
OracleCallableStatement funcnone = (OracleCallableStatement)
conn.prepareCall ("begin ? := funcnone; end;");
This chapter introduces the Java Database Connectivity (JDBC) Thin client and covers
the features supported only by the JDBC Thin driver. It also provides basic
information about working with Oracle JDBC applets. This following topics are
covered in this chapter:
■ Overview of JDBC Thin Client
■ Additional Features Supported
■ JDBC in Applets
Note: When the JDBC Thin driver is used with an applet, the
browser used on the client-side must have the capability to support
Java sockets.
The HTTP protocol, which is usually used for communication over a network, is
stateless. However, the JDBC Thin driver is not stateless. Therefore, the initial HTTP
request to download the applet and the JDBC Thin driver is stateless. After the JDBC
Thin driver establishes the database connection, the communication between the
browser and the database is stateful and in a two-tier configuration.
JDBC in Applets
You can use only the Oracle JDBC Thin driver for an applet. This section describes
what you must do to connect an applet to a database. This description includes how
to use the Connection Manager feature of Oracle Database, or signed applets if you are
connecting to a database that is running on a different host from the Web server. It also
describes how your applet can connect to a database through a firewall. The section
concludes with how to package and deploy the applet.
The following topics are covered:
■ Connecting to the Database Through the Applet
■ Connecting to a Database on a Different Host Than the Web Server
■ Using Applets with Firewalls
■ Packaging Applets
■ Specifying an Applet in an HTML Page
If your database and Web server are running on the same host, then there is no issue
and no special steps are required. You can connect to the database as you would from
an application.
As with connecting from an application, there are two ways in which you can specify
the connection information to the driver. You can provide it in the form of
host:port:sid or in the form of TNS keyword-value syntax.
For example, if the database to which you want to connect resides on host prodHost,
at port 1521, and system identifier (SID) ORCL, and you want to connect with user
name scott and password tiger, then use either of the two following connection
strings:
■ Using host:port:sid syntax:
String connString="jdbc:oracle:thin:@prodHost:1521:ORCL";
ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
If you use the TNS keyword-value pair to specify the connection information to the
JDBC Thin driver, then you must declare the protocol as TCP.
However, a Web server and database server both require many resources. You seldom
find both servers running on the same computer. Usually, your applet connects to a
database on a host other than the one on which the Web server runs. If you want your
applet to connect to a database running on a different computer, then you have the
following options:
■ Use the Oracle Connection Manager on the host computer. The applet can connect
to the Connection Manager, which connects to a database on another computer.
■ Use signed applets, which can request socket connection privileges to other
computers.
Your applet can also take advantage of the data encryption and integrity checksum
features of the Advanced Security option of Oracle Database.
Web Server
webHost oraHost
cman_profile = (parameter_list =
(MAXIMUM_RELAYS=512)
(LOG_LEVEL=1)
(TRACING=YES)
(RELAY_STATISTICS=YES)
(SHOW_TNS_INFO=YES)
(USE_ASYNC_CALL=YES)
(AUTHENTICATION_LEVEL=0)
)
After you create the file, start the Connection Manager at the operating system prompt
with the following command:
cmctl start
To use your applet, you must now write the connection string for it.
The first element in the address_list entry represents the connection to the
Connection Manager. The second element represents the database to which you want
to connect. The order in which you list the addresses is important.
When your applet uses a URL, such as the preceding one, it will function exactly as if
it were connected directly to the database on the host oraHost.
Configuring a Firewall for Applets that use the JDBC Thin Driver
The instructions in this section assume that you are running an Oracle Net-compliant
firewall.
Java applets do not have access to the local system. Because of the security limitations,
applets cannot access the host name or environment variables on the local system. As a
result, the JDBC Thin driver cannot access the host name on which it is running. The
firewall cannot be provided with the host name. To allow requests from JDBC Thin
clients to go through the firewall, you must do the following to the list of firewall
rules:
■ Add the IP address, and not the host name, of the host on which the JDBC applet
is running.
■ Ensure that the host name, "__jdbc__", never appears in the firewall rules. This
host name has been hard-coded as a false host name inside the driver to force an
IP address lookup. If you do enter this host name in the list of rules, then every
applet using the JDBC Thin driver will be able to go through your firewall.
The first element in the address_list represents the connection to the firewall. The
second element represents the database to which you want to connect. Note that the
order in which you specify the addresses is important.
You can also write the preceding URL in the following format:
String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1600)(host=fireWallHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(INSTANCE_NAME=orcl))
(source_route=yes))";
OracleDataSource ods = new OracleDataSource();
ods.setURL(connString);
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
When your applet uses a URL similar to the preceding URL, it will act as if it were
connected to the database on host oraHost.
Packaging Applets
After you have coded your applet, you must package it and make it available to users.
To package an applet, you will need your applet class files and the JDBC driver class
files contained in the ojdbc5.jar or ojdbc6.jar files.
Follow these steps:
1. Move the JDBC driver classes file ojdbc5.jar or ojdbc6.jar to an empty
directory.
If your applet connects to a database with a non-US7ASCII and
non-WE8ISO8859P1 character set and uses Oracle object types, then also move the
orai18n.jar file to the same directory.
2. Add your applet classes files to the directory and any other files that the applet
may require.
3. Zip the applet classes and driver classes together into a single ZIP or Java Archive
(JAR) file. The single ZIP file should contain the following:
■ Class files from the ojdbc5.jar or ojdbc6.jar files and required class files
from the orai18n.jar files, if the applet requires Globalization Support
■ Your applet classes
4. Ensure that the ZIP or JAR file is not compressed.
You can now make the applet available to users. One way to do this is to add the
APPLET tag to the HTML page from which the applet will be run. For example:
<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet ARCHIVE=JdbcApplet.zip
CODEBASE=Applet_Samples
</APPLET>
If you use this form of the CODE attribute, then the classes for the applet and the JDBC
Thin driver must be in the same directory as the HTML page.
Note: Do not include the file name extension, .class, in the CODE
attribute.
CODEBASE
The CODEBASE attribute is optional. It specifies the base URL of the applet, that is, the
name of the directory that contains the code of the applet. If it is not specified, then the
URL of the document is used. This means that the classes for the applet and the JDBC
Thin driver must be in the same directory as the HTML page. For example, if the
current directory is my_Dir:
<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet CODEBASE="."
</APPLET>
The attribute, CODEBASE=".", indicates that the applet resides in the current
directory, my_Dir.
Now, consider that the value of CODEBASE is set to Applet_Samples, as follows:
<APPLET WIDTH=500 HEIGHT=200 CODE=JdbcApplet CODEBASE="Applet_Samples"
</APPLET>
ARCHIVE
The ARCHIVE attribute is optional. It specifies the name of the archive file that contains
the applet classes and resources the applet needs. Oracle recommends using an archive
file, which saves many extra round-trips to the server.
The archive file will be preloaded. If you have more than one archive file in the list,
separate them with commas. In the following example, the class files are stored in the
archive file, JdbcApplet.zip:
<APPLET CODE="JdbcApplet" ARCHIVE="JdbcApplet.zip" WIDTH=500 HEIGHT=200>
</APPLET>
This chapter introduces the features specific to the Java Database Connectivity (JDBC)
Oracle Call Interface (OCI) driver. It also describes the OCI Instant Client. This chapter
contains the following sections:
■ OCI Connection Pooling
■ Client Result Cache
■ Transparent Application Failover
■ OCI Native XA
■ OCI Instant Client
■ Instant Client Light (English)
{
pstmt = conn.prepareStatement (query);
pstmt.setInt(1,7500);
rs = pstmt.executeQuery();
while (rs.next( ) )
{ // see the values }
rs.close;
pstmt.close( ) ;
}
}
In the preceding example, the client result cache hint /*+ result_cache */ is
annotated to the actual query, that is, select * from emp where empno < : 1.
So, the first execution of the query goes to the database and the result set is cached for
the remaining nine executions of the query. This improves the performance of your
application significantly.
You must use JDBC statement caching or cache statements at the application level
when using the JDBC OCI client result cache.
See Also: "Statement and Result Set Caching" for more information
on JDBC statement caching
Timing Measurement
First, you measure the time taken to run the queries without the /*+ result_cache
*/ hints. Then add the /*+ result_cache */ hints to the query and measure the
time again. You will see the performance gain.
OCI Native XA
The JDBC OCI driver also provides a feature called Native XA.
environment variable, you can enable running the JDBC OCI application in the Instant
Client mode.
Note:
■ To provide Native XA functionality, you must copy the JDBC XA
class library. On UNIX, this library, libheteroxa11.so, is
located in ORACLE_HOME/jdbc/lib. On Windows, this library,
heteroxa11.dll, is located in ORACLE_HOME\bin.
■ All the libraries must be copied from the same ORACLE_HOME and
must be placed in the same directory.
■ On hybrid platforms, such as Sparc64, if the JDBC OCI driver
needs to be operated in the Instant Client mode, then you must
copy the libociei.so library from the
ORACLE_HOME/instantclient32 directory. You must copy all
other Sparc64 libraries needed for the JDBC OCI Instant Client
from the ORACLE_HOME/lib32 directory.
■ Only one set of Oracle libraries should be specified in the library
path environment variable. That is, if you have multiple
directories containing Instant Client libraries, then only one such
directory should be specified in the library path environment
variable.
■ If you have an Oracle home on your computer, then you should
not have the ORACLE_HOME/lib and Instant Client directories in
the library path environment variable simultaneously, regardless
of the order in which they appear in the variable. That is, only one
of ORACLE_HOME/lib directory (for non-Instant Client
operation) or Instant Client directory (for Instant Client operation)
should be specified in the library path environment variable.
■ Oracle recommends that you download Instant Client from Oracle
Technology Network (OTN)
http://www.oracle.com/technology/tech/oci/instantclien
t/instantclient.html
After applying the patch in an ORACLE_HOME environment, copy the files listed in
Table 6–1, " OCI Instant Client Shared Libraries" to the instant client directory as
described in "JDBC OCI Instant Client Installation Process".
Instead of copying individual files, you can generate Instant Client ZIP files for OCI,
OCCI, JDBC, and SQL*Plus as described in "Regeneration of Data Shared Library and
ZIP files". Then, you can copy the ZIP files to the target computer and unzip them as
described in "JDBC OCI Instant Client Installation Process".
The opatch utility stores the patching information of the ORACLE_HOME installation
in libclnstsh.so.11.1. This information can be retrieved by the following
command:
genezi -v
Note that if the computer from where Instant Client is deployed does not have the
genezi utility, then it must be copied from the ORACLE_HOME/bin directory on the
computer that has the ORACLE_HOME installation.
A new version of the libociei.so Data Shared Library based on the current files in
the ORACLE_HOME is then placed in the
ORACLE_HOME/rdbms/install/instantclient directory.
Note that the location of the regenerated Data Shared Library, libociei.so, is
different from that of the original Data Shared Library, libociei.so, which is
located in the ORACLE_HOME/instantclient directory.
The preceding steps also generate Instant Client ZIP files for OCI, OCCI, JDBC, and
SQL*Plus.
Regeneration of data shared library and ZIP files is not available on Microsoft
Windows platforms.
For example:
url="jdbc:oracle:oci:@//example.com:5521:bjava21"
//host:[port][/service name]
For example:
url="jdbc:oracle:oci:@//example.com:5521/bjava21
See Also: Oracle Database Net Services Administrator's Guide for more
information about connection formats
If the TNS_ADMIN environment variable is not set and TNSNAMES entries, such as
inst1, are used, then the ORACLE_HOME environment variable must be set and the
configuration files are expected to be in the $ORACLE_HOME/network/admin
directory.
The empty connection string is not supported. However, an alternate way to use the
empty connection string is to set the TWO_TASK environment variable on UNIX
systems, or the LOCAL variable on Microsoft Windows, to either a tnsnames.ora
entry or an Oracle Net keyword-value pair. If TWO_TASK or LOCAL is set to a
tnsnames.ora entry, then the tnsnames.ora file must be loaded by the
TNS_ADMIN or ORACLE_HOME setting.
Example
Consider that the listener.ora file on the database server contains the following
information:
LISTENER = (ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573)))
SID_LIST_LISTENER = (SID_LIST=
(SID_DESC=(SID_NAME=rdbms3)
(GLOBAL_DBNAME=rdbms3.server6.us.alchemy.com)
(ORACLE_HOME=/home/dba/rdbms3/oracle)))
or:
url = "jdbc:oracle:oci:@//server6:1573/rdbms3.server6.us.alchemy.com"
Alternatively, you can set the TWO_TASK environment variable to any of the
connection strings and connect to the database server without specifying the
connection string along with the sqlplus command. For example, set the TWO_TASK
environment in one of the following ways:
setenv TWO_TASK "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573))
(CONNECT_DATA=(SERVICE_NAME=rdbms3.server6.us.alchemy.com)))"
or:
setenv TWO_TASK //server6:1573/rdbms3.server6.us.alchemy.com
Now, you can connect to the database server using the following URL:
url = "jdbc:oracle:oci:@"
The connection string can also be stored in the tnsnames.ora file. For example,
consider that the tnsnames.ora file contains the following:
conn_str = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=server6)(PORT=1573))
(CONNECT_DATA=(SERVICE_NAME=rdbms3.server6.us.alchemy.com)))
Now, you can connect with either of the conn_str connection strings, as specified
previously.
If tnsnames.ora can be located by TNS_ADMIN or ORACLE_HOME, then TWO_TASK
can be set to:
setenv TWO_TASK conn_str
set, then it does not have an impact on the operation of the OCI driver. OCI will
always obtain its data from the Data Shared Library. If the Data Shared Library is not
available, only then is the ORACLE_HOME environment variable used and a full client
installation is assumed. Even though the ORACLE_HOME environment variable is not
required to be set, if it is set, then it must be set to a valid operating system path name
that identifies a directory.
Environment variables ORA_NLS10 and ORA_NLSPROFILES33 are ignored in the
Instant Client mode.
In the Instant Client mode, if the ORA_TZFILE variable is not set, then the smaller,
default, timezone.dat file from the Data Shared Library is used. If the larger
timezlrg.dat file is to be used from the Data Shared Library, then set the
ORA_TZFILE environment variable to the name of the file without any absolute or
relative path names. That is:
On UNIX systems:
setenv ORA_TZFILE timezlrg.dat
On Microsoft Windows:
set ORA_TZFILE timezlrg.dat
If the driver is not operating in the Instant Client mode, then the ORA_TZFILE
variable, if set, names a complete path name, as it does in previous Oracle Database
releases.
If TNSNAMES entries are used, then, as mentioned earlier, the TNS_ADMIN directory
must contain the TNSNAMES configuration files, and if TNS_ADMIN is not set, then the
ORACLE_HOME/network/admin directory must contain Oracle Net Services
configuration files.
Table 6–2 Data Shared Library for Instant Client and Instant Client Light (English)
Platform Instant Client Instant Client Light (English)
Sun Solaris libociei.so (67 MB) libociicus.so (4 MB)
Linux libociei.so (67 MB) libociicus.so (4 MB)
Microsoft Windows oraociei11.dll (85 MB) oraociicus11.dll (15 MB)
Globalization Settings
The NLS_LANG setting determines the language, territory, and character set as
language_territory.characterset. In Instant Client Light, language can only
be American, territory can be any that is supported, and characterset can be
any one of the following:
■ Single-byte
– US7ASCII
– WE8DEC
– WE8MSWIN1252
– WE8ISO8859P1
■ Unicode
– UTF8
– AL16UTF16
– AL32UTF8
Specifying character set or national character set other than those listed as the client or
server character set or setting the language in NLS_LANG on the client will throw one
of the following errors:
■ ORA-12734
■ ORA-12735
■ ORA-12736
■ ORA-12737
With Instant Client Light, the error messages obtained are only in English. Therefore,
the valid values for the NLS_LANG setting are of the type:
American_territory.characterset
where, territory can be any valid and supported territory and characterset can
be any one the previously listed character sets.
Instant Client Light can operate with the OCI environment handles created in the
OCI_UTF16 mode.
Operation
To operate in the Instant Client Light mode, an application must set the
LD_LIBARARY_PATH environment variable in UNIX systems or the PATH
environment variable in Microsoft Windows to a location containing the client and
data shared libraries. OCI applications by default look for the OCI Data Shared
Library, libociei.so in the LD_LIBRARY_PATH environment variable in UNIX
Installation
Instant Client Light can be installed in one of the following ways:
■ From OTN
You can download the required file from
http://www.oracle.com/technology/tech/oci/instantclient/insta
ntclient.html
For Instant Client Light, instead of downloading and expanding the Basic package,
download and unzip the Basic Light package. The instantclient_11_1
directory in which the lightweight libraries are unzipped should be empty before
unzipping the files.
■ From Client Admin Install
Instead of copying libociei.so or oraociei11.dll from the
ORACLE_HOME/instantclient directory, copy libociicus.so or
oraociic10.dll from the ORACLE_HOME/instantclient/light directory.
That is, the Instant Client directory on the LD_LIBRARY_PATH environment
variable, in UNIX systems, should contain the Instant Client Light Data Shared
Library, libociicus.so, instead of the larger OCI Instant Client Data Shared
Library, libociei.so. In Microsoft Windows, the PATH environment variable
should contain oraociicus11.dll instead of oraociei11.dll.
■ From Oracle Universal Installer
If the Instant Client option is selected from Oracle Universal Installer, then
libociei.so (or oraociei11.dll on Microsoft Windows) is installed in the
base directory of the installation which is going to be placed on the
LD_LIBRARY_PATH environment variable. This is so that Instant Client Light is
not enabled by default. The Instant Client Light Data Shared Library,
libociicus.so (or oraociicus11.dll on Microsoft Windows), is installed in
the light subdirectory of the base directory. Therefore, to operate in the Instant
Client Light mode, the OCI Data Shared Library, libociei.so (or
oraociei11.dll on Windows) must be deleted or renamed and the Instant
Client Light Data Shared Library must be copied from the light subdirectory to
the base directory of the installation.
For example, if Oracle Universal Installer has installed the Instant Client in
my_oraic_11_1 directory on the LD_LIBRARY_PATH environment variable, then
one would need to do the following to operate in the Instant Client Light mode:
cd my_oraic_11_1
rm libociei.so
mv light/libociicus.so .
Note: All the Instant Client files should always be copied or installed
in an empty directory. This is to ensure that no incompatible binaries
exist in the installation.
– jdbc:default:connection:
■ Use the Oracle-specific defaultConnection method of the OracleDriver
class.
Using defaultConnection is generally recommended.
class JDBCConnection
{
public static Connection connect() throws SQLException
{
Connection conn = null;
try {
// connect with the server-side internal driver
conn = ora.defaultConnection();
}
Note that there is no conn.close call in the example. When JDBC code is running
inside the target server, the connection is an implicit data channel, not an explicit
connection instance as from a client. It should not be closed.
If you do call the close method, then be aware of the following:
■ All connection instances obtained through the defaultConnection method,
which actually reference the same database connection, will be closed and
unavailable for further use, with state and resource cleanup as appropriate.
Running defaultConnection afterward would result in a new connection
object.
■ Even though the connection object is closed, the implicit connection to the
database will not be closed.
or:
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:default:connection");
Connection conn = ods.getConnection();
or:
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:kprb:");
Connection conn = ods.getConnection();
or:
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:default:connection:");
Connection conn = ods.getConnection();
Any user name or password you include in the URL is ignored in connecting to the
default server connection.
The OracleDataSource.getConnection method returns a new Java Connection
object every time you call it. The fact that OracleDataSource.getConnection
returns a new connection object every time you call it is significant if you are working
with object maps or type maps. A type map is associated with a specific Connection
object and with any state that is part of the object. If you want to use multiple type
maps as part of your program, then you can call getConnection to create a new
Connection object for each type map.
Exception-Handling Extensions
The server-side internal driver, in addition to having standard exception-handling
capabilities, such as getMessage(), getErrorCode(), and getSQLState(),
provides the oracle.jdbc.driver.OracleSQLException class, which is a legacy
from the earliest server-side internal driver. This class is a subclass of the standard
java.sql.SQLException class and is not available to the client-side JDBC drivers
or the server-side Thin driver.
When an error condition occurs in the server, it often results in a series of related errors
being placed in an internal error stack. The JDBC server-side internal driver retrieves
errors from the stack and places them in a chain of OracleSQLException objects.
You can use the following methods in processing these exceptions:
■ SQLException getNextException()
This method returns the next exception in the chain or a null value if there are no
further exceptions. You can start with the first exception you receive and work
through the chain. This is a standard method.
■ int getNumParameters() (Oracle extension)
Errors from the server usually include parameters, or variables, that are part of the
error message. These may indicate what type of error occurred, what kind of
operation was being attempted, or the invalid or affected values. This method
returns the number of parameters included with this error. It is an Oracle
extension.
■ Object[] getParameters() (Oracle extension)
This method returns a Java Object[] array containing the parameters included
with this error. It is an Oracle extension.
However, in 11g release 1, only a subset of the exceptions thrown by the driver are
instances of this class. In 11g release 1 (11.1), this class is deprecated and will be
removed in the next release.
or:
conn.rollback();
We can modify this code fragment for use in the server-side internal driver. In the
server-side internal driver, no user, password, or database information is necessary.
For the connection statement, you use:
ods.setUrl(
"jdbc:oracle:kprb:@");
Connection conn = ods.getConnection();
You can load the files using the JDBC Thin driver, as follows:
loadjava -thin -user scott@localhost:1521:ORCL Foo.jar
Password: password
Or, use the following command to load using the JDBC Thin driver:
loadjava -thin -user scott@localhost:1521:ORCL -resolve Foo.java
Password: password
Either of these will result in appropriate class schema objects being created in addition
to the source schema object.
This part consists of chapters that discuss the use of data sources and URLs to connect
to the database. It also includes chapters that discuss the security features supported
by the Oracle Java Database Connectivity (JDBC) Oracle Call Interface (OCI) and Thin
drivers, Secure Sockets Layer (SSL) support in JDBC Thin driver, and middle-tier
authentication through proxy connections.
Part III contains the following chapters:
■ Chapter 8, "Data Sources and URLs"
■ Chapter 9, "JDBC Client-Side Security Features"
■ Chapter 10, "Proxy Authentication"
8
Data Sources and URLs
Data Sources
Data sources are standard, general-use objects for specifying databases or other
resources to use. The JDBC 2.0 extension application programming interface (API)
introduced the concept of data sources. For convenience and portability, data sources
can be bound to Java Naming and Directory Interface (JNDI) entities, so that you can
access databases by logical names.
The data source facility provides a complete replacement for the previous JDBC
DriverManager facility. You can use both facilities in the same application, but it is
recommended that you transition your application to data sources.
This section covers the following topics:
■ Overview of Oracle Data Source Support for JNDI
■ Features and Properties of Data Sources
■ Creating a Data Source Instance and Connecting
■ Creating a Data Source Instance, Registering with JNDI, and Connecting
■ Supported Connection Properties
■ Using Roles for SYS Login
■ Configuring Database Remote Login
■ Bequeath Connection and SYS Logon
■ Properties for Oracle Performance Extensions
JNDI allows an application to use logical names in accessing these services, removing
vendor-specific syntax from application code. JNDI has the functionality to associate a
logical name with a particular source for a desired service.
All Oracle JDBC data sources are JNDI-referenceable. The developer is not required to
use this functionality, but accessing databases through JNDI logical names makes the
code more portable.
Properties of DataSource
The OracleDataSource class, as with any class that implements the DataSource
interface, provides a set of properties that can be used to specify a database to connect
to. These properties follow the JavaBeans design pattern.
Table 8–1 and Table 8–2 list OracleDataSource properties. The properties in
Table 8–1 are standard properties according to the Sun Microsystems specification. The
properties in Table 8–2 are Oracle extensions.
The OracleDataSource class implements the following setter and getter methods
for the standard properties:
■ public synchronized void setDatabaseName(String dbname)
■ public synchronized String getDatabaseName()
■ public synchronized void setDataSourceName(String dsname)
■ public synchronized String getDataSourceName()
■ public synchronized void setDescription(String desc)
■ public synchronized String getDescription()
■ public synchronized void setNetworkProtocol(String np)
■ public synchronized String getNetworkProtocol()
■ public synchronized void setPassword(String pwd)
■ public synchronized void setPortNumber(int pn)
■ public synchronized int getPortNumber()
■ public synchronized void setServerName(String sn)
■ public synchronized String getServerName()
■ public synchronized void setUser(String user)
■ public synchronized String getUser()
Note:
■ This table omits properties that supported the deprecated
connection cache based on OracleConnectionCache.
■ Because Native XA performs better than Java XA, use Native
XA whenever possible.
■ boolean getConnectionCachingEnabled()
■ void setImplicitCachingEnabled()
■ String getDriverType()
■ void setDriverType(String dt)
■ String getURL()
■ void setURL(String url)
■ String getTNSEntryName()
■ void setTNSEntryName(String tns)
■ boolean getNativeXA()
■ void setNativeXA(boolean nativeXA)
■ String getONSConfiguration()
■ void setONSConfiguration(String onsConfig)
If you are using the server-side internal driver, that is, the driverType property is set
to kprb, then any other property settings are ignored.
If you are using the JDBC Thin or OCI driver, then note the following:
■ A URL setting can include settings for user and password, as in the following
example, in which case this takes precedence over individual user and password
property settings:
jdbc:oracle:thin:scott/tiger@localhost:1521:orcl
■ Settings for user and password are required, either directly through the URL
setting or through the getConnection call. The user and password settings in
a getConnection call take precedence over any property settings.
■ If the url property is set, then any tnsEntry, driverType, portNumber,
networkProtocol, serverName, and databaseName property settings are
ignored.
■ If the tnsEntry property is set, which presumes the url property is not set, then
any databaseName, serverName, portNumber, and networkProtocol
settings are ignored.
■ If you are using an OCI driver, which presumes the driverType property is set
to oci, and the networkProtocol is set to ipc, then any other property settings
are ignored.
Also, note that getConnectionCacheName() will return the name of the cache only
if the ConnectionCacheName property of the data source is set after caching is
enabled on the data source.
Calling the JNDI InitialContext() constructor creates a Java object that references
the initial JNDI naming context. System properties, which are not shown, instruct
JNDI which service provider to use.
The ctx.bind call binds the OracleDataSource instance to a logical JNDI name.
This means that anytime after the ctx.bind call, you can use the logical name
jdbc/sampledb in opening a connection to the database described by the properties
of the OracleDataSource instance ods. The logical name jdbc/sampledb is
logically bound to this database.
The JNDI namespace has a hierarchy similar to that of a file system. In this example,
the JNDI name specifies the subcontext jdbc under the root naming context and
specifies the logical name sampledb within the jdbc subcontext.
The Context interface and InitialContext class are in the standard
javax.naming package.
Note: The JDBC 2.0 Specification requires that all JDBC data
sources be registered in the jdbc naming subcontext of a JNDI
namespace or in a child subcontext of the jdbc subcontext.
Open a Connection
To perform a lookup and open a connection to the database logically bound to the
JNDI name, use the logical JNDI name. Doing this requires casting the lookup result,
which is otherwise a Java Object, to OracleDataSource and then using its
getConnection method to open the connection.
Here is an example:
OracleDataSource odsconn = (OracleDataSource)ctx.lookup("jdbc/sampledb");
Connection conn = odsconn.getConnection();
Note: The ability to specify a role is supported only for the sys
user name.
■ In Microsoft Windows
orapwd file=%ORACLE_HOME%\database\PWDsid_name.ora entries=200
Enter password: password
file must be the name of the password file. password is the password for the
user SYS. It can be altered using the ALTER USER statement in SQL Plus. You
should set entries to a value higher than the number of entries you expect.
The syntax for the password file name is different on Microsoft Windows and
UNIX.
2. Enable remote login as sysdba. This step grants SYSDBA and SYSOPER system
privileges to individual users and lets them connect as themselves.
Stop the database, and add the following line to initservice_name.ora, in
UNIX, or init.ora, in Microsoft Windows:
remote_login_passwordfile=exclusive
3. Change the password for the SYS user. This is an optional step.
PASSWORD sys
Changing password for sys
New password: password
Retype new password: password
Example
The following example shows how to use the put method of the
java.util.Properties class, in this case, to set Oracle performance extension
parameters.
//import packages and register the driver
import java.sql.*;
import java.math.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.OracleDataSource;
Note:
■ The brackets indicate that the username/password pair is
optional.
■ kprb, the internal server-side driver, uses an implicit
connection. Database URLs for the server-side driver end after
the driver_type.
The first part of the URL specifies which JDBC driver is to be used. The supported
driver_type values are thin, oci, and kprb.
The remainder of the URL contains an optional user name and password separated by
a slash, an @, and the database specifier, which uniquely identifies the database to
which the application is connected. Some database specifiers are valid only for the
JDBC Thin driver, some only for the JDBC OCI driver, and some for both.
Database Specifiers
Table 8–3, shows the possible database specifiers, listing which JDBC drivers support
each specifier.
Note:
■ Starting Oracle Database 10g, Oracle Service IDs are not
supported.
■ Starting Oracle Database 10g, Oracle no longer supports Oracle
Names as a naming method.
For example:
jdbc:oracle:thin:scott/tiger@//myhost:1521/myservicename
Note: The JDBC Thin driver supports only the TCP/IP protocol.
Note: When using TNSNames with the JDBC Thin driver, you must
set the oracle.net.tns_admin property to the directory that
contains your tnsnames.ora file.
java -Doracle.net.tns_admin=$ORACLE_HOME/network/admin
LDAP Syntax
An example of database specifier using the Lightweight Directory Access Protocol
(LDAP) syntax is as follows:
"jdbc:oracle:thin:@ldap://ldap.acme.com:7777/sales,cn=OracleContext,dc=com"
Note: The JDBC Thin driver can use LDAP over SSL to
communicate with Oracle Internet Directory if you substitute
ldaps: for ldap: in the database specifier. The LDAP server must
be configured to use SSL. If it is not, then the connection attempt
will hang.
The JDBC Thin driver supports failover of a list of LDAP servers during the service
name resolution process, without the need for a hardware load balancer. Also,
client-side load balancing is supported for connecting to LDAP servers. A list of space
separated LDAP URLs syntax is used to support failover and load balancing.
When a list of LDAP URLs is specified, both failover and load balancing are enabled
by default. The oracle.net.ldap_loadbalance connection property can be used
to disable load balancing, and the oracle.net.ldap_failover connection
property can be used to disable failover.
An example, which uses failover, but with client-side load balancing disabled, is as
follows:
Properties prop = new Properties();
String url =
"jdbc:oracle:thin:@ldap://ldap1.acme.com:3500/cn=salesdept,cn=OracleContext,dc=com
/salesdb " +
"ldap://ldap2.acme.com:3500/cn=salesdept,cn=OracleContext,dc=com/salesdb " +
"ldap://ldap3.acme.com:3500/cn=salesdept,cn=OracleContext,dc=com/salesdb";
prop.put("oracle.net.ldap_loadbalance", "OFF" );
OracleDataSource ods = new OracleDataSource();
ods.setURL(url);
ods.setConnectionProperties(prop);
The JDBC Thin driver supports LDAP nonanonymous bind. A set of JNDI
environment properties, which contains authentication information, can be specified
for a data source. If a LDAP server is configured as not allowing anonymous bind,
then authentication information must be provided to connect to the LDAP server. The
following example shows a simple clear-text password authentication:
String url =
"jdbc:oracle:thin:@ldap://ldap.acme.com:7777/sales,cn=salesdept,cn=OracleContext,d
c=com";
ods.setConnectionProperties(prop);
Since JDBC passes down the three properties to JNDI, the authentication mechanism
chosen by client is consistent with how these properties are interpreted by JNDI. For
example, if the client specifies authentication information without explicitly specifying
the java.naming.security.authentication property, then the default
authentication mechanism is "simple". Please refer to relevant JDNI documentation for
details.
This chapter discusses support in the Oracle Java Database Connectivity (JDBC) Oracle
Call Interface (OCI) and JDBC Thin drivers for login authentication, data encryption,
and data integrity, particularly, with respect to features of the Oracle Advanced
Security option.
Oracle Advanced Security, previously known as the Advanced Networking Option
(ANO) or Advanced Security Option (ASO), provides industry standards-based data
encryption, data integrity, third-party authentication, single sign-on, and access
authorization. From 11g release 1 (11.1), both the JDBC OCI and Thin drivers support
all the Oracle Advanced Security features. Earlier releases of the JDBC drivers did not
support some of the ASO features.
SSL Authentication
Example 9–1 uses SSL authentication to connect to the database.
Example 9–1
import java.sql.*;
import java.util.Properties;
Example 9–2
import java.sql.*;
import javax.sql.*;
import java.util.Properties;
import oracle.jdbc.pool.*;
authentication. Oracle JDBC drivers provide support for the following strong
authentication methods:
■ Kerberos
■ RADIUS
■ SSL (certificate-based authentication)
When a connection is attempted from the local database server, the OS username is
passed to the Oracle server. If the username is recognized, the Oracle the connection is
accepted, otherwise the connection is rejected.
su - w_rose
export ORACLE_HOME=/u01/app/oracle/product/10.1.0/db_1
export PATH=$PATH:$ORACLE_HOME/bin
export ORACLE_SID=DEV1
sqlplus /
Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Data Mining options
SQL>
Note: The preceding steps are only for creating a local user. Domain
users can be created in Active Directory.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.1.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>
The preceding code assumes that it is executed by p_floyd on the client machine. The
JDBC drivers retrieve the OS username from the user.name system property that is
set by the JVM. As a result, the following thin driver-specific error no longer exists:
ORA-17443=Null user or password not supported in THIN driver
Table 9–1 shows, for example, that if encryption is requested by the client, but rejected
by the server, it is disabled. The same is true for integrity. As another example, if
encryption is accepted by the client and requested by the server, it is enabled. And,
again, the same is true for integrity.
Table 9–2 OCI Driver Client Parameters for Encryption and Integrity
Parameter Description Parameter Name Possible Settings
Client encryption level SQLNET.ENCRYPTION_CLIENT REJECTED
ACCEPTED
REQUESTED
REQUIRED
Client encryption selected list SQLNET.ENCRYPTION_TYPES_CLIENT RC4_40, RC4_56,
DES, DES40, AES128,
AES192, AES256,
3DES112, 3DES168
(see Note)
Client integrity level SQLNET.CRYPTO_CHECKSUM_CLIENT REJECTED
ACCEPTED
REQUESTED
REQUIRED
Client integrity selected list SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT MD5, SHA-1
Table 9–3 Thin Driver Client Parameters for Encryption and Integrity
Parameter
Parameter Name Type Possible Settings
CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL String REJECTED
ACCEPTED
REQUESTED
REQUIRED
CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES String AES256, AES192, AES128, 3DES168,
3DES112, DES56C, DES40C, RC4_256,
RC4_128, RC4_40, RC4_56
CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL String REJECTED
ACCEPTED
REQUESTED
REQUIRED
CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES String MD5, SHA1
Note:
■ Because Oracle Advanced Security support for the Thin driver
is incorporated directly into the JDBC classes JAR file, there is
only one version, not separate domestic and export editions.
Only parameter settings that would be suitable for an export
edition are possible.
■ The letter C in DES40C and DES56C refers to Cipher Block
Chaining (CBC) mode.
The parentheses around the values encryption type and checksum type allow for lists
of values. When multiple values are supplied, the server and the client negotiate to
determine which value is to be actually used.
Example
Example 9–3 is a complete class that sets data encryption and integrity parameters
before connecting to a database to perform a query.
Before running this example, you must turn on encryption in the sqlnet.ora file.
For example, the following lines will turn on AES256, AES192, and AES128 for the
encryption and MD5 and SHA1 for the checksum:
SQLNET.ENCRYPTION_SERVER = ACCEPTED
SQLNET.CRYPTO_CHECKSUM_SERVER = ACCEPTED
SQLNET.CRYPTO_CHECKSUM_TYPES_SERVER= (MD5, SHA1)
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_LEVEL,An
oServices.ANO_REQUIRED);
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_ENCRYPTION_TYPES,"(
" + AnoServices.ENCRYPTION_AES256
+ "," + AnoServices.ENCRYPTION_AES192 + ")");
// We also require the use of the SHA1 algorithm for data integrity checking.
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_LEVEL,AnoS
ervices.ANO_REQUIRED);
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CHECKSUM_TYPES,"( "
+ AnoServices.CHECKSUM_SHA1 + " )");
prop.setProperty("user",DemoAESAndSHA1.USERNAME);
prop.setProperty("password",DemoAESAndSHA1.PASSWORD);
OracleConnection oraConn =
(OracleConnection)dr.connect(DemoAESAndSHA1.URL,prop);
System.out.println("Connection created! Encryption algorithm is: " +
SSL Terminology
The following terms are commonly used in the SSL context:
■ certificate: A certificate is a digitally signed document that binds a public key with
an entity. The certificate can be used to verify that the public key belongs to that
individual.
■ certification authority: A certification authority (CA), also known as certificate
authority, is an entity which issues digitally signed certificates for use by other
parties.
■ cipher suite: A cipher suite is a set of cryptographic algorithms and key sizes used
to encrypt data sent over an SSL-enabled network.
■ private key: A private key is a secret key, which is never transmitted over a
network. The private key is used to decrypt a message that has been encrypted
using the corresponding public key. It is also used to sign certificates. The
certificate is verified using the corresponding public key.
■ public key: A public key is an encryption key that can be made public or sent by
ordinary means such as an e-mail message. The public key is used for encrypting
the message sent over SSL. It is also used to verify a certificate signed by the
corresponding private key.
■ wallet: A wallet is a password-protected container that is used to store
authentication and signing credentials, including private keys, certificates, and
trusted certificates required by SSL.
■ osdt_core.jar
All these JAR files should be under $ORACLE_HOME/jlib directory.
3. Use the following commands to connect to the database as sysdba and dismount
it:
SQL> connect / as sysdba
SQL> shutdown immediate;
trace_level_server=16
trace_directory_server=/scratch/sqlnet/
7. Use the following commands to verify that you can connect through SQL*Plus:
> kinit client
> klist
Ticket cache: FILE:/tmp/krb5cc_5088
Default principal: [email protected]
Code Example
This following example demonstrates the new Kerberos authentication feature that is
part of Oracle Database 11g Release 1 (11.1) JDBC thin driver. This demo covers two
scenarios:
■ In the first scenario, the OS maintains the user name and credentials. The
credentials are stored in the cache and the driver retrieves the credentials before
trying to authenticate to the server. This scenario is in the module
connectWithDefaultUser().
Note: 1.Before you run this part of the demo, use the following command to
verify that you have valid credentials:
> /usr/kerberos/bin/kinit client
where, the password is welcome.
2. Use the following command to list your tickets:
> /usr/kerberos/bin/klist
■ The second scenario covers the case where the application wants to control the
user credentials. This is the case of the application server where multiple web
users have their own credentials. This scenario is in the module
connectWithSpecificUser().
Note: To run this demo, you need to have a working setup, that is, a
Kerberos server up and running, and an Oracle database server that is
configured to use Kerberos authentication. You then need to change
the URLs used in the example to compile and run it.
Example 9–4
import com.sun.security.auth.module.Krb5LoginModule;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.net.ano.AnoServices;
public class KerberosJdbcDemo
{
String url ="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)"+
"(HOST=oracleserver.mydomain.com)(PORT=5561))(CONNECT_DATA=" +
"(SERVICE_NAME=mydatabaseinstance)))";
System.setProperty("java.security.krb5.conf","/home/Jdbc/Security/kerberos/krb5.co
nf");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERV
ICES,
"("+AnoServices.AUTHENTICATION_KERBEROS5+")");
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5
_MUTUAL,
"true");
/* If you get the following error [Unable to obtain Princpal Name for
* authentication] although you know that you have the right TGT in your
* credential cache, then it's probably because the JVM can't locate your
* cache.
*
* Note that the default location on windows is "C:\Documents and
Settings\krb5cc_username".
*/
//
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5
_CC_NAME,
/*
On linux:
> which kinit
/usr/kerberos/bin/kinit
> ls -l /etc/krb5.conf
lrwxrwxrwx 1 root root 47 Jun 22 06:56 /etc/krb5.conf ->
/home/Jdbc/Security/kerberos/krb5.conf
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_KRB5
_CC_NAME,
"/tmp/krb5cc_5088");
Connection conn = driver.connect(url,prop);
String auth = ((OracleConnection)conn).getAuthenticationAdaptorName();
System.out.println("Authentication adaptor="+auth);
printUserName(conn);
conn.close();
}
// This first part isn't really meaningful to the sake of this demo. In
// a real world scenario, you have a valid "specificSubject" Subject that
// represents a web user that has valid Kerberos credentials.
Krb5LoginModule krb5Module = new Krb5LoginModule();
HashMap sharedState = new HashMap();
HashMap options = new HashMap();
options.put("doNotPrompt","false");
options.put("useTicketCache","false");
options.put("principal","[email protected]");
krb5Module.initialize(specificSubject,newKrbCallbackHandler(),sharedState,options)
;
boolean retLogin = krb5Module.login();
krb5Module.commit();
if(!retLogin)
throw new Exception("Kerberos5 adaptor couldn't retrieve credentials (TGT)
from the cache");
// Now we have a valid Subject with Kerberos credentials. The second scenario
// really starts here:
// execute driver.connect(...) on behalf of the Subject 'specificSubject':
Connection conn =
(Connection)Subject.doAs(specificSubject, new PrivilegedExceptionAction()
{
public Object run()
{
Connection con = null;
Properties prop = new Properties();
prop.setProperty(AnoServices.AUTHENTICATION_PROPERTY_SERVICES,
"(" + AnoServices.AUTHENTICATION_KERBEROS5 + ")");
try
{
OracleDriver driver = new OracleDriver();
con = driver.connect(url, prop);
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select user from dual");
while(rs.next())
System.out.println("User is:"+rs.getString(1));
rs.close();
}
finally
{
if(stmt != null)
stmt.close();
}
}
}
2. Use the following commands to create a new user aso from within a database:
SQL> create user aso identified externally;
SQL> grant create session to aso;
3. Use the following commands to connect to the database as sysdba and dismount
it:
SQL> connect / as sysdba
SQL> shutdown immediate;
Note: Once the test is over, you need to revert the preceding changes
made to the t_init1.ora file.
7. Use the following command to verify that you can connect through SQL*Plus:
>sqlplus
'aso/1234@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracleserver.mydomain.com)(
PORT=5529))
(CONNECT_DATA=(SERVICE_NAME=mydatabaseinstance)))'
Code Example
This example demonstrates the new RADIUS authentication feature that is a part of
Oracle Database 11g Release 1 (11.1) JDBC thin driver. You need to have a working
setup, that is, a RADIUS server up and running, and an Oracle database server that is
configured to use RADIUS authentication. You then need to change the URLs given in
the example to compile and run it.
Example 9–5
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleDriver;
import oracle.net.ano.AnoServices;
public class RadiusJdbcDemo
{
String url ="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)"+
"(HOST=oracleserver.mydomain.com)(PORT=5561))(CONNECT_DATA=" +
"(SERVICE_NAME=mydatabaseinstance)))";
/*
* This method attempts to logon to the database using the RADIUS
* authentication protocol.
*
* It should print the following output to stdout:
* -----------------------------------------------------
* Authentication adaptor=RADIUS
* User is:ASO
* -----------------------------------------------------
*/
void connect() throws SQLException
{
OracleDriver driver = new OracleDriver();
Properties prop = new Properties();
prop.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_AUTHENTICATION_SERV
ICES,
"("+AnoServices.AUTHENTICATION_RADIUS+")");
// The user "aso" needs to be properly setup on the radius server with
// password "1234".
prop.setProperty("user","aso");
prop.setProperty("password","1234");
Note that you need not specify database login credentials in this CONNECT statement.
Instead your system looks for database login credentials in the client wallet.
Oracle Java Database Connectivity (JDBC) provides proxy authentication, also called
N-tier authentication. This feature is supported through both the JDBC Oracle Call
Interface (OCI) driver and the JDBC Thin driver. This chapter contains the following
sections:
■ About Proxy Authentication
■ Types of Proxy Connections
■ Creating Proxy Connections
■ Closing a Proxy Session
■ Caching Proxy Connections
In all cases, an administrator must authorize the middle-tier server to proxy a client,
that is, to act on behalf of the client. Operations done on behalf of a client by a
middle-tier server can be audited. Issue the following command to authorize the
middle-tier server to proxy a client:
ALTER USER jeff GRANT CONNECT THROUGH scott;
The role clause limits the access only to those database objects that are mentioned
in the list of the roles. The list of roles can be empty.
■ Find the users who are currently authorized to connect through a middle tier by
querying the PROXY_USERS data dictionary view.
■ Disallow a proxy connection by using the REVOKE CONNECT THROUGH clause of
ALTER USER command.
You need to use the different fields and methods present in the
oracle.jdbc.OracleConnection interface to set up the different types of proxy
connections.
In this case, jeff is the user name and scott is the proxy for jeff.
The password option exists for additional security. Having no authenticated
clause implies default authentication, which is using only the user name without
the password. The SQL statement for specifying default authentication is:
ALTER USER jeff GRANT CONNECT THROUGH scott
■ DISTINGUISHED NAME
This is a global name in lieu of the password of the user being proxied for. An
example of the corresponding SQL statement using a distinguished name is:
CREATE USER jeff IDENTIFIED GLOBALLY AS
'CN=jeff,OU=americas,O=oracle,L=redwoodshores,ST=ca,C=us';
■ CERTIFICATE
This is a more encrypted way of passing the credentials of the user, who is to be
proxied, to the database. The certificate contains the distinguished name encoded
in it. One way of generating the certificate is by creating a wallet and then
decoding the wallet to get the certificate. The wallet can be created using runutl
mkwallet. It is then necessary to authenticate using the generated certificate. The
SQL statement for specifying authentication using certificate is:
ALTER USER jeff GRANT CONNECT THROUGH scott AUTHENTICATED USING CERTIFICATE;
.
Note:
■ All the options can be associated with roles.
■ When opening a new proxied connection, a new session is started
on the database server. Along with this session a new local
transaction is created.
A new proxy session is opened by using the following method from the
oracle.jdbc.OracleConnection interface:
void openProxySession(int type, java.util.Properties prop) throws
SQLExceptionOpens
Where,
type is the type of the proxy session and can have the following values:
■ OracleConnection.PROXYTYPE_USER_NAME
This type is used for specifying the user name.
■ OracleConnection.PROXYTYPE_DISTINGUISHED_NAME
This type is used for specifying the distinguished name of the user.
■ OracleConnection.PROXYTYPE_CERTIFICATE
This type is used for specifying the proxy certificate.
prop is the property value of the proxy session and can have the following values:
■ PROXY_USER_NAME
This property value should be used with the type
OracleConnection.PROXYTYPE_USER_NAME. The value should be a
java.lang.String.
■ PROXY_DISTINGUISHED_NAME
This property value should be used with the type
OracleConnection.PROXYTYPE_DISTINGUISHED_NAME. The value should be
a java.lang.String.
■ PROXY_CERTIFICATE
This property value should be used with the type
OracleConnection.PROXYTYPE_CERTIFICATE. The value is a bytep[] array
that contains the certificate.
■ PROXY_ROLES
This property value can be used with the following types:
– OracleConnection.PROXYTYPE_USER_NAME
– OracleConnection.PROXYTYPE_DISTINGUISHED_NAME
– OracleConnection.PROXYTYPE_CERTIFICATE
The value should be a java.lang.String.
■ PROXY_SESSION
This property value is used with the close method to close the proxy session.
■ PROXY_USER_PASSWORD
This property value should be used with the type
OracleConnection.PROXYTYPE_USER_NAME. The value should be a
java.lang.String.
The following code snippet shows the use of the openProxySession method:
java.util.Properties prop = new java.util.Properties();
prop.put(OracleConnection.PROXY_USER_NAME, "jeff");
String[] roles = {"role1", "role2"};
prop.put(OracleConnection.PROXY_ROLES, roles);
conn.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, prop);
OracleConnection.close(OracleConnection.PROXY_SESSION);
A proxy connection may be cached in the connection cache using the connection
attributes feature of the connection cache. Connection attributes are name/value pairs
that are user-defined and help tag a connection before returning it to the connection
cache for reuse. When the tagged connection is retrieved, it can be directly used
without having to do a round-trip to create or close a proxy session. Implicit
connection cache supports caching of any user/password authenticated connection.
Therefore, any user authenticated proxy connection can be cached and retrieved.
It is recommended that proxy connections should not be closed without applying the
connection attributes. If a proxy connection is closed without applying the connection
attributes, the connection is returned to the connection cache for reuse, but cannot be
retrieved. The connection caching mechanism does not remember or reset session
state.
A proxy connection can be removed from the connection cache by closing the
connection directly.
This part provides a chapter that discusses about accessing and manipulating Oracle
data. It also includes chapters that provide information about Java Database
Connectivity (JDBC) support for user-defined object types, large object (LOB) and
binary file (BFILE) locators and data, object references, and Oracle collections, such as
nested tables. This part also provides chapters that discuss the result set functionality
in JDBC, JDBC row sets, and globalization support provided by Oracle JDBC drivers.
Part IV contains the following chapters:
■ Chapter 11, "Accessing and Manipulating Oracle Data"
■ Chapter 12, "Java Streams in JDBC"
■ Chapter 13, "Working with Oracle Object Types"
■ Chapter 14, "Working with LOBs and BFILEs"
■ Chapter 15, "Using Oracle Object References"
■ Chapter 16, "Working with Oracle Collections"
■ Chapter 17, "Result Set"
■ Chapter 18, "JDBC RowSets"
■ Chapter 19, "Globalization Support"
11
Accessing and Manipulating Oracle Data
Table of Mappings
Table 11–1 shows the default mappings between SQL data types, JDBC type codes,
standard Java types, and Oracle extended types.
The SQL Data Types column lists the SQL types that exist in Oracle Database 11g. The
JDBC Type Codes column lists data type codes supported by the JDBC standard and
defined in the java.sql.Types class or by Oracle in the
oracle.jdbc.OracleTypes class. For standard type codes, the codes are identical
in these two classes.
The Standard Java Types column lists standard types defined in the Java language. The
Oracle Extension Java Types column lists the oracle.sql.* Java types that
correspond to each SQL data type in the database. These are Oracle extensions that let
you retrieve all SQL data in the form of a oracle.sql.* Java type. Manipulating
Table 11–1 Default Mappings Between SQL Types and Java Types
Oracle Extension Java
SQL Data Types JDBC Type Codes Standard Java Types Types
STANDARD JDBC TYPES:
CHAR java.sql.Types.CHAR java.lang.String oracle.sql.CHAR
VARCHAR2 java.sql.Types.VARCHAR java.lang.String oracle.sql.CHAR
LONG java.sql.Types.LONGVARCHAR java.lang.String oracle.sql.CHAR
NUMBER java.sql.Types.NUMERIC java.math.BigDecima oracle.sql.NUMBER
l
NUMBER java.sql.Types.DECIMAL java.math.BigDecima oracle.sql.NUMBER
l
NUMBER java.sql.Types.BIT boolean oracle.sql.NUMBER
NUMBER java.sql.Types.TINYINT byte oracle.sql.NUMBER
NUMBER java.sql.Types.SMALLINT short oracle.sql.NUMBER
NUMBER java.sql.Types.INTEGER int oracle.sql.NUMBER
NUMBER java.sql.Types.BIGINT long oracle.sql.NUMBER
NUMBER java.sql.Types.REAL float oracle.sql.NUMBER
NUMBER java.sql.Types.FLOAT double oracle.sql.NUMBER
NUMBER java.sql.Types.DOUBLE double oracle.sql.NUMBER
RAW java.sql.Types.BINARY byte[] oracle.sql.RAW
RAW java.sql.Types.VARBINARY byte[] oracle.sql.RAW
LONGRAW java.sql.Types.LONGVARBINARY byte[] oracle.sql.RAW
DATE java.sql.Types.DATE java.sql.Date oracle.sql.DATE
DATE java.sql.Types.TIME java.sql.Time oracle.sql.DATE
TIMESTAMP java.sql.Types.TIMESTAMP javal.sql.Timestamp oracle.sql.TIMESTAMP
BLOB java.sql.Types.BLOB java.sql.Blob oracle.sql.BLOB
CLOB java.sql.Types.CLOB java.sql.Clob oracle.sql.CLOB
user-defined java.sql.Types.STRUCT java.sql.Struct oracle.sql.STRUCT
object
user-defined java.sql.Types.REF java.sql.Ref oracle.sql.REF
reference
user-defined java.sql.Types.ARRAY java.sql.Array oracle.sql.ARRAY
collection
ROWID java.sql.Types.ROWID java.sql.RowId oracle.sql.ROWID
NCLOB java.sql.Types.NCLOB java.sql.NClob oracle.sql.NCLOB
NCHAR java.sql.Types.NCHAR java.lang.String oracle.sql.CHAR
ORACLE EXTENSIONS:
Table 11–1 (Cont.) Default Mappings Between SQL Types and Java Types
Oracle Extension Java
SQL Data Types JDBC Type Codes Standard Java Types Types
BFILE oracle.jdbc.OracleTypes.BFIL NA oracle.sql.BFILE
E
REF CURSOR oracle.jdbc.OracleTypes.CURS java.sql.ResultSet oracle.jdbc.OracleRe
OR sultSet
TIMESTAMP oracle.jdbc.OracleTypes.TIME java.sql.Timestamp oracle.sql.TIMESTAMP
STAMP
TIMESTAMP oracle.jdbc.OracleTypes.TIME java.sql.Timestamp oracle.sql.TIMESTAMP
WITH TIME STAMPTZ TZ
ZONE
TIMESTAMP oracle.jdbc.OracleTypes.TIME java.sql.Timestamp oracle.sql.TIMESTAMP
WITH LOCAL STAMPLTZ LTZ
TIME ZONE
See Also :
■ "Valid SQL-JDBC Data Type Mappings" on page A-1
■ Chapter 4, "Oracle Extensions"
NUMBER Types
For the different type codes that an Oracle NUMBER value can correspond to, call the
getter routine that is appropriate for the size of the data for mapping to work properly.
For example, call getByte to get a Java tinyint value for an item x, where -128 < x <
128.
User-Defined Types
User-defined types, such as objects, object references, and collections, map by default
to weak Java types, such as java.sql.Struct, but alternatively can map to strongly
typed custom Java classes. Custom Java classes can implement one of two interfaces:
■ The standard java.sql.SQLData
■ The Oracle-specific oracle.sql.ORAData
See Also: "Mapping Oracle Objects" on page 13-1 and "Creating and
Using Custom Object Classes for Oracle Objects" on page 13-6
The next example shows how to compare values for equality when some return values
might be NULL. The following code returns all the ENAMES from the EMP table that are
NULL, if there is no value of 100 for COMM.
PreparedStatement pstmt = conn.prepareStatement("SELECT ENAME FROM EMP
WHERE COMM =? OR ((COMM IS NULL) AND (? IS NULL))");
pstmt.setBigDecimal(1, new BigDecimal(100));
pstmt.setNull(2, java.sql.Types.VARCHAR);
If you need the extended functionality provided by the Oracle extensions to JDBC, you
can select the results into a standard ResultSet variable and then cast that variable
to OracleResultSet later.
Key extensions to the result set and statement classes include the getOracleObject
and setOracleObject methods, used to access and manipulate data in
oracle.sql.* formats.
Note: You cannot qualify a column name with a table name and pass
it as a parameter to the getXXX method. For example:
ResultSet rset = stmt.executeQuery("SELECT emp.deptno, dept.deptno
FROM emp, dept");
rset.getInt("emp.deptno");
When you retrieve data into a Datum variable, you can use the standard Java
instanceof operator to determine which oracle.sql.* type it really is.
See Also: Table A–1, " Valid SQL Data Type-Java Class Mappings"
on page A-1, for information about type compatibility between all
SQL and Java types.
getBigDecimal
JDBC 2.0 simplified method signatures for the getBigDecimal method. The previous
input signatures were:
(int columnIndex, int scale) or (String columnName, int scale)
The scale parameter, used to specify the number of digits to the right of the decimal,
is no longer necessary. The Oracle JDBC drivers retrieve numeric values with full
precision.
getBoolean
Because there is no BOOLEAN database type, when you use getBoolean a data type
conversion always occurs. The getBoolean method is supported only for numeric
columns. When applied to these columns, getBoolean interprets any zero value as
false and any other value as true. When applied to any other sort of column,
getBoolean raises the exception java.lang.NumberFormatException.
Binding Oracle-specific types using the appropriate setXXX methods, instead of the
methods used for binding standard Java types, may offer some performance
advantage.
This section covers the following topics:
■ Input Data Binding
■ Method setFixedCHAR for Binding CHAR Data into WHERE Clauses
For fixed length character sets, multiply the length of the Java character data by the
fixed character size in bytes and compare that to the restrictive values. For variable
length character sets, there are three cases based on the Java character length, as
follows:
■ If character length is less than 32766 divided by the maximum character size, then
direct bind is used.
■ If character length is greater than 32766 divided by the minimum character size,
then LOB bind is used.
■ If character length is in between and if the actual length of the converted bytes is
less than 32766, then direct bind is used, else LOB bind is used.
See Also: JDBC Release Notes for further discussion and possible
workarounds
Note:
■ Remember to cast your prepared statement object to
OraclePreparedStatement to use the setFixedCHAR
method.
■ There is no need to use setFixedCHAR for an INSERT
statement. The database always automatically pads the data to
the column width as it inserts it.
Example
The following example demonstrates the difference between the setCHAR and
setFixedCHAR methods.
/* Schema is :
create table my_table (col1 char(10));
insert into my_table values ('JDBC');
*/
PreparedStatement pstmt = conn.prepareStatement
("select count(*) from my_table where col1 = ?");
((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC");
runQuery (pstmt); // This will print "No of rows are 1"
while (rs.next())
System.out.println("No of rows are " + rs.getInt(1));
rs.close();
rs = null;
}
while (rset.next())
{
OracleResultSetMetaData orsmd = ((OracleResultSet)rset).getMetaData();
int numColumns = orsmd.getColumnCount();
System.out.println("Num of columns = " + numColumns);
PL/SQL Blocks
The basic unit in PL/SQL is a block. All PL/SQL programs are made up of blocks,
which can be nested within each other. A PL/SQL block has three parts: a declarative
part, an executable part, and an exception-handling part. You get the following
advantages by using PL/SQL blocks in your application:
■ Better performance
■ Higher productivity
■ Full portability
■ Tight integration with Oracle
■ Tight security
This chapter describes how the Oracle Java Database Connectivity (JDBC) drivers
handle Java streams for several data types. Data streams enable you to read LONG
column data of up to 2 gigabytes (GB). Methods associated with streams let you read
the data incrementally.
This chapter covers the following topics:
■ Streaming LONG or LONG RAW Columns
■ Streaming CHAR, VARCHAR, or RAW Columns
■ Streaming LOBs and External Files
■ Data Streaming and Multiple Columns
■ Streaming and Row Prefetching
■ Closing a Stream
■ Notes and Precautions on Streams
To access the data in a LONG column, you can get the column as a Java InputStream
object and use the read method of the InputStream object. As an alternative, you
can get the data as a String or byte array. In this case, the driver will do the
streaming for you.
You can get LONG and LONG RAW data with any of the three stream types. The driver
performs conversions for you, depending on the character set of the database and the
driver.
Note: Do not create tables with LONG columns. Use large object
(LOB) columns, CLOB, NCLOB, and BLOB, instead. LONG columns
are supported only for backward compatibility. Oracle recommends
that you convert existing LONG columns to LOB columns. LOB
columns are subject to far fewer restrictions than LONG columns.
■ If the driver is JDBC OCI and the client character set is not US7ASCII or
WE8ISO8859P1, then a call to getBinaryStream returns UTF-8. If the client
character set is US7ASCII or WE8ISO8859P1, then the call returns a US7ASCII
stream of bytes.
■ If the driver is JDBC Thin and the database character set is not US7ASCII or
WE8ISO8859P1, then a call to getBinaryStream returns UTF-8. If the
server-side character set is US7ASCII or WE8ISO8859P1, then the call returns a
US7ASCII stream of bytes.
Table 12–1 summarizes LONG and LONG RAW data conversions for each stream type.
The following Java code snippet writes the data from the LONG RAW column into a file
called leslie.gif:
ResultSet rset = stmt.executeQuery
("select GIFDATA from streamexample where NAME='LESLIE'");
if (rset.next())
{
// Get the GIF data as a stream from Oracle to the client
InputStream gif_data = rset.getBinaryStream (1);
try
{
FileOutputStream file = null;
file = new FileOutputStream ("leslie.gif");
int chunk;
while ((chunk = gif_data.read()) != -1)
file.write(chunk);
}
catch (Exception e)
{
String err = e.toString();
System.out.println(err);
}
finally
{
if file != null()
file.close();
}
}
Because a LONG RAW column can contain up to 2 gigabytes of data, the getBytes
example can use much more memory than the getBinaryStream example. Use
streams if you do not know the maximum size of the data in your LONG or LONG RAW
columns.
method. The getXXXStream entry points return a stream that reads data from this
buffer.
See Also: "Reading and Writing BLOB, CLOB and NCLOB Data" on
page 14-5 and "Data Interface for LOBs" on page 14-10
Streaming BFILEs
An external file, or BFILE, is used to store a locator to a file outside the database. The
file can be stored somewhere on the file system of the data server. The locator points to
the actual location of the file.
When a query fetches one or more BFILE columns, the JDBC driver transfers the file
to the client as required. The data can be accessed as a stream To manipulate BFILE
data from JDBC, use methods in the Oracle extension class oracle.sql.BFILE. This
class provides specific functionality, such as reading from the BFILE into an input
stream, writing from an output stream into a BFILE, determining the length of a
BFILE, and closing a BFILE.
The incoming data for each row has the following shape:
<a date><the characters of the long column><a number>
As you process each row of the result set, you must complete any processing of the
stream column before reading the number column.
while rset.next()
{
//get the date
java.sql.Date date = rset.getDate(1);
Closing a Stream
You can discard the data from a stream at any time by calling the close method. It is
a good programming practice to close the connection when you no longer need it.
If you do not use the order as in the SELECT statement to access data, then you can
lose the stream data. That is, if you bypass the stream data column and access data
in a column that follows it, then the stream data will be lost. For example, if you
try to access the data for the NUMBER column before reading the data from the
stream data column, then the JDBC driver first reads then discards the streaming
data automatically. This can be very inefficient if the LONG column contains a large
amount of data.
If you try to access the LONG column later in the program, then the data will not be
available and the driver will return a "Stream Closed" error.
The later point is illustrated in the following example:
ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
int n = rset.getInt(3); // This discards the streaming data
InputStream is = rset.getAsciiStream(2);
// Raises an error: stream closed.
}
If you get the stream but do not use it before you get the NUMBER column, then the
stream still closes automatically:
ResultSet rset = stmt.executeQuery
("select DATECOL, LONGCOL, NUMBERCOL from TABLE");
while rset.next()
{
InputStream is = rset.getAsciiStream(2); // Get the stream
int n = rset.getInt(3);
// Discards streaming data and closes the stream
}
int c = is.read(); // c is -1: no more characters to read-stream closed
See Also: "Data Interface for LOBs" on page 14-10 and release notes
for details
This chapter describes the Java Database Connectivity (JDBC) support for user-defined
object types. It discusses functionality of the generic, weakly typed
oracle.sql.STRUCT class, as well as how to map to custom Java classes that
implement either the JDBC standard SQLData interface or the Oracle ORAData
interface.
The following topics are covered:
■ Mapping Oracle Objects
■ Using the Default STRUCT Class for Oracle Objects
■ Creating and Using Custom Object Classes for Oracle Objects
■ Object-Type Inheritance
■ Using JPublisher to Create Custom Object Classes
■ Describing an Object Type
Note: In this book, Java classes that you create to map to Oracle
objects will be referred to as custom Java classes or, more specifically,
custom object classes. This is as opposed to custom references
classes, which are Java classes that map to object references, and
custom collection classes, which are Java classes that map to Oracle
collections.
Custom object classes can implement either a standard JDBC interface or an Oracle
extension interface to read and write data. JDBC materializes Oracle objects as
instances of particular Java classes. Two main steps in using JDBC to access Oracle
objects are:
1. Creating the Java classes for the Oracle objects
Note: When you use the SQLData interface, you must use a Java
type map to specify your SQL-Java mapping, unless weakly typed
java.sql.Struct objects will suffice.
a structured object type. The Java types for other attribute values would be the
same as for a getObject call on data of the underlying SQL type.
■ getAttributes
This method is the same as the preceding getAttributes(map) method, except
it uses the default type map for the connection.
■ getSQLTypeName
This method returns a Java String that represents the fully qualified name of the
Oracle object type that this Struct represents.
Another way to return the object as a STRUCT object is to cast the result set to
OracleResultSet and use the Oracle extension getSTRUCT method:
oracle.sql.STRUCT oracleSTRUCT=((OracleResultSet)rs).getSTRUCT(1);
or:
oracle.sql.Datum[] attrs = ((oracle.sql.STRUCT)jdbcStruct).getOracleAttributes();
The sql_type_name parameter is a Java String containing the name of the Oracle
object type, such as EMPLOYEE, and connection is the connection object.
Once you have your StructDescriptor object for the Oracle object type, you can
construct the STRUCT object. To do this, provide the Connection object, the
StructDescriptor object, and an array of Java objects containing the attributes you
want the STRUCT to contain.
The following constructors of STRUCT are available:
STRUCT(Connection conn, java.sql.StructDescriptor structDesc, Object[] attributes)
The following code illustrates the use of the constructor that takes a Map object:
...
HashMap map = new HashMap(1);
map.put("A1","attribute1");
STRUCT struct = new STRUCT(connection, structDescriptor, map);
...
or:
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
((OraclePreparedStatement)ps).setOracleObject(1, mySTRUCT);
When you enable auto-buffering, the oracle.sql.STRUCT object keeps a local copy
of all the converted attributes. This data is retained so that subsequent access of this
information does not require going through the data format conversion process.
You must also provide a way to create and populate instances of the custom object
class from the Oracle object and its attribute data. The driver must be able to read from
a custom object class and write to it. In addition, the custom object class can provide
getXXX and setXXX methods corresponding to the attributes of the Oracle object,
although this is not necessary. To create and populate the custom classes and provide
these read/write capabilities, you can choose between the following interfaces:
■ The JDBC standard SQLData interface
■ The ORAData and ORADataFactory interfaces provided by Oracle
The custom object class you create must implement one of these interfaces. The
ORAData interface can also be used to implement the custom reference class
corresponding to the custom object class. However, if you are using the SQLData
interface, then you can use only weak reference types in Java, such as java.sql.Ref
or oracle.sql.REF. The SQLData interface is for mapping SQL objects only.
As an example, assume you have an Oracle object type, EMPLOYEE, in the database
that consists of two attributes: Name, which is of the CHAR type and EmpNum, which is
of the NUMBER type. You use the type map to specify that the EMPLOYEE object should
map to a custom object class that you call JEmployee. You can implement either the
SQLData or ORAData interface in the JEmployee class.
You can create custom object classes yourself, but the most convenient way to create
them is to use the Oracle JPublisher utility to create them for you. JPublisher supports
the standard SQLData interface as well as the Oracle-specific ORAData interface, and
is able to generate classes that implement either one.
Advantages of ORAData
The advantages of ORAData are:
■ It does not require an entry in the type map for the Oracle object.
■ It has awareness of Oracle extensions.
■ You can construct an ORAData from an oracle.sql.STRUCT. This is more
efficient because it avoids unnecessary conversions to native Java types.
■ You can obtain the corresponding Datum object from the ORAData object, using
the toDatum method.
■ It provides better performance. ORAData works directly with Datum types, which
is the internal format used by the driver to hold Oracle objects.
Advantages of SQLData
SQLData is a JDBC standard that makes your code portable.
See Also: "Creating and Using Custom Object Classes for Oracle
Objects" on page 13-6
When using a SQLData implementation, if you do not include a type map entry, then
the object will map to the oracle.sql.STRUCT class by default. ORAData
implementations, by contrast, have their own mapping functionality so that a type
map entry is not required. When using an ORAData implementation, use the Oracle
getORAData method instead of the standard getObject method.
The type map relates a Java class to the SQL type name of an Oracle object. This
one-to-one mapping is stored in a hash table as a keyword-value pair. When you read
data from an Oracle object, the JDBC driver considers the type map to determine
which Java class to use to materialize the data from the Oracle object type. When you
write data to an Oracle object, the JDBC driver gets the SQL type name from the Java
class by calling the getSQLTypeName method of the SQLData interface. The actual
conversion between SQL and Java is performed by the driver.
The attributes of the Java class that corresponds to an Oracle object can use either Java
native types or Oracle native types to store attributes.
You have the option of creating your own class to accomplish this, but the standard
java.util.Hashtable class meets the requirement.
Hashtable and other classes used for type maps implement a put method that takes
keyword-value pairs as input, where each key is a fully qualified SQL type name and
the corresponding value is an instance of a specified Java class.
A type map is associated with a connection instance. The standard
java.sql.Connection interface and the Oracle-specific
oracle.jdbc.OracleConnection interface include a getTypeMap method. Both
return a Map object.
This section covers the following topics:
■ Adding Entries to an Existing Type Map
■ Creating a New Type Map
■ Materializing Object Types not Specified in the Type Map
2. Use the put method of the type map to add map entries. The put method takes
two arguments: a SQL type name string and an instance of a specified Java class
that you want to map to.
myMap.put(sqlTypeName, classObject);
The sqlTypeName is a string that represents the fully qualified name of the SQL
type in the database. The classObject is the Java class object to which you want
to map the SQL type. Get the class object with the Class.forName method, as
follows:
myMap.put(sqlTypeName, Class.forName(className));
For example, if you have a PERSON SQL data type defined in the CORPORATE
database schema, then map it to a Person Java class defined as Person with this
statement:
myMap.put("CORPORATE.PERSON", Class.forName("Person"));
The map has an entry that maps the PERSON SQL data type in the CORPORATE
database to the Person Java class.
Note: SQL type names in the type map must be all uppercase,
because that is how Oracle Database stores SQL names.
2. Use the put method of the type map object to add entries to the map. For
example, if you have an EMPLOYEE SQL type defined in the CORPORATE database,
then you can map it to an Employee class object defined by Employee.java, as
follows:
newMap.put("CORPORATE.EMPLOYEE", class.forName("Employee"));
3. When you finish adding entries to the map, use the setTypeMap method of the
OracleConnection object to overwrite the existing type map of the connection.
For example:
oraconn.setTypeMap(newMap);
The JDBC driver calls your readSQL method to read a stream of data values from the
database and populate an instance of your custom object class. Typically, the driver
would use this method as part of an OracleResultSet object getObject call.
Similarly, the JDBC driver calls your writeSQL method to write a sequence of data
values from an instance of your custom object class to a stream that can be written to
the database. Typically, the driver would use this method as part of an
OraclePreparedStatement object setObject call.
■ The readSQL method takes as input a SQLInput stream and a string that
indicates the SQL type name of the data, that is, the name of the Oracle object type,
such as EMPLOYEE.
When your Java application calls getObject, the JDBC driver creates a
SQLInput stream object and populates it with data from the database. The driver
can also determine the SQL type name of the data when it reads it from the
database. When the driver calls readSQL, it passes in these parameters.
■ For each Java data type that maps to an attribute of the Oracle object, readSQL
must call the appropriate readXXX method of the SQLInput stream that is passed
in.
For example, if you are reading EMPLOYEE objects that have an employee name as
a CHAR variable and an employee number as a NUMBER variable, then you must
have a readString call and a readInt call in your readSQL method. JDBC calls
these methods according to the order in which the attributes appear in the SQL
definition of the Oracle object type.
■ The readSQL method takes the data that the readXXX methods read and convert
and assigns them to the appropriate fields or elements of a custom object class
instance.
You must implement writeSQL as follows:
The PERSONNEL table contains one column, EMP_COL, of SQL type EMP_OBJECT.
This SQL type is defined in the type map to map to the Java class Employee.
2. Use the getObject method of your result set to populate an instance of your
custom object class with data from one row of the result set. The getObject
method returns the user-defined SQLData object because the type map contains
an entry for Employee.
if (rs.next())
Employee emp = (Employee)rs.getObject(1);
Note that if the type map did not have an entry for the object, then getObject
would return an oracle.sql.STRUCT object. Cast the output to type STRUCT,
because the getObject method signature returns the generic
java.lang.Object type.
if (rs.next())
STRUCT empstruct = (STRUCT)rs.getObject(1);
The getObject method calls readSQL, which, in turn, calls readXXX from the
SQLData interface.
Note: If you want to avoid using the defined type map, then use
the getSTRUCT method. This method always returns a STRUCT
object, even if there is a mapping entry in the type map.
3. If you have get methods in your custom object class, then use them to read data
from your object attributes. For example, if EMPLOYEE has the attributes EmpName
of type CHAR and EmpNum of type NUMBER, then provide a getEmpName method
that returns a Java String and a getEmpNum method that returns an int value.
Then call them in your Java application, as follows:
String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();
3. Use the getObject method to retrieve the employee object. The following code
assumes that there is a type map entry to map the Oracle object to the Java type
Employee:
Employee emp = (Employee)ocs.getObject(1);
This statement uses the emp object and the empname and empnumber variables
assigned in the preceding example.
2. Prepare a statement that updates an Oracle object in a row of a database table, as
appropriate, using the data provided in your Java data type object.
PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO PERSONNEL VALUES (?)");
■ It does not require a type map to specify the names of the Java custom classes you
want to create.
■ It provides better performance. ORAData works directly with Datum types, the
internal format the driver uses to hold Oracle objects.
The ORAData and ORADataFactory interfaces do the following:
■ The toDatum method of the ORAData class transforms the data into an
oracle.sql.* representation.
■ ORADataFactory specifies a create method equivalent to a constructor for
your custom object class. It creates and returns an ORAData instance. The JDBC
driver uses the create method to return an instance of the custom object class to
your Java application or applet. It takes as input an oracle.sql.Datum object
and an integer indicating the corresponding SQL type code as specified in the
OracleTypes class.
ORAData and ORADataFactory have the following definitions:
public interface ORAData
{
Datum toDatum (OracleConnection conn) throws SQLException;
}
This method takes as input the column index of the data in your result set and a
ORADataFactory instance. For example, you can implement a getORAFactory
method in your custom object class to produce the ORADataFactory instance to
input to getORAData. The type map is not required when using Java classes that
implement ORAData.
■ Use the standard getObject(index, map) method specified by the
ResultSet interface to retrieve data as instances of ORAData. In this case, you
must have an entry in the type map that identifies the factory class to be used for
the given object type and its corresponding SQL type name.
You can insert object data in one of the following ways:
■ Use the following setORAData method of the Oracle-specific
OraclePreparedStatement class:
ops.setORAData (int bind_index, ORAData custom_obj);
This method takes as input the parameter index of the bind variable and the name
of the object containing the variable.
■ Use the standard setObject method specified by the PreparedStatement
interface. You can also use this method, in its different forms, to insert ORAData
instances without requiring a type map.
The following sections describe the getORAData and setORAData methods.
To continue the example of an Oracle object EMPLOYEE, you might have something
like the following in your Java application:
ORAData datum = ors.getORAData(1, Employee.getORAFactory());
Note:
■ ORAData and ORADataFactory are defined as separate
interfaces so that different Java classes can implement them if
you wish.
■ To use the ORAData interface, your custom object classes must
import oracle.sql.*.
or:
if (ors.next())
ORAData datum = ors.getORAData(1, Employee.getORAFactory());
This example assumes that Employee is the name of your custom object class and
ors is the name of your OracleResultSet object.
In case you do not want to use getORAData, the JDBC drivers let you use the
getObject method of a standard JDBC ResultSet to retrieve ORAData data.
However, you must have an entry in the type map that identifies the factory class
to be used for the given object type and its corresponding SQL type name.
For example, if the SQL type name for your object is EMPLOYEE, then the
corresponding Java class is Employee, which will implement ORAData. The
corresponding Factory class is EmployeeFactory, which will implement
ORADataFactory.
Use this statement to declare the EmployeeFactory entry for your type map:
map.put ("EMPLOYEE", Class.forName ("EmployeeFactory"));
Then use the form of getObject where you specify the map object:
Employee emp = (Employee) rs.getObject (1, map);
If the default type map of the connection already has an entry that identifies the
factory class to be used for the given object type and its corresponding SQL type
name, then you can use this form of getObject:
Employee emp = (Employee) rs.getObject (1);
3. If you have get methods in your custom object class, then use them to read data
from your object attributes into Java variables in your application. For example, if
EMPLOYEE has EmpName of type CHAR and EmpNum of type NUMBER, provide a
getEmpName method that returns a Java String and a getEmpNum method that
returns an integer. Then call them in your Java application as follows:
String empname = emp.getEmpName();
int empnumber = emp.getEmpNum();
Note: The type map is not used when you are performing
database INSERT and UPDATE operations.
1. If you have set methods in your custom object class, then use them to write data
from Java variables in your application to attributes of your Java data type object.
emp.setEmpName(empname);
emp.setEmpNum(empnumber);
The setORAData method calls the toDatum method of the custom object class
instance to retrieve an oracle.sql.STRUCT object that can be written to the
database.
In this step you could also use the setObject method to bind the Java data type.
For example:
opstmt.setObject(1,emp);
Note: You can use your Java data type objects as either IN or OUT
bind variables.
■ Customizing data representation, for example, data in a table column is in feet but
you want it represented in meters after it is selected
■ Serializing and deserializing Java objects
For example, use ORAData to store instances of Java objects that do not correspond to
a particular SQL object type in the database in columns of SQL type RAW. The create
method in ORADataFactory would have to implement a conversion from an object
of type oracle.sql.RAW to the desired Java object. The toDatum method in
ORAData would have to implement a conversion from the Java object to an
oracle.sql.RAW object. This can be done, for example, by using Java serialization.
Upon retrieval, the JDBC driver transparently retrieves the raw bytes of data in the
form of an oracle.sql.RAW and calls the create method of ORADataFactory to
convert the oracle.sql.RAW object to the desired Java class.
When you insert the Java object into the database, you can simply bind it to a column
of type RAW to store it. The driver transparently calls the ORAData.toDatum method to
convert the Java object to an oracle.sql.RAW object. This object is then stored in a
column of type RAW in the database.
Support for the ORAData interfaces is also highly efficient because the conversions are
designed to work using oracle.sql.* formats, which happen to be the internal
formats used by the JDBC drivers. Moreover, the type map, which is necessary for the
SQLData interface, is not required when using Java classes that implement ORAData.
Object-Type Inheritance
Object-type inheritance allows a new object type to be created by extending another
object type. The new object type is then a subtype of the object type from which it
extends. The subtype automatically inherits all the attributes and methods defined in
the supertype. The subtype can add attributes and methods and overload or override
methods inherited from the supertype.
Object-type inheritance introduces substitutability. Substitutability is the ability of a
slot declared to hold a value of type T in addition to any subtype of type T. Oracle
JDBC drivers handle substitutability transparently.
A database object is returned with its most specific type without losing information.
For example, if the STUDENT_T object is stored in a PERSON_T slot, Oracle JDBC
driver returns a Java object that represents the STUDENT_T object.
This section covers the following topics:
■ Creating Subtypes
■ Implementing Customized Classes for Subtypes
■ Retrieving Subtype Objects
■ Creating Subtype Objects
Creating Subtypes
Create custom object classes if you want to have Java classes that explicitly correspond
to the Oracle object types. If you have a hierarchy of object types, you may want a
corresponding hierarchy of Java classes.
The most common way to create a database subtype in JDBC is to run a SQL CREATE
TYPE command using the execute method of the java.sql.Statement interface.
For example, you want to create a type inheritance hierarchy for:
PERSON_T
|
STUDENT_T
|
PARTTIMESTUDENT_T
In the following code, the foo member procedure in type ST is overloaded and the
member procedure print overwrites the copy it inherits from type T.
CREATE TYPE T AS OBJECT (...,
MEMBER PROCEDURE foo(x NUMBER),
MEMBER PROCEDURE Print(),
...
NOT FINAL;
Once the subtypes have been created, they can be used as both columns of a base table
as well as attributes of a object type.
public Person () {}
public Student () {}
Customized classes that implement the ORAData interface do not have to mirror the
database object type hierarchy. For example, you could have declared the Student
class without a superclass. In this case, Student would contain fields to hold the
inherited attributes from PERSON_T as well as the attributes declared by STUDENT_T.
ORADataFactory Implementation
The JDBC application uses the factory class in querying the database to return
instances of Person or its subclasses, as in the following example:
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
public Person () {}
case, Student would contain fields to hold the inherited attributes from PERSON_T as
well as the attributes declared by STUDENT_T.
public Student () {}
JPublisher Utility
Even though you can manually create customized classes that implement the
SQLData, ORAData, and ORADataFactory interfaces, it is recommended that you
use Oracle JPublisher to automatically generate these classes. The customized classes
generated by Oracle JPublisher that implement the SQLData, ORAData, and
ORADataFactory interfaces, can mirror the inheritance hierarchy.
See Also:
■ "Using JPublisher to Create Custom Object Classes" on page 13-30
■ Oracle Database JPublisher User's Guide
if (s != null)
{
if (s instanceof Person)
System.out.println ("This is a Person");
else if (s instanceof Student)
System.out.println ("This is a Student");
else if (s instanceof ParttimeStudent)
System.out.pritnln ("This is a PartimeStudent");
else
System.out.println ("Unknown type");
}
}
The JDBC drivers check the connection type map for each call to the following:
■ getObject method of the java.sql.ResultSet and
java.sql.CallableStatement interfaces
■ getAttribute method of the java.sql.Struct interface
■ getArray method of the java.sql.Array interface
■ getValue method of the oracle.sql.REF interface
{
if (s instanceof Person)
System.out.println ("This is a Person");
else if (s instanceof Student)
System.out.println ("This is a Student");
else if (s instanceof ParttimeStudent)
System.out.pritnln ("This is a PartimeStudent");
else
System.out.println ("Unknown type");
}
}
s is initialized with data fields inherited from PERSON_T and STUDENT_T, and data
fields defined in PARTTIMESTUDENT_T.
if (sqlname.equals ("SCOTT.PERSON")
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
}
else if (sqlname.equals ("SCOTT.STUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
}
else if (sqlname.equals ("SCOTT.PARTTIMESTUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
System.out.println ("numHours="+((BigDecimal)attrs[5]).intValue());
}
else
throw new Exception ("Invalid type name: "+sqlname);
}
}
rset.close ();
stmt.close ();
conn.close ();
JPublisher Functionality
You can direct JPublisher to create custom object classes that implement either the
SQLData interface or the ORAData interface, according to how you set the JPublisher
type mappings.
If you use the ORAData interface, then JPublisher will also create a custom reference
class to map to object references for the Oracle object type. If you use the SQLData
interface, then JPublisher will not produce a custom reference class. You would use
standard java.sql.Ref instances instead.
If you want additional functionality, you can subclass the custom object class and add
features as desired. When you run JPublisher, there is a command-line option for
specifying both a generated class name and the name of the subclass you will
implement. For the SQL-Java mapping to work properly, JPublisher must know the
subclass name, which is incorporated into some of the functionality of the generated
class.
Type-Mapping Modes
JPublisher defines the following type-mapping modes, two of which apply to numeric
types only:
■ JDBC mapping (setting jdbc)
Uses standard default mappings between SQL types and Java native types. For a
custom object class, uses a SQLData implementation.
■ Oracle mapping (setting oracle)
Uses corresponding oracle.sql types to map to SQL types. For a custom object,
reference, or collection class, uses a ORAData implementation.
■ Object-JDBC mapping (setting objectjdbc)
Is an extension of the JDBC mapping. Where relevant, object-JDBC mapping uses
numeric object types from the standard java.lang package, such as
Table 13–1 JPublisher SQL Type Categories, Supported Settings, and Defaults
SQL Type JPublisher
Category Mapping Option Mapping Settings Default
UDT types -usertypes oracle, jdbc oracle
numeric types -numbertypes oracle, jdbc, objectjdbc, bigdecimal objectjdbc
LOB types -lobtypes oracle, jdbc oracle
built-in types -builtintypes oracle, jdbc jdbc
This method returns the fully qualified name of the oracle.sql.Datum subclass
whose instances are manufactured if the OracleResultSet class
getOracleObject method is called to retrieve the value of the specified attribute.
For example, oracle.sql.NUMBER.
To use the getOracleColumnClassName method, you must cast the
ResultSetMetaData object, which that was returned by the getMetaData method,
to StructMetaData.
Example
The following method shows how to retrieve information about the attributes of a
structured object type. This includes the initial step of creating a StructDescriptor
instance.
//
// Print out the ADT's attribute names and types
//
void getAttributeInfo (Connection conn, String type_name) throws SQLException
{
// get the type descriptor
StructDescriptor desc = StructDescriptor.createDescriptor (type_name, conn);
// temporary buffers
String attr_name;
int attr_type;
String attr_typeName;
This chapter describes how to use Java Database Connectivity (JDBC) and the
oracle.sql.* classes to access and manipulate large object (LOB) and binary file
(BFILE) locators and data. This chapter contains the following sections:
■ Oracle Extensions for LOBs and BFILEs
■ Working with BLOBs, CLOBs and NCLOBs
■ Data Interface for LOBs
■ Working With Temporary LOBs
■ Using Open and Close With LOBs
■ Working with BFILEs
■ Oracle SecureFiles
Notes:
■ In Oracle Database 11g, the Oracle JDBC drivers support the
JDBC 4.0 java.sql.NClob interface.
■ In Oracle Database 10g, the Oracle JDBC drivers support the
JDBC 3.0 java.sql.Clob and java.sql.Blob interfaces.
Certain Oracle extensions made in oracle.sql.CLOB and
oracle.sql.BLOB in earlier Oracle Database releases are no
longer necessary and are deprecated. You should port your
application to the standard JDBC 3.0 interface.
■ Prior to Oracle Database 10g, the maximum size of a LOB was
232 bytes. This restriction has been removed since Oracle
Database 10g, and the maximum size is limited to the size of
available physical storage. The Java LOB application
programming interface (API) has not changed.
BFILEs are large binary data objects stored in operating system files outside of
database tablespaces. These files use reference semantics. They can also be located on
tertiary storage devices, such as hard disks, CD-ROMs, PhotoCDs, and DVDs. As with
BLOB, CLOB, and NCLOBs, a BFILE is accessed and referenced by a locator which is
stored in the database table and points to the BFILE data.
To work with LOB data, you must first obtain a LOB locator. Then you can read or
write LOB data and perform data manipulation.
The JDBC drivers support the following oracle.sql.* classes for BLOBs, CLOBs,
NCLOBs, and BFILEs:
■ oracle.sql.BLOB
■ oracle.sql.CLOB
■ oracle.sql.NCLOB
■ oracle.sql.BFILE
The oracle.sql.BLOB, oracle.sql.CLOB, and oracle.sql.NCLOB classes
implement the java.sql.Blob, java.sql.Clob, and java.sql.NClob interfaces,
respectively. In contrast, BFILE is an Oracle extension, without a corresponding
java.sql interface.
Instances of these classes contain only the locators for these data types, not the data.
After accessing the locators, you must perform some additional steps to access the
data.
Note: If you want to create a new LOB, then use the factory
methods from oracle.jdbc.OracleConnection interface.
If you retrieve or cast the result set or the callable statement to OracleResultSet or
OracleCallableStatement, then you can use Oracle extensions, as follows:
■ You can use getBLOB, getCLOB, and getNCLOB, which return
oracle.sql.BLOB, CLOB, and NCLOB objects, respectively.
■ You can also use the getOracleObject method, which returns an
oracle.sql.Datum object, and cast the output appropriately.
Example: Getting BLOB, CLOB, and NCLOB Locators from a Result Set
Assume the database has a table called lob_table with a column for a BLOB locator,
blob_col, a column for a CLOB locator, clob_col, and a column for a NCLOB
locator, nclob_col. This example assumes that you have already created the
Statement object, stmt.
First, select the LOB locators into a standard result set, then get the LOB data into
appropriate Java classes:
// Select LOB locator into standard result set.
ResultSet rs =
stmt.executeQuery ("SELECT blob_col, clob_col, nclob_col FROM lob_table");
while (rs.next())
{
// Get LOB locators into Java container classes.
java.sql.Blob blob = (java.sql.Blob)rs.getObject(1);
java.sql.Clob clob = (java.sql.Clob)rs.getObject(2);
java.sql.NClob nclob = (java.sql.NClob)rs.getObject(3);
(...process...)
}
ocs.registerOutParameter(1, OracleTypes.CLOB);
ocs.execute();
oracle.sql.CLOB clob = ocs.getCLOB(1);
To read and write LOB data, you can use these methods:
■ To read from a BLOB, use the getBinaryStream method of an java.sql.BLOB
object to retrieve the entire BLOB as an input stream. This returns a
java.io.InputStream object.
As with any InputStream object, use one of the overloaded read methods to
read the LOB data and use the close method when you finish.
■ To write to a BLOB, use the setBinaryStream method of an java.sql.BLOB
object to retrieve the BLOB as an output stream. This returns a
java.io.OutputStream object to be written back to the BLOB.
As with any OutputStream object, use one of the overloaded write methods to
update the LOB data and use the close method when you finish.
■ To read from a CLOB, use the getAsciiStream or getCharacterStream
method of an java.sql.CLOB object to retrieve the entire CLOB as an input
stream. The getAsciiStream method returns an ASCII input stream in a
java.io.InputStream object. The getCharacterStream method returns a
Unicode input stream in a java.io.Reader object.
As with any InputStream or Reader object, use one of the overloaded read
methods to read the LOB data and use the close method when you finish.
You can also use the getSubString method of java.sql.CLOB object to
retrieve a subset of the CLOB as a character string of type java.lang.String.
■ To write to a CLOB, use the setAsciiStream or setCharacterStream
method of an java.sql.CLOB object to retrieve the CLOB as an output stream to
be written back to the CLOB. The setAsciiStream method returns an ASCII
output stream in a java.io.OutputStream object. The setCharacterStream
method returns a Unicode output stream in a java.io.Writer object.
As with any Stream or Writer object, use one of the overloaded write methods
to update the LOB data and use the flush and close methods when you finish.
■ To read from an NCLOB, use the getAsciiStream or getCharacterStream
method of an java.sql.NCLOB object to retrieve the entire NCLOB as an input
stream. The getAsciiStream method returns an ASCII input stream in a
java.io.InputStream object. The getCharacterStream method returns a
Unicode input stream in a java.io.Reader object.
As with any InputStream or Reader object, use one of the overloaded read
methods to read the LOB data and use the close method when you finish.
Notes:
■ The stream write methods described in this section write
directly to the database when you write to the output stream.
You do not need to run an UPDATE to write the data. However,
you need to call close or flush to ensure all changes are
written. CLOBs and BLOBs are transaction controlled. After
writing to either, you must commit the transaction for the
changes to be permanent. BFILEs are not transaction controlled.
Once you write to them the changes are permanent, even if the
transaction is rolled back, unless the external file system does
something else.
■ When writing to or reading from a CLOB or an NCLOB, the
JDBC drivers perform all character set conversions for you.
■ When reading a LOB using any of the getXXX methods
described in the section, the returned stream fetches blocks of
data from the database needed. The entire LOB is not fetched
all at once, which makes it practical to read very large LOBs.
...
The next example reads a vector of data into a byte array, then uses the
setAsciiStream method to write the array of ASCII data to a CLOB.
java.io.OutputStream out;
The next example reads a vector of data into a byte array, then uses the
setAsciiStream method to write the array of ASCII data to an NCLOB.
java.io.OutputStream out;
Create a BLOB, CLOB, or NCLOB column in a table with the SQL CREATE TABLE
statement, then populate the LOB. This includes creating the LOB entry in the table,
obtaining the LOB locator, and then copying the data into the LOB.
In this example, the VARCHAR2 column designates a row number, such as 1 or 2, and
the BLOB column stores the locator of the BLOB data.
3. Declare a file handler for the john.gif file, then print the length of the file. This
value will be used later to ensure that the entire file is read into the BLOB. Next,
create a FileInputStream object to read the contents of the file, and an
OutputStream object to retrieve the BLOB as a stream.
File binaryFile = new File("john.gif");
System.out.println("john.gif length = " + binaryFile.length());
FileInputStream instream = new FileInputStream(binaryFile);
OutputStream outstream = blob.setBinaryStream(1L);
4. Call getBufferSize to retrieve the ideal buffer size to use in writing to the
BLOB, then create the buffer byte array.
int size = blob.getBufferSize();
byte[] buffer = new byte[size];
int length = -1;
5. Use the read method to read the file to the byte array buffer, then use the
write method to write it to the BLOB. When you finish, close the input and
output streams and commit the changes.
while ((length = instream.read(buffer)) != -1)
outstream.write(buffer, 0, length);
instream.close();
outstream.close();
conn.commit();
Once your data is in the BLOB, CLOB, or NCLOB, you can manipulate the data.
Input
In Oracle Database 11g release 1 (11.1), the setBytes, setBinaryStream,
setString, setCharacterStream, and setAsciiStream methods of
PreparedStatement are extended for BLOB and CLOB parameters.
For the JDBC Oracle Call Interface (OCI) and Thin drivers there is no limitation on the
size of the byte array or String and no limit on the length specified for the stream
functions except the limits imposed by the Java language, which is that array sizes are
limited to positive Java int or 2147483648 elements.
For the server-side internal driver there is currently a limitation of 4000 bytes for
operations on SQL statements, such as an INSERT statement. The limitation does not
apply for PL/SQL statements. There is a simple workaround for an INSERT statement,
which is to wrap it in a PL/SQL block, as follows:
BEGIN
INSERT id, c INTO clob_tab VALUES(?,?);
END;
You must bear in mind the following automatic switching of the input mode for large
data:
■ For SQL statements:
– setBytes switches to setBinaryStream for data larger than 2000 bytes
– setString switches to setCharacterStream for data larger than 32766
characters
■ PL/SQL statements
– setBytes switches to setBinaryStream for data larger than 2000 bytes
and to setBytesForBlob for data larger that 32766 bytes
– setString switches to setStringForClob for string data larger than 32766
bytes in the database character set
– setNClob or setObject is used for large national character set type data. If
the setObject method is used , the target data type must be specified as
Types.NCHAR, Types.NCLOB, Types.NVARCHAR, or
Types.LONGNVARCHAR.
This will have impact on some programs, which formerly got ORA-17157 errors for
attempts to use setString for String values larger than 32766 characters. Now,
depending on the type of the target parameter an error may occur while the
application is executed or the operation may succeed.
Another impact is that the automatic switching may result in additional server-side
parsing to adapt to the change in the parameter type. This would result in a
performance effect if the data sizes vary above and below the limit for repeated
executions of the statement. Switching to the stream modes will effect batching as
well.
Oracle Database 10g release 1 (10.1) has the SetBigStringTryClob connection
property. Setting this property causes the standard setString method to switch to
setStringForClob method for large data. This property is no longer used or
needed. The setBytesForBlob and setStringForClob methods create temporary
LOBs, which are automatically freed when the statement is executed or closed before
execution.
However, when a PL/SQL procedure or function is embedded in a SQL statement,
data less than 4 KB is bound as String, which is the standard. When data is greater
than 4KB, the driver binds the data as a String as for any SQL statement. This will
throw an error. The workaround is to use setClob or setCharacterStream
instead of setString or setStringForClob. You can also create a callable
statement.
Output
The getBytes, getBinaryStream, getSting, getCharacterStream, and
getAsciiStream methods of ResultSet and CallableStatement are extended
to work with BLOB, CLOB, and BFILE columns or OUT parameters. These methods will
work for any LOB of length less than 2147483648. This operates entirely on the
client-side and will work with any supported version of the database, that is, Oracle
Database 8.1.7 and later.
BLOB, BFILE, or CLOB data can be read and written using the same streaming
mechanism as for LONG RAW and LONG data. To read, use defineColumnType(nn,
Types.LONGVARBINARY) or defineColumnType(nn,Types.LONGVARCHAR) on
the column. This produces a direct stream on the data as if it were a LONG RAW or
LONG column. This technique is limited to Oracle Database 10g release 1 (10.1) and
later.
Another workaround is to use a container block to make the call. The clob_proc
procedure can be wrapped with a Java string to use for the prepareCall statement,
as follows:
"DECLARE c_temp; BEGIN c_temp := ?; clob_proc( c_temp); ? := c_temp; END;"
In either case you may use setString on the first parameter and
registerOutParameter with Types.CLOB on the second.
Size Limitations
Please be aware of the effect on the performance of the Java memory management
system due to creation of very large byte array or String. Please read the
information provided by your Java virtual machine (JVM) vendor about the impact of
very large data elements on memory management, and consider using the stream
interfaces instead.
Notes:
■ Failure to free a temporary LOB will result in the storage used
by that LOB in the database being unavailable. Frequent failure
to free temporary LOBs will result in filling up temporary table
space with unavailable LOB storage.
■ When fetching data from a ReultSet with columns that are
temporary LOBs, use getClob or getBlob instead of
getString or getBytes. Also invoke freeTemporary to
free the temporary LOBs.
The form argument specifies whether the created LOB is a CLOB or an NCLOB. If
form equals oracle.jdbc.OraclePreparedStatement.FORM_NCHAR, then the
method creates an NCLOB. If form equals
Notes:
■ In the OracleResultSet and OracleCallableStatement
classes, getBFILE and getBfile both return
oracle.sql.BFILE. There is no java.sql interface for
BFILEs.
■ If using getObject or getOracleObject, remember to cast
the output, as necessary.
Note that as an alternative, you can use getObject to return the BFILE locator. In this
case, because getObject returns a java.lang.Object, cast the results to BFILE.
For example:
oracle.sql.BFILE my_bfile = (BFILE)rs.getObject(1);
Notes:
■ BFILEs are read-only. They reside in the OS (operating system)
File System and can be written to only using OS tools and
commands.
■ You can create a BFILE. However, you cannot create an OS file
that a BFILE would refer to. Those are created only externally.
Use the SQL CREATE TABLE statement to create a table containing a BFILE column. In
this example, the name of the table is my_bfile_table.
// Create a table containing a BFILE field
cmd = "CREATE TABLE my_bfile_table (x varchar2 (30), b bfile)";
stmt.execute (cmd);
In this example, the VARCHAR2 column designates a row number and the BFILE
column stores the locator of the BFILE data.
'jdbcTest.data'))";
stmt.execute (cmd);
In this example, the name of the directory alias is test_dir. The locator of the BFILE
file1.data is loaded into the BFILE column on row one, and the locator of the
BFILE jdbcTest.data is loaded into the bfile column on row two.
As an alternative, you may want to create the row for the row number and BFILE
locator now, but wait until later to insert the locator. In this case, insert the row
number into the table and null as a place holder for the BFILE locator.
cmd ="INSERT INTO my_bfile_table VALUES ('three', null)";
stmt.execute(cmd);
Here, three is inserted into the row number column and null is inserted as the place
holder. Later in your program, insert the BFILE locator into the table by using a
prepared statement.
First get a valid BFILE locator into the bfile object:
rs = stmt.executeQuery("SELECT b FROM my_bfile_table WHERE x='two'");
rs.next();
oracle.sql.BFILE bfile = ((OracleResultSet)rs).getBFILE(1);
Then, create your prepared statement. Note that because this example uses the
setBFILE method to identify the BFILE, the prepared statement must be cast to
OraclePreparedStatement:
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement
(UPDATE my_bfile_table SET b=? WHERE x = 'three');
ops.setBFILE(1, bfile);
ops.execute();
Now row two and row three contain the same BFILE.
Once you have the BFILE locators available in a table, you can access and manipulate
the BFILE data.
if (rset.next ())
BFILE bfile = ((OracleResultSet)rset).getBFILE (2);
Oracle SecureFiles
In Oracle Database 11g Release 1 (11.1), Oracle SecureFiles, a completely redesigned
storage for LOBs, provide the following capabilities:
■ SecureFile compression enables users to compress data to save disk space.
■ SecureFile encryption introduces a new encryption facility that allows for random
reads and writes of the encrypted data.
■ Deduplication enables Oracle database to automatically detect duplicate LOB data
and conserve space by storing only one copy of data.
■ LOB data path optimization includes logical cache above storage layer, read
prefetching, new caching modes, and vectored IO.
■ High performance space management.
These features are implemented in the database and are transparenly available to
JDBC programs through the existing APIs.
The new setLobOptions and getLobOptions APIs are described in the PL/SQL
Packages and Types Reference, and may be accessed from JDBC through callable
statements.
Note:
■ If you are using the oracle.sql.ORAData interface for
custom object classes, then you will presumably use ORAData
for corresponding custom reference classes as well. However, if
you are using the standard java.sql.SQLData interface for
custom object classes, then you can only use weak Java types
for references. The SQLData interface is for mapping SQL
object types only.
■ You can create and retrieve REF objects in your JDBC
application only by running SQL statements. There is no
JDBC-specific functionality for creating and retrieving REF
objects.
■ You cannot have a reference to an array, even though arrays,
like objects, are structured types.
Retrieves the fully qualified SQL structured type name of the referenced object.
This is a standard method specified by the java.sql.Ref interface.
■ getValue
Retrieves the referenced object from the database, enabling you to access its
attribute values. It optionally takes a type map object. You can use the default type
map of the database connection object. This method is an Oracle extension.
■ setValue
Sets the referenced object in the database, allowing you to update its attribute
values. It takes an instance of the object type, either a STRUCT instance or an
instance of a custom object class, as input. This method is an Oracle extension.
The ADDRESS object type has two attributes: a street name and a house number. The
PEOPLE table has three columns: a column for character data, a column for numeric
data, and a column containing a reference to an ADDRESS object.
To retrieve an object reference, follow these general steps:
1. Use a standard SQL SELECT statement to retrieve the reference from a database
table REF column.
2. Use getREF to get the address reference from the result set into a REF object.
3. Let Address be the Java custom class corresponding to the SQL object type
ADDRESS.
4. Add the correspondence between the Java class Address and the SQL type
ADDRESS to your type map.
5. Use the getValue method to retrieve the contents of the Address reference. Cast
the output to Address.
The PEOPLE database table is defined earlier in this section. The code for the preceding
steps, except the step of adding Address to the type map, is as follows:
ResultSet rs = stmt.executeQuery("SELECT col3 FROM PEOPLE");
while (rs.next())
{
REF ref = ((OracleResultSet)rs).getREF(1);
Address a = (Address)
ref.getValue();
}
As with other SQL types, you could retrieve the reference with the getObject
method of your result set. Note that this would require you to cast the output. For
example:
REF ref = (REF)rs.getObject(1);
param_index is the parameter index and sql_type is the SQL type code. The
sql_type_name is the name of the structured object type that this reference is
used for. For example, if the OUT parameter is a reference to an ADDRESS object,
then ADDRESS is the sql_type_name that should be passed in.
3. Run the call, as follows:
ocs.execute();
Then, you can create a Java Address object that corresponds to the database ADDRESS
object. Use the setValue method of the REF class to set the value of the database
object, as follows:
Address addr = new Address(...);
ref.setValue(addr);
Here, the setValue method updates the database ADDRESS object immediately.
Be aware that the standard SQLData interface supports only SQL object mappings.
For this reason, if you instruct JPublisher to implement the standard SQLData
interface in creating a custom object class, then JPublisher will not generate a custom
reference class. In this case, your only option is to use standard java.sql.Ref
instances or oracle.sql.REF instances to map to your object references.
See Also:
■ "Using JPublisher to Create Custom Object Classes" on page 13-30
■ Oracle Database JPublisher User's Guide
See Also: For more information about custom collection classes, see
"Custom Collection Classes with JPublisher" on page 16-13.
Creating Collections
Because Oracle supports only named collections, you must declare a particular
VARRAY type name or nested table type name. VARRAY and nested table are not types
themselves, but categories of types.
A SQL type name is assigned to a collection when you create it using the SQL CREATE
TYPE statement:
CREATE TYPE <sql_type_name> AS <datatype>;
A VARRAY is an array of varying size. It has an ordered set of data elements, and all
the elements are of the same data type. Each element has an index, which is a number
corresponding to the position of the element in the VARRAY. The number of elements
in a VARRAY is the size of the VARRAY. You must specify a maximum size when you
declare the VARRAY type. For example:
CREATE TYPE myNumType AS VARRAY(10) OF NUMBER;
This statement defines myNumType as a SQL type name that describes a VARRAY of
NUMBER values that can contain no more than 10 elements.
A nested table is an unordered set of data elements, all of the same data type. The
database stores a nested table in a separate table which has a single column, and the
type of that column is a built-in type or an object type. If the table is an object type,
then it can also be viewed as a multi-column table, with a column for each attribute of
the object type. You can create a nested table as follows:
CREATE TYPE myNumList AS TABLE OF integer;
This statement identifies myNumList as a SQL type name that defines the table type
used for the nested tables of the type INTEGER.
Once the multilevel collection types have been created, they can be used as both
columns of a base table as well as attributes of a object type.
Each method using the first signature returns collection elements as an XXX[], where
XXX is a Java primitive type. Each method using the second signature returns a slice of
the collection containing the number of elements specified by count, starting at the
index location.
When you enable auto-buffering, the oracle.sql.ARRAY object keeps a local copy of
all the converted elements. This data is retained so that a second access of this
information does not require going through the data format conversion process.
Note: Oracle JDBC does not support the JDBC 4.0 method
createArrayOf method of java.sql.Connection interface. This
method only allows anonymous array types, while all Oracle array
types are named. Use the Oracle specific method createArray of
oracle.jdbc.OracleConnection instead.
This section describes how to create ARRAY objects. This section covers the following
topics:
■ Steps in Creating ARRAY Objects
■ Creating Multilevel Collections
where, typeName is the name of the SQL type of the created object and elements is
the elements of the created object.
Perform the following to create an array:
1. Create a collection with the CREATE TYPE statement as follows:
CREATE TYPE elements AS varray(22) OF NUMBER(5,2);
getOracleArray
The getOracleArray method is an Oracle-specific extension that is not specified in
the standard Array interface. The getOracleArray method retrieves the element
values of the array into a Datum[] array. The elements are of the oracle.sql.* data
type corresponding to the SQL type of the data in the original array.
For an array of structured objects, this method will use oracle.sql.STRUCT
instances for the elements.
Oracle also provides a getOracleArray(index,count) method to get a subset of
the array elements.
getResultSet
The getResultSet method returns a result set that contains elements of the array
designated by the ARRAY object. The result set contains one row for each array
element, with two columns in each row. The first column stores the index into the
array for that element, and the second column stores the element value. In the case of
VARRAYs, the index represents the position of the element in the array. In the case of
nested tables, which are by definition unordered, the index reflects only the return
order of the elements in the particular query.
Oracle recommends using getResultSet when getting data from nested tables.
Nested tables can have an unlimited number of elements. The ResultSet object
returned by the method initially points at the first row of data. You get the contents of
the nested table by using the next method and the appropriate getXXX method. In
contrast, getArray returns the entire contents of the nested table at one time.
The getResultSet method uses the default type map of the connection to determine
the mapping between the SQL type of the Oracle object and its corresponding Java
data type. If you do not want to use the default type map of the connection, another
version of the method, getResultSet(map), enables you to specify an alternate type
map.
Oracle also provides the getResultSet(index,count) and
getResultSet(index,count,map) methods to retrieve a subset of the array
elements.
getArray
The getArray method is a standard JDBC method that returns the array elements as a
java.lang.Object, which you can cast as appropriate. The elements are converted
to the Java types corresponding to the SQL type of the data in the original array.
Oracle also provides a getArray(index,count) method to retrieve a subset of the
array elements.
If you use getResultSet to return an array of primitive data types, then the JDBC
driver returns a ResultSet object that contains, for each element, the index into the
array for the element and the element value. For example:
ResultSet rset = intArray.getResultSet();
In this case, the result set contains one row for each array element, with two columns
in each row. The first column stores the index into the array and the second column
stores the element value.
If the elements of an array are of a SQL type that maps to a Java type, then getArray
returns an array of elements of this Java type. The return type of the getArray
method is java.lang.Object. Therefore, the result must be cast before it can be
used.
BigDecimal[] values = (BigDecimal[]) intArray.getArray();
See Also: "Using a Type Map to Map Array Elements" on page 16-12
where in the array you want to start and how many elements you want to retrieve. As
previously described, you can specify a type map or use the default type map for your
connection to convert to Java types. For example:
Object object = arr.getArray(index, count, map);
Object object = arr.getArray(index, count);
Where arr is an oracle.sql.ARRAY object, index is type long, count is type int,
and map is a java.util.Map object.
Note that if you use getResultSet to obtain the array, then you must would first get
the result set object, and then use the next method to iterate through it. Notice the use
of the parameter indexes in the getInt method to retrieve the element index and the
element value.
ResultSet rset = my_array.getResultSet();
while (rset.next())
{
// The first column contains the element index and the
// second column contains the element value
System.out.println(">> index " + rset.getInt(1)+" = " + rset.getInt(2));
}
while (rset.next())
{
ARRAY varray3 = (ARRAY) rset.getObject (1);
while (varray1Elems.next())
System.out.println ("idx="+varray1Elems.getInt(1)+"
value="+varray1Elems.getInt(2));
}
}
}
rset.close ();
stmt.close ();
conn.close ();
1. Define the array that you want to pass to the prepared statement as an
oracle.sql.ARRAY object.
ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name,
elements);
param_index is the parameter index, sql_type is the SQL type code, and
sql_type_name is the name of the array type. In this case, the sql_type is
OracleTypes.ARRAY.
3. Run the call, as follows:
ocs.execute();
If you want to retrieve all the employees belonging to the SALES department into an
array of instances of the custom object class EmployeeObj, then you must add an
entry to the type map to specify mapping between the EMPLOYEE SQL type and the
EmployeeObj custom object class.
To do this, first create your statement and result set objects, then select the
EMPLOYEE_LIST associated with the SALES department into the result set. Cast the
result set to OracleResultSet so you can use the getARRAY method to retrieve the
EMPLOYEE_LIST into an ARRAY object (employeeArray in the following example).
The EmployeeObj custom object class in this example implements the SQLData
interface.
Statement s = conn.createStatement();
OracleResultSet rs = (OracleResultSet)s.executeQuery
("SELECT Employees FROM employee_table WHERE DeptName = 'SALES'");
Now that you have the EMPLOYEE_LIST object, get the existing type map and add an
entry that maps the EMPLOYEE SQL type to the EmployeeObj Java type.
// add type map entry to map SQL type
// "EMPLOYEE" to Java type "EmployeeObj"
Map map = conn.getTypeMap();
map.put("EMPLOYEE", Class.forName("EmployeeObj"));
Next, retrieve the SQL EMPLOYEE objects from the EMPLOYEE_LIST. To do this, call
the getArray method of the employeeArray array object. This method returns an
array of objects. The getArray method returns the EMPLOYEE objects into the
employees object array.
// Retrieve array elements
Object[] employees = (Object[]) employeeArray.getArray();
Finally, create a loop to assign each of the EMPLOYEE SQL objects to the
EmployeeObj Java object emp.
// Each array element is mapped to EmployeeObj object.
for (int i=0; i<employees.length; i++)
{
EmployeeObj emp = (EmployeeObj) employees[i];
...
}
See Also:
■ "Using JPublisher to Create Custom Object Classes" on page 13-30
■ Oracle Database JPublisher User's Guide
Standard Java Database Connectivity (JDBC) 2.0 features in Java Development Kit
(JDK) 1.2.x include enhancements to result set functionality, such as processing
forward or backward, positioning relatively or absolutely, seeing changes to the
database made internally or externally, and updating result set data and then copying
the changes to the database.
This chapter discusses these features, including the following topics:
■ Overview of JDBC 2.0 Result Set
■ Creating Scrollable or Updatable Result Sets
■ Positioning and Processing in Scrollable Result Sets
■ Updating Result Sets
■ Fetch Size
■ Refetching Rows
■ Seeing Database Changes Made Internally and Externally
Result Set Functionality and Result Set Categories Supported in JDBC 2.0
Result set functionality in JDBC 2.0 includes enhancements for scrollability and
positioning, sensitivity to changes by others, and updatability.
■ Scrollability, positioning, and sensitivity are determined by the result set type.
■ Updatability is determined by the concurrency type.
Specify the desired result set type and concurrency type when you create the
statement object that will produce the result set.
Together, the various result set types and concurrency types provide for six different
categories of result set.
Updatability
Updatability refers to the ability to update data in a result set and then copy the
changes to the database. This includes inserting new rows into the result set or
deleting existing rows.
Updatability might also require database write locks to mediate access to the
underlying database. Because you cannot have multiple write locks concurrently,
updatability in a result set is associated with concurrency in database access.
Result sets can optionally be updatable under JDBC 2.0
Important: Because all rows of any scrollable result set are stored
in the client-side cache, a situation where the result set contains
many rows, many columns, or very large columns might cause the
client-side Java Virtual Machine (JVM) to fail. Do not specify
scrollability for a large result set.
/**
* Return the data stored in the i-th row and j-th column.
*/
public Object get (int i, int j) throws IOException;
/**
* Remove the i-th row.
*/
public void remove (int i) throws IOException;
/**
* Remove the data stored in i-th row and j-th column
*/
public void remove (int i, int j) throws IOException;
/**
* Remove all data from the cache.
*/
public void clear () throws IOException;
/**
* Close the cache.
*/
public void close () throws IOException;
If you implement this interface with your own class, then your application code must
instantiate your class and then use the setResultSetCache method of an
OracleStatement, OraclePreparedStatement, or
OracleCallableStatement object to set the caching mechanism to use your
implementation. Following is the method signature:
void setResultSetCache(OracleResultSetCache cache) throws SQLException
Call this method prior to running a query. The result set produced by the query will
then use your specified caching mechanism.
And you can specify one of the following static constant values for concurrency
type:
■ ResultSet.CONCUR_READ_ONLY
■ ResultSet.CONCUR_UPDATABLE
pstmt.setString(1, "28959");
ResultSet rs = pstmt.executeQuery();
...
Scrollable and updatable result sets cannot have any column as Stream. When the
server has to fetch a Stream column, it reduces the fetch size to one and blocks all
columns following the Stream column until the Stream column is read. As a result,
columns cannot be fetched in bulk and scrolled through.
Workaround
As a workaround for the SELECT * limitation, you can use table aliases, as shown in
the following example:
SELECT t.* FROM TABLE t ...
Note: You cannot position relatively from before the first row,
which is the default initial position, or after the last row.
Attempting relative positioning from either of these positions
would result in a SQLException exception.
rs.afterLast();
while (rs.previous())
{
System.out.println(rs.getString("empno") + " " + rs.getFloat("sal"));
}
...
Unlike relative positioning, you can use next() from before the first row and
previous() from after the last row. You do not have to be at a valid current row to
use these methods.
Note: In a non-scrollable result set, you can process only with the
next() method. Attempting to use the previous() method will
cause a SQLException exception.
Presuming the result set is also scrollable, you can position to a row using any of the
available positioning methods, except beforeFirst method and afterLast
method, which do not go to a valid current row, and then delete that row, as in the
following example:
...
rs.absolute(5);
rs.deleteRow();
...
Important: The deleted row remains in the result set object even
after it has been deleted from the database.
In a scrollable result set, by contrast, a DELETE operation is evident
in the local result set object. The row would no longer be in the
result set after the DELETE. The row preceding the deleted row
becomes the current row, and row numbers of subsequent rows are
changed accordingly.
2. Call the updateRow method to copy the changes to the database or the
cancelRowUpdates method to cancel the changes.
Once you call the updateRow method, the changes are run and are made
permanent with the next transaction COMMIT operation. Be aware that by default,
the auto-commit flag is set to true so that any operation run is committed
immediately.
If you choose to cancel the changes before copying them to the database, then call
the cancelRowUpdates method instead. This will also revert to the original
values for that row in the local result set object. Note that once you call the
updateRow method, the changes are written to the transaction and cannot be
canceled unless you roll back the transaction.
Positioning to a different row before calling updateRow also cancels the changes
and reverts to the original values in the result set.
Before calling updateRow, you can call the usual getXXX methods to verify that
the values have been updated correctly. These methods take an int column index
or string column name as input. For example:
float myfloat = rs.getFloat(2);
...
// process myfloat to see if it's appropriate
...
Note: Result set UPDATE operations are visible in the local result
set object for all result set types, forward-only, scroll-sensitive, and
scroll-insensitive.
Example
Following is an example of a result set UPDATE operation that is also copied to the
database. The tenth row is updated. The column number is used to specify column 1,
and the column name, sal, is used to specify column 2.
Statement stmt = conn.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp");
if (rs.absolute(10)) // (returns false if row does not exist)
{
rs.updateString(1, "28959");
rs.updateFloat("sal", 100000.0f);
rs.updateRow();
}
// Changes are made permanent with the next COMMIT operation.
Note: The result set will remember the current position prior to
the moveToInsertRow call. Afterward, you can go back to it with
a moveToCurrentRow call.
You can specify a string for column name, instead of an integer for column
number.
3. Copy the changes to the database by calling the result set insertRow method.
Once you call insertRow, the insert is processed and will be made permanent
with the next transaction COMMIT operation.
Positioning to a different row before calling insertRow cancels the insert and
clears the insert-row.
Before calling insertRow you can call the usual getXXX methods to verify that
the values have been set correctly in the insert-row. These methods take an int
column index or string column name as input. For example:
float myfloat = rs.getFloat(2);
...process myfloat to see if it's appropriate...
Note: No result set type can see a row inserted by a result set
INSERT operation.
Example
The following example performs a result set INSERT operation, moving to the
insert-row, writing the data, copying the data into the database, and then returning to
what was the current row prior to going to the insert-row. The column number is used
to specify column 1, and the column name, sal, is used to specify column 2.
...
Statement stmt = conn.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs.moveToInsertRow();
rs.updateString(1, "28959");
rs.updateFloat("sal", 100000.0f);
rs.insertRow();
// Changes will be made permanent with the next COMMIT operation.
rs.moveToCurrentRow(); // Go back to where we came from...
...
A conflict will occur if you try to perform a DELETE or UPDATE operation on a row
updated by another committed transaction.
Oracle JDBC drivers use the ROWID to uniquely identify a row in a database table. As
long as the ROWID is valid when a driver tries to send an UPDATE or DELETE operation
to the database, the operation will be run.
The driver will not report any changes made by another committed transaction. Any
conflicts are silently ignored and your changes will overwrite the previous changes.
To avoid such conflicts, use the Oracle FOR UPDATE feature when running the query
that produces the result set. This will avoid conflicts, but will also prevent
simultaneous access to the data. Only a single write lock can be held concurrently on a
data item.
Fetch Size
By default, when Oracle JDBC runs a query, it retrieves a result set of 10 rows at a time
from the database cursor. This is the default Oracle row fetch size value. You can
change the number of rows retrieved with each trip to the database cursor by changing
the row fetch size value.
JDBC 2.0 also enables you to specify the number of rows fetched with each database
round-trip for a query, and this number is referred to as the fetch size. In Oracle JDBC,
the row-prefetch value is used as the default fetch size in a statement object. Setting
the fetch size overrides the row-prefetch setting and affects subsequent queries run
through that statement object.
Fetch size is also used in a result set. When the statement object run a query, the fetch
size of the statement object is passed to the result set object produced by the query.
However, you can also set the fetch size in the result set object to override the
statement fetch size that was passed to it.
The result set fetch size, either set explicitly, or by default equal to the statement fetch
size that was passed to it, determines the number of rows that are retrieved in any
subsequent trips to the database for that result set. This includes any trips that are still
required to complete the original query, as well as any refetching of data into the result
set. Data can be refetched, either explicitly or implicitly, to update a scroll-sensitive or
scroll-insensitive/updatable result set.
subsequent trips to the database to get more rows for the original query, as well as
affecting any later refetching of rows.
Refetching Rows
The result set refreshRow method is supported for some types of result sets for
refetching data. This consists of going back to the database to re-obtain the database
rows that correspond to n rows in the result set, starting with the current row, where n
is the fetch size. This lets you see the latest updates to the database that were made
outside of your result set, subject to the isolation level of the enclosing transaction.
Because refetching re-obtains only rows that correspond to rows already in your result
set, it does nothing about rows that have been inserted or deleted in the database since
the original query. It ignores rows that have been inserted, and rows will remain in
your result set even after the corresponding rows have been deleted from the database.
When there is an attempt to refetch a row that has been deleted in the database, the
corresponding row in the result set will maintain its original values.
You must be at a valid current row when you call this method, not outside the row
bounds and not at the insert-row.
The refreshRow method is supported for the following result set categories:
■ scroll-sensitive/read-only
■ scroll-sensitive/updatable
■ scroll-insensitive/updatable
JDBC 2.0 DatabaseMetaData objects include the following methods to verify this:
■ boolean othersDeletesAreVisible(int) throws SQLException
Table 17–1 Visibility of Internal and External Changes for Oracle JDBC
Can See Can See Can See Can See Can See Can See
Internal Internal Internal External External External
Result Set Type DELETE? UPDATE? INSERT? DELETE? UPDATE? INSERT?
forward-only no yes no no no no
scroll-sensitive yes yes no no yes no
scroll-insensitive yes yes no no no no
Note:
■ Remember that explicit use of the refreshRow method, is
distinct from the concept of visibility of external changes.
■ Remember that even when external changes are visible, as with
UPDATE operations underlying a scroll-sensitive result set, they
are not detected. The result set rowDeleted, rowUpdated,
and rowInserted methods always return false.
See Also:
■ JSR-114 specification at:
http://jcp.org/en/jsr/detail?id=114
■ Java SE 5.0 Javadoc at:
http://java.sun.com/j2se/1.5.0/docs/api/
■ Java SE 6.0 Javadoc at:
http://java.sun.com/javase/6/docs/api/
The JSR-114 specification includes implementation details for five types of RowSet:
■ CachedRowSet
■ JdbcRowSet
■ WebRowSet
■ FilteredRowSet
■ JoinRowSet
Oracle JDBC supports all five types of RowSets through the interfaces and classes
present in the oracle.jdbc.rowset package. Oracle Database 11g Release 1 (11.1)
adds RowSets support in the server-side drivers. Therefore, starting from Oracle
Database 11g Release 1 (11.1), RowSets support is uniform across all Oracle JDBC
driver types. The standard Oracle JDBC Java Archive (JAR) files, for example,
ojdbc5.jar and ojdbc6.jar contain the oracle.jdbc.rowset package.
Note:
■ The other JAR files with different file suffix names, for example,
ojdbc5_g.jar, ojdbc5dms.jar, and so on also contain the
oracle.jdbc.rowset package.
■ In Oracle Database 10g release 2 (10.2), the implementation classes
were packaged in the ojdbc14.jar file.
■ Prior to Oracle Database 10g release 2 (10.2), the implementation
classes were packaged in the ocrs12.jar file.
■ Prior to Oracle Database 11g Release 1 (11.1), RowSets support
was not available in the server-side drivers.
To use the Oracle RowSet implementations, you need to import either the entire
oracle.jdbc.rowset package or specific classes and interfaces from the package
for the required RowSet type. For client-side usage, you also need to include the
standard Oracle JAR files like ojdbc5.jar or ojdbc6.jar in the CLASSPATH
environment variable.
RowSet Properties
The javax.sql.RowSet interface provides a set of JavaBeans properties that can be
altered to access the data in the data source through a single interface. Example of
properties are connection string, user name, password, type of connection, and the
query string.
For a complete list of properties and property descriptions, refer to the Java2 Platform,
Standard Edition (J2SE) Javadoc for javax.sql.RowSet at
http://java.sun.com/j2se/1.5.0/docs/api/javax/sql/RowSet.html
The interface provides standard accessor methods for setting and retrieving the
property values. The following code illustrates setting some of the RowSet properties:
...
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
...
In this example, the URL, user name, password, and SQL query are set as the RowSet
properties to retrieve the employee number, employee name, and salary of all the
employees into the RowSet object.
Applications that need to handle only selected events can implement only the required
event handling methods by using the
oracle.jdbc.rowset.OracleRowSetListenerAdapter class, which is an
abstract class with empty implementation for all the event handling methods. In the
following code, only the rowSetChanged event is handled, while the remaining
events are not handled by the application:
...
rowset.addRowSetListener(new oracle.jdbc.rowset.OracleRowSetListenerAdapter ()
{
public void rowSetChanged(RowSetEvent event)
{
// your action for rowSetChanged
}
}
);
...
In the preceding example, the employee number 7839 is set as the input or bind
parameter for the SQL query specified in the command property of the RowSet object.
When the SQL query is processed, the RowSet object is filled with the employee name
and salary information of the employee whose employee number is 7839.
Traversing RowSets
The javax.sql.RowSet interface extends the java.sql.ResultSet interface. The
RowSet interface, therefore, provides cursor movement and positioning methods,
which are inherited from the ResultSet interface, for traversing through data in a
RowSet object. Some of the inherited methods are absolute, beforeFirst,
afterLast, next, and previous.
The RowSet interface can be used just like a ResultSet interface for retrieving and
updating data. The RowSet interface provides an optional way to implement a
scrollable and updatable result set. All the fields and methods provided by the
ResultSet interface are implemented in RowSet.
In the preceding code, the cursor position is initialized to the position before the first
row of the RowSet by the beforeFirst method. The rows are retrieved in forward
direction using the next method.
The following code illustrates how to scroll through a RowSet in the reverse direction:
/**
* Scrolling backward, and printing the empno in
* the reverse order as it was fetched.
*/
//going to the last row of the rowset
rowset.afterLast ();
while (rowset.previous ())
System.out.println ("empno: " +rowset.getInt (1));
In the preceding code, the cursor position is initialized to the position after the last row
of the RowSet. The rows are retrieved in reverse direction using the previous
method of RowSet.
Inserting, updating, and deleting rows are supported by the Row Set feature as they
are in the Result Set feature. In order to make the Row Set updatable, you must call the
setReadOnly(false) and acceptChanges methods.
The following code illustrates the insertion of a row at the fifth position of a Row Set:
...
/**
* Make rowset updatable
*/
rowset.setReadOnly (false);
/**
* Inserting a row in the 5th position of the rowset.
*/
// moving the cursor to the 5th position in the rowset
if (rowset.absolute(5))
{
rowset.moveToInsertRow ();
rowset.updateInt (1, 193);
In the preceding code, a call to the absolute method with a parameter 5 takes the
cursor to the fifth position of the RowSet and a call to the moveToInsertRow method
creates a place for the insertion of a new row into the RowSet. The updateXXX
methods are used to update the newly created row. When all the columns of the row
are updated, the insertRow is called to update the RowSet. The changes are
committed through acceptChanges method.
CachedRowSet
A CachedRowSet is a RowSet in which the rows are cached and the RowSet is
disconnected, that is, it does not maintain an active connection to the database. The
oracle.jdbc.rowset.OracleCachedRowSet class is the Oracle implementation
of CachedRowSet. It can interoperate with the reference implementation of Sun
Microsystems. The OracleCachedRowSet class in the ojdbc5.jar and
ojdbc6.jar files implements the standard JSR-114 interface
javax.sql.rowset.CachedRowSet.
In the following code, an OracleCachedRowSet object is created and the connection
URL, user name, password, and the SQL query for the RowSet object is set as
properties. The RowSet object is populated using the execute method. After the
execute method has been processed, the RowSet object can be used as a
java.sql.ResultSet object to retrieve, scroll, insert, delete, or update data.
...
RowSet rowset = new OracleCachedRowSet();
rowset.setUrl("jdbc:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
while (rowset.next ())
{
System.out.println("empno: " +rowset.getInt (1));
System.out.println("ename: " +rowset.getString (2));
System.out.println("sal: " +rowset.getInt (3));
}
...
In the preceding example, a ResultSet object is obtained by running a query and the
retrieved ResultSet object is passed to the populate method of the
CachedRowSet object to populate the contents of the result set into the
CachedRowSet.
CachedRowSet Constraints
All the constraints that apply to an updatable result set are applicable here, except
serialization, because OracleCachedRowSet is serializable. The SQL query has the
following constraints:
■ References only a single table in the database
■ Contains no join operations
■ Selects the primary key of the table it references
In addition, a SQL query should also satisfy the following conditions, if new rows are
to be inserted:
■ Selects all non-nullable columns in the underlying table
■ Selects all columns that do not have a default value
Connection properties like, transaction isolation and concurrency mode of the result
set, cannot be set after populating the RowSet, because the properties cannot be
applied to the connection after retrieving the data from the same.
JdbcRowSet
A JdbcRowSet is a RowSet that wraps around a ResultSet object. It is a connected
RowSet that provides JDBC interfaces in the form of a JavaBean interface. The Oracle
implementation of JdbcRowSet is oracle.jdbc.rowset.OracleJDBCRowSet. The
OracleJDBCRowSet class in ojdbc5.jar and ojdbc6.jar implements the
standard JSR-114 interface javax.sql.rowset.JdbcRowSet.
Table 18–1 shows how the JdbcRowSet interface differs from CachedRowSet
interface.
JdbcRowSet is a connected RowSet, which has a live connection to the database and all
the calls on the JdbcRowSet are percolated to the mapping call in the JDBC connection,
statement, or result set. A CachedRowSet does not have any connection to the
database open.
JdbcRowSet requires the presence of JDBC drivers unlike a CachedRowSet, which
does not require JDBC drivers during manipulation. However, both JdbcRowSet and
CachedRowSet require JDBC drivers during population of the RowSet and while
committing the changes of the RowSet.
The following code illustrates how a JdbcRowSet is used:
...
RowSet rowset = new OracleJDBCRowSet();
rowset.setUrl("java:oracle:oci:@");
rowset.setUsername("SCOTT");
rowset.setPassword("TIGER");
rowset.setCommand("SELECT empno, ename, sal FROM emp");
rowset.execute();
while (rowset.next())
{
System.out.println("empno: " + rowset.getInt(1));
System.out.println("ename: " + rowset.getString(2));
System.out.println("sal: " + rowset.getInt(3));
}
...
In the preceding example, the connection URL, user name, password, and SQL query
are set as properties of the RowSet object, the SQL query is processed using the
execute method, and the rows are retrieved and printed by traversing through the
data populated in the RowSet object.
WebRowSet
A WebRowSet is an extension to CachedRowSet. It represents a set of fetched rows or
tabular data that can be passed between tiers and components in a way such that no
active connections with the data source need to be maintained. The WebRowSet
interface provides support for the production and consumption of result sets and their
synchronization with the data source, both in Extensible Markup Language (XML)
format and in disconnected fashion. This allows result sets to be shipped across tiers
and over Internet protocols.
The Oracle implementation of WebRowSet is
oracle.jdbc.rowset.OracleWebRowSet. This class, which is in the ojdbc5.jar
and ojdbc6.jar files, implements the standard JSR-114 interface
javax.sql.rowset.WebRowSet. This class also extends the
oracle.jdbc.rowset.OracleCachedRowSet class. Besides the methods available
in OracleCachedRowSet, the OracleWebRowSet class provides the following
methods:
public OracleWebRowSet() throws SQLException
These methods read the OracleWebRowSet object in the XML format according
to its JSR-114 XML schema, using the supplied Reader or InsputStream object.
The Oracle WebRowSet implementation supports Java API for XML Processing (JAXP)
1.2. Both Simple API for XML (SAX) 2.0 and Document Object Model (DOM)
JAXP-conforming XML parsers are supported. It follows the current JSR-114 W3C
XML schema for WebRowSet from Sun Microsystems, which is at:
http://java.sun.com/xml/ns/jdbc/webrowset.xsd
See Also:
■ JSR-114 specification at:
http://jcp.org/en/jsr/detail?id=114
■ Java SE 5.0 Javadoc at:
http://java.sun.com/j2se/1.5.0/docs/api/
■ Java SE 6.0 Javadoc at:
http://java.sun.com/javase/6/docs/api/
Applications that use the readXml(...) methods should set one of the following
two standard JAXP system properties before calling the methods:
■ javax.xml.parsers.SAXParserFactory
This property is for a SAX parser.
■ javax.xml.parsers.DocumentBuilderFactory
This property is for a DOM parser.
The following code illustrates the use of OracleWebRowSet for both writing and
reading in XML format:
import java.sql.*;
import java.io.*;
import oracle.jdbc.rowset.*;
...
String url = "jdbc:oracle:oci8:@";
try
{
// Create a java.io.Writer object
FileWriter out = new FileWriter("xml.out");
try
{
// Use the preceding output file as input
FileReader fr = new FileReader("xml.out");
Note: The preceding code uses the Oracle SAX XML parser, which
supports schema validation.
FilteredRowSet
A FilteredRowSet is an extension to WebRowSet that provides programmatic support
for filtering its content. This enables you to avoid the overhead of supplying a query
and the processing involved. The Oracle implementation of FilteredRowSet is
oracle.jdbc.rowset.OracleFilteredRowSet. The OracleFilteredRowSet
class in the ojdbc5.jar and ojdbc6.jar files implements the standard JSR-114
interface javax.sql.rowset.FilteredRowSet.
The OracleFilteredRowSet class defines the following new methods:
public Predicate getFilter();
This method returns a Predicate object that defines the filtering criteria active
on the OracleFilteredRowSet object.
public void setFilter(Predicate p) throws SQLException;
The predicate defined in the preceding code is used for filtering content in an
OracleFilteredRowSet object, as follows:
...
OracleFilteredRowSet ofrs = new OracleFilteredRowSet();
int low[] = {50, 100};
int high[] = {100, 200};
int indexes[] = {1, 2};
ofrs.setCommand("select col1, col2 from test_table");
// this will only get rows with col1 in (50,100) and col2 in (100,200)
while (ofrs.next()) {...}
...
JoinRowSet
A JoinRowSet is an extension to WebRowSet that consists of related data from
different RowSets. There is no standard way to establish a SQL JOIN between
This method returns a String array containing the names of the RowSet objects
that are added to the OracleJoinRowSet object.
public boolean supportsCrossJoin();
public boolean supportsFullJoin();
public boolean supportsInnerJoin();
public boolean supportsLeftOuterJoin();
public boolean supportsRightOuterJoin();
This method is used to set the JOIN type on the OracleJoinRowSet object. It
takes an integer constant as defined in the javax.sql.rowset.JoinRowSet
interface that specifies the JOIN type.
public int getJoinType() throws SQLException;
This method returns an integer value that indicates the JOIN type set on the
OracleJoinRowSet object. This method throws a SQLException exception.
public CachedRowSet toCachedRowSet() throws SQLException;
This method returns a String containing the SQL-like description of the WHERE
clause used in the OracleJoinRowSet object. This methods throws a
SQLException exception.
The following code illustrates how OracleJoinRowSet is used to perform an inner
join on two RowSets, whose data come from two different tables. The resulting
RowSet contains data as if they were the result of an inner join on these two tables.
Assume that there are two tables, an Order table with two NUMBER columns
Order_id and Person_id, and a Person table with a NUMBER column Person_id
and a VARCHAR2 column Name.
...
// RowSet holding data from table Order
OracleCachedRowSet ocrsOrder = new OracleCachedRowSet();
...
ocrsOrder.setCommand("select order_id, person_id from order");
...
// Join on person_id column
ocrsOrder.setMatchColumn(2);
ocrsOrder.execute();
The Oracle Java Database Connectivity (JDBC) drivers provide globalization support,
formerly known as National Language Support (NLS). Globalization support enables
you retrieve data or insert data into a database in any character set that Oracle
supports. If the clients and the server use different character sets, then the driver
provides the support to perform the conversions between the database character set
and the client character set.
This chapter contains the following sections:
■ Providing Globalization Support
■ NCHAR, NVARCHAR2, NCLOB and the defaultNChar Property in JDK 1.5
■ New Methods for National Character Set Type Data in JDK 1.6
See Also:
■ "Oracle Character Data Types Support" on page 4-10
■ Oracle Database Globalization Support Guide
■ Oracle Database Reference
Note:
■ Starting from Oracle Database 10g, the NLS_LANG variable is no
longer part of the JDBC globalization mechanism. The JDBC
driver does not check NLS environment. So, setting it has no
effect.
■ The JDBC server-side internal driver provides complete
globalization support and does not require any globalization
extension files.
■ JDBC 4.0 includes methods for reading and writing national
character set values. You should use these methods when using
JSE 6 or later.
■ CHAR or VARCHAR data members of object and collection for the character sets
US7ASCII, WE8DEC, WE8ISO8859P1, WE8MSWIN1252, and UTF8.
To use any other character sets in CHAR or VARCHAR data members of objects or
collections, you must include orai18n.jar in the CLASSPATH environment variable
of your application.
Compressing orai18n.jar
The orai18n.jar file contains many important character set and globalization
support files. You can reduce the size of orai18n.jar using the built-in
customization tool, as follows:
java -jar orai18n.jar -custom-charsets-jar [jar/zip_filename] -charset
characterset_name [characterset_name ...]
If you do not specify a file name for your custom JAR/ZIP file, then a file with the
name jdbc_orai18n_cs.jar is created in the current working directory. Also, for
your custom JAR/ZIP file, you cannot specify a name that starts with orai18n.
If any invalid or unsupported character set name is specified in the command, then no
output JAR/ZIP file will be created. If the custom JAR/ZIP file exists, then the file will
not be updated or removed.
The custom character set JAR/ZIP does not accept any command. However, it prints
the version information and the command that was used to generate the JAR/ZIP file.
For example, you have jdbc_orai18n_cs.zip, the command that displays the
information and the displayed information is as follows:
$ java -jar jdbc_orai18n_cs.jar
Oracle Globalization Development Kit - 11.1.X.X.X Release
This custom character set jar/zip file was created with the following command:
java -jar orai18n.jar -custom-charsets-jar jdbc_orai18n_cs.jar -charset
WE8ISO8859P15
The limitation to the number of character sets that can be specified depends on that of
the shell or command prompt of the operating system. It is certified that all supported
character sets can be specified with the command.
Note: If you are using a custom character set, then you need to
perform the following so that JDBC supports the custom character set:
1. After creating the .nlt and .nlb files as part of the process of creating a
custom character set, create .glb files for the newly created character set
and also for the lx0boot.nlt file using the following command:
java -classpath $ORACLE_HOME/jlib/orai18n-tools.jar Ginstall
<nlt file>
2. Add the generated files and
$ORACLE_HOME/jlib/orai18n-mappings.jar into the classpath
environment variable while executing the JDBC code that connects to the
database with the custom character set.
For more information about creating a custom character set, refer to
Oracle Database Globalization Support Guide.
If you want to set the value of defaultNChar to true, then specify the following at
the command-line:
java -Doracle.jdbc.defaultNChar=true myApplication
If you prefer, then you can also specify defaultNChar as a connection property and
access NCHAR, NVARCHAR2, or NCLOB data.
If the value of defaultNChar is true, then you should call the
setFormOfUse(<column_Index>, OraclePreparedStatement.FORM_CHAR)
for columns that do not need national-language characters. For example:
PreparedStatement pstmt =
conn.prepareStatement("insert into TEST values(?,?,?)");
pstmt.setFormOfUse(3, OraclePreparedStatement.FORM_CHAR);
pstmt.setString(3, myString); // CHAR column
Note:
■ Always use java.lang.String for character data instead of
oracle.sql.CHAR. CHAR is provided only for backward
compatibility.
■ You can also use the setObject method to access national
character set types, but if the setObject method is used, then
the target data type must be specified as Types.NCHAR,
Types.NCLOB, Types.NVARCHAR, or Types.LONGNVARCHAR.
New Methods for National Character Set Type Data in JDK 1.6
JDBC 4.0 introduces support for the following four additional SQL types to access the
national character set types:
■ NCHAR
■ NVARCHAR
■ LONGNVARCHAR
■ NCLOB
These types are similar to the CHAR, VARCHAR, LONGVARCHAR, and CLOB types, except
that the values are encoded using the national character set. The JDBC specification
uses the String class to represent NCHAR, NVARCHAR, and LONGNVARCHAR data, and
the NClob class to represent NCLOB values.
To retrieve a national character value, an application calls one of the following
methods:
■ getNString
■ getNClob
■ getNCharacterStream
■ getObject
To specify a value for a parameter marker of national character type, an application
calls one of the following methods:
■ setNString
■ setNCharacterStream
■ setNClob
■ setObject
Tip: If the setObject method is used, then the target data type
must be specified as Types.NCHAR, Types.NCLOB,
Types.NVARCHAR, or Types.LONGNVARCHAR.
This part consists of chapters that discuss the Oracle Java Database Connectivity
(JDBC) features that enhance performance, such as Statement caching, implicit
connection caching, run-time connection load balancing, and Oracle Call Interface
(OCI) connection pooling. It also includes a chapter that provides information about
Oracle performance extensions, such as update batching and row prefetching.
Part V contains the following chapters:
■ Chapter 20, "Statement and Result Set Caching"
■ Chapter 21, "Implicit Connection Caching"
■ Chapter 22, "Run-Time Connection Load Balancing"
■ Chapter 23, "Performance Extensions"
■ Chapter 24, "OCI Connection Pooling"
■ Chapter 25, "Oracle Advanced Queuing"
20
Statement and Result Set Caching
This chapter describes the benefits and use of Statement caching, an Oracle Java
Database Connectivity (JDBC) extension.
This chapter contains the following sections:
■ About Statement Caching
■ Using Statement Caching
■ Reusing Statements Objects
■ Result Set Caching
Because explicit Statement caching retains statement data and state as well as
metadata, it has a performance edge over implicit Statement caching, which retains
only metadata. However, you must be cautious when using this type of caching,
because explicit Statement caching saves all three types of information for reuse and
you may not be aware of what data and state are retained from prior use of the
statements.
Implicit and explicit Statement caching can be differentiated on the following points:
■ Retrieving statements
In the case of implicit Statement caching, you take no special action to retrieve
statements from a cache. Instead, whenever you call prepareStatement or
prepareCall, JDBC automatically checks the cache for a matching statement and
returns it if found. However, in the case of explicit Statement caching, you use
specialized Oracle WithKey methods to cache and retrieve statement objects.
■ Providing key
Implicit Statement caching uses the SQL string of a prepared or callable statement
as the key, requiring no action on your part. In contrast, explicit Statement caching
requires you to provide a Java String, which it uses as the key.
■ Returning statements
During implicit Statement caching, if the JDBC driver cannot find a statement in
cache, then it will automatically create one. However, during explicit Statement
caching, if the JDBC driver cannot find a matching statement in cache, then it will
return a null value.
Table 20–1 compares the different methods employed in implicit and explicit
Statement caching.
Note:
■ You enable implicit and explicit caching for a particular
physical connection independently. Therefore, it is possible to
do Statement caching both implicitly and explicitly during the
same session.
■ Implicit and explicit Statement caching share the same cache.
Remember this when you set the statement cache size.
3. Disable implicit Statement caching for any particular statement you do not want to
cache. This is an optional step.
4. Cache the statement using the close method.
5. Retrieve the implicitly cached statement by calling the appropriate standard
prepare method.
Note: If you are using JSE 6, then you can disable Statement caching
by using the standard JDBC 4.0 method setPoolable:
PreparedStatement.setPoolable(false);
Table 20–2 describes the methods used to allocate statements and retrieve implicitly
cached statements.
Table 20–2 Methods Used in Statement Allocation and Implicit Statement Caching
Method Functionality for Implicit Statement Caching
prepareStatement Performs a cache search that either finds and returns the
desired cached OraclePreparedStatement object or
allocates a new OraclePreparedStatement object if a
match is not found
prepareCall Performs a cache search that either finds and returns the
desired cached OracleCallableStatement object or
allocates a new OracleCallableStatement object if a
match is not found
If you retrieve a statement with a specified key, then the JDBC driver searches the
cache for the statement, based on the specified key. If a match is found, then the
matching statement is returned along with its state, data, and metadata. This
information is as it was when the statement was last closed. If a match is not found,
then the JDBC driver returns null.
The following code recalls pstmt from cache using the "mykey" key with the
getStatementWithKey method. Recall that the pstmt statement object was cached
with the "mykey" key.
pstmt = ((OracleConnection)conn).getStatementWithKey ("mykey");
If you call the creationState method on the pstmt statement object, then the
method returns EXPLICIT.
Table 20–3 describes the methods used to retrieve explicitly cached statements.
You must annotate a query or query fragment with a result cache hint to indicate that
results are to be stored in the query result cache.
The query result set can be cached in the following ways:
■ Server-side Cache
■ Client Result Cache
Server-side Cache
Oracle Database 11g Release 1 (11.1) provides support for server-side Result Set
caching for both JDBC types. The server-side result cache is used to cache the results of
the current queries, query fragments, and PL/SQL functions in memory and then to
use the cached results in future executions of the query, query fragment, or PL/SQL
function. The cached results reside in the result cache memory portion of the SGA. A
cached result is automatically invalidated whenever a database object used in its
creation is successfully modified. The server-side caching can be of the following two
types:
■ SQL Query Result Cache
■ PL/SQL Function Result Cache
See Also:
■ Oracle Database Performance Tuning Guide for more information
about SQL Query Result Cache
■ Oracle Database PL/SQL Language Reference for more information
about PL/SQL Function Result Cache
Turning Caching On
An application turns the implicit connection cache on by calling
OracleDataSource.setConnectionCachingEnabled(true). After implicit
caching is turned on, the first connection request to the OracleDataSource class
transparently creates a connection cache.
Example 21–1 provides a sample code that uses the implicit connection cache.
Opening a Connection
After you have turned connection caching on, whenever you retrieve a connection
through the OracleDataSource.getConnection method, the JDBC drivers check
to see if a connection is available in the cache.
The getConnection method checks if there are any free physical connections in the
cache that match the specified criteria. If a match is found, then a logical connection is
returned, wrapping the physical connection. If no physical connection match is found,
then a new physical connection is created, wrapped in a logical connection, and
returned.
There are four variations on getConnection, two that make no reference to the
connection cache and two that specify which sort of connections the cache may return.
The non-cache-specific getConnection methods behave in the standard manner.
When this property is set, the name is used to uniquely identify the cache accessed by
the cache-enabled OracleDataSource. If the property is not set, then a default cache
name is created using the convention
DataSourceName#HexRepresentationOfNumberOfCaches.
Note:
■ Before setting the cache-specific properties, you must enable
caching on the data source; otherwise the
setConnectionCacheProperties method will have no effect.
■ Although these properties govern the behavior of the connection
cache, they are set on the data source, and not on the connection
or on the cache itself.
Closing a Connection
An application returns a connection to the cache by calling the close method. There
are two variants of the close method: one with no arguments and one that takes a
Connection object as argument.
Note:
■ Applications must close connections to ensure that the
connections are returned to the cache.
■ When implicit connection cache is enabled, you must reset all the
connection states, such as auto-commit, batch size, prefetch size,
transaction status, and transaction isolation, before putting the
connection back into the cache. This ensures that any subsequent
connection retrieved from the cache will have its state reset.
import javax.naming.*;
import javax.naming.spi.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
...
// create a DataSource
OracleDataSource ods = new OracleDataSource();
ods.close();
Connection Attributes
Each connection obtained from a data source can have user-defined attributes.
Attributes are specified by the application developer and are
java.lang.Properties name and value pairs.
An application can use connection attributes to supply additional semantics to identify
connections. For instance, an application may create an attribute named
connection_type and then assign it the value payroll or inventory.
The methods that get and set connection attributes are found on the
OracleConnection interface. This section covers the following topics:
■ Getting Connections
■ Setting Connection Attributes
■ Checking Attributes of a Returned Connection
■ Connection Attribute Example
Getting Connections
The first connection you retrieve has no attributes. You must set them. After you have
set attributes on a connection, you can request the connection by specifying its
attribute, using the specialized forms of the getConnection method:
■ getConnection(java.util.Properties cachedConnectionAttributes
Requests a database connection that matches the specified
cachedConnectionAttributes.
For this reason, applications should always check the attributes of a returned
connection. To do this, use the getUnMatchedConnectionAttributes method,
which returns a list of any attributes that were not matched in retrieving the
connection. If the return value of this method is null, you know that you must set all
the connection attributes.
Limit Properties
These properties control the size of the cache.
InitialLimit
Sets how many connections are created in the cache when it is created or reinitialized.
When this property is set to an integer value greater than 0, creating or reinitializing
the cache automatically creates the specified number of connections, filling the cache
in advance of need.
Default: 0
MaxLimit
Sets the maximum number of connection instances the cache can hold. The default
value is Integer.MAX_VALUE, meaning that there is no limit enforced by the
connection cache, so that the number of connections is limited only by the number of
database sessions configured for the database.
Default: Integer.MAX_VALUE (no limit)
MaxStatementsLimit
Sets the maximum number of statements that a connection keeps open. When a cache
has this property set, reinitializing the cache or closing the data source automatically
closes all cursors beyond the specified MaxStatementsLimit.
Default: 0
MinLimit
Sets the minimum number of connections the cache maintains.
Default: 0
Note:
■ Setting the MinLimit property does not initialize the cache to
contain the minimum number of connections. To do this, use the
InitialLimit property.
■ When InitialLimit is greater than MinLimit, it is possible to
have any number of connections specified by InitialLimit up
to a value specified by MaxLimit. Therefore, InitialLimit
does not depend on MinLimit.
■ Connections can fall below the minimum limit set on the
connection pool when JDBC Fast Connection Failover DOWN
events are processed. The processing removes affected
connections from the pool. MinLimit will be honored as requests
to the connection pool increase and the number of connections get
past the MinLimit value.
TIMEOUT Properties
These properties control the lifetime of an element in the cache.
InactivityTimeout
Sets the maximum time a physical connection can remain idle in a connection cache.
An idle connection is one that is not active and does not have a logical handle
associated with it. When InactivityTimeout expires, the underlying physical
connection is closed. However, the size of the cache is not allowed to shrink below
minLimit, if it has been set.
Default: 0 (no timeout in effect)
TimeToLiveTimeout
Sets the maximum time in seconds that a logical connection can remain open. When
TimeToLiveTimeout expires, the logical connection is unconditionally closed, the
relevant statement handles are canceled, and the underlying physical connection is
returned to the cache for reuse.
Default: 0 (no timeout in effect)
AbandonedConnectionTimeout
Sets the maximum time that a connection can remain unused before the connection is
closed and returned to the cache. A connection is considered unused if it has not had
SQL database activity.
When AbandonedConnectionTimeout is set, JDBC monitors SQL database activity
on each logical connection. For example, when stmt.execute is called on the
connection, a heartbeat is registered to convey that this connection is active. The
heartbeats are set at each database execution. If a connection has been inactive for the
specified amount of time, the underlying connection is reclaimed and returned to the
cache for reuse.
Default: 0 (no timeout in effect)
PropertyCheckInterval
Sets the time interval at which the Connection Cache Manager inspects and enforces
all specified cache properties. PropertyCheckInterval is set in seconds.
Default: 900 seconds
Other Properties
These properties control miscellaneous cache behavior.
AttributeWeights
AttributeWeights sets the weight for each attribute set on the connection.
ClosestConnectionMatch
ClosestConnectionMatch causes the connection cache to retrieve the connection
with the closest approximation to the specified connection attributes.
ConnectionWaitTimeout
Specifies cache behavior when a connection is requested and there are already
MaxLimit connections active. If ConnectionWaitTimeout is equal to zero, then each
connection request waits for zero seconds, that is, null connection is returned
immediately. If ConnectionWaitTimeout is greater than zero, then each connection
request waits for the specified number of seconds or until a connection is returned to
the cache. If no connection is returned to the cache before the timeout elapses, then the
connection request returns null.
Default: zero
LowerThresholdLimit
Sets the lower threshold limit on the cache. The default is 20 percent of the MaxLimit
on the connection cache. This property is used whenever a releaseConnection()
cache callback method is registered.
ValidateConnection
Setting ValidateConnection to true causes the connection cache to test every
connection it retrieves against the underlying database. If a valid connection cannot be
retrieved, then an exception is thrown.
Default: false
import javax.naming.*;
import javax.naming.spi.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
...
OracleDataSource ds = (OracleDataSource) ctx.lookup("...");
java.util.Properties prop = new java.util.Properties ();
prop.setProperty("MinLimit", "5"); // the cache size is 5 at least
prop.setProperty("MaxLimit", "25");
prop.setProperty("InitialLimit", "3"); // create 3 connections at startup
prop.setProperty("InactivityTimeout", "1800"); // seconds
prop.setProperty("AbandonedConnectionTimeout", "900"); // seconds
prop.setProperty("MaxStatementsLimit", "10");
prop.setProperty("PropertyCheckInterval", "60"); // seconds
System.out.println(occm.getNumberOfActiveConnections(cacheName)
+ " connections are active");
// Refresh all connections in cache
occm.refreshCache(cacheName,
OracleConnectionCacheManager.REFRESH_ALL_CONNECTIONS);
// Reinitialize cache, closing all connections
java.util.Properties newProp = new java.util.Properties();
newProp.setProperty("MaxLimit", "50");
occm.reinitializeCache(cacheName, newProp);
Advanced Topics
This section discusses cache functionality that is useful for advanced users, but is not
essential to understanding or using the implicit connection cache. This section covers
the following topics:
■ Attribute Weights and Connection Matching
■ Connection Cache Callbacks
ClosestConnectionMatch
Setting ClosestConnectionMatch to true causes the connection cache to retrieve
the connection with the closest approximation to the specified connection attributes.
This can be used in combination with AttributeWeights to specify what is
considered a closest match.
Default: false
AttributeWeights
Sets the weights for each connectionAttribute. This property is used when
ClosestConnectionMatch is set to true to determine which attributes are given
highest priority when searching for matches. An attribute with a high weight is given
more importance in determining a match than an attribute with a low weight.
AttributeWeights contains a set of Strings representing key-value pairs. Each
key/value pair sets the weights for each connectionAttribute for which the user
intends to request a connection. Each String is in the format written by the
java.util.Properties.Store(OutputStream, String) method, and thus
can be read by the java.util.Properties.load(InputStream) method. The
Key is a connectionAttribute and the Value is the weight. A weight must be an
integer value greater than 0. The default weight is 1.
For example, TRANSACTION_ISOLATION could be assigned a weight of 10 and ROLE
a weight of 5. If ClosestConnectionMatch is set to true, when a
connectionAttribute based connection request is made on the cache, connections
with a matching TRANSACTION_ISOLATION will be favored over connections with a
matching ROLE.
Default: No AttributeWeights
■ The application maintains state on each connection, but has no control over the
connection and, therefore, cannot ensure cleaning up of state for reuse of
connections by other applications or users.
The use of either of the timeout mechanisms is not recommended.
Oracle Database 11g provides the run-time connection load balancing feature. This
chapter contains the following sections:
■ Overview of Run-Time Connection Load Balancing
■ Enabling Run-Time Connection Load Balancing
Instance1-
Best
Client
1
Instance2-
3 Best
Instance3-
Bad
Connection retrieval based on the load balancing advisory is automatic. A request for
a connection is serviced by selecting a connection based on the service goal as
determined by the Load Balancing Advisory. The service goal determines whether the
connection provides best service quality, that is, how efficiently a single transaction
completes, or best throughput, that is, how efficiently an entire job or long-running
query completes. The advisory is used by the connection cache as long as the events
are posted by Oracle Real Application Clusters. When the events stop arriving, the
connection cache reverts to random retrieval of connections from the cache.
Run-time connection load balancing relies on the Oracle Notification Service (ONS)
infrastructure. It uses the same out-of-band ONS event mechanism that is used for Fast
Connection Failover processing. As a result, run-time connection load balancing is
enabled by default when Fast Connection Failover is enabled. There is no additional
setup or configuration of ONS required to benefit from run-time connection load
balancing.
Note: You can set the connection balancing goal to LONG. However,
this is mostly useful for closed workloads, that is, when the rate of
completing work is equal to the rate of starting new work.
This chapter describes the Oracle performance extensions to the Java Database
Connectivity (JDBC) standard.
This chapter covers the following topics:
■ Update Batching
■ Additional Oracle Performance Extensions
Update Batching
You can reduce the number of round-trips to the database, thereby improving
application performance, by grouping multiple UPDATE, DELETE, or INSERT
statements into a single batch and having the whole batch sent to the database and
processed in one trip. This is referred to as update batching.
This is especially useful with prepared statements, when you are repeating the same
statement with different bind variables.
Oracle JDBC supports two distinct models for update batching:
■ The standard model, implementing the JDBC 2.0 specification, which is referred to
as standard update batching
■ The Oracle-specific model, independent of the JDBC 2.0 specification, which is
referred to as Oracle update batching
Note:
■ Do not mix standard update batching with Oracle update
batching in the same application. The JDBC driver will throw
an exception when you mix these.
■ Disable auto-commit mode if you use either update batching
model. In case an error occurs while you are processing a batch,
this provides you the option of committing or rolling back the
operations that ran successfully prior to the error.
■ If the connection receives a ROLLBACK request before sendBatch has been called,
then the pending batched operations are not removed. You must explicitly call
clearBatch to do this.
Even though this sets the default batch value for all the prepared statements of the
connection, you can override it by calling the setExecuteBatch method of the
oracle.jdbc.OraclePreparedStatement interface on individual Oracle
prepared statements.
The connection batch value will apply to statement objects created after this batch
value was set.
Note that instead of calling the setDefaultExecuteBatch method, you can set the
defaultBatchValue Java property if you use a Java Properties object in
establishing the connection.
If you wish, insert the getExecuteBatch method at any point in the program to
check the default batch value for the statement, as follows:
System.out.println (" Statement Execute Batch Value " +
((OraclePreparedStatement)ps).getExecuteBatch());
3. If you send an execute-update call to the database at this point, then no data will
be sent to the database, and the call will return 0.
// No data is sent to the database by this call to executeUpdate
System.out.println ("Number of rows updated so far: "
+ ps.executeUpdate ());
4. If you enter a set of input values for a second row and an execute-update, then the
number of batch calls to executeUpdate will be equal to the batch value of 2.
The data will be sent to the database, and both rows will be inserted in a single
round-trip.
ps.setInt (1, 11);
ps.setString (2, "Applications");
ps.setString (3, "Indonesia");
ps.close ();
To check the particular statement batch value of an Oracle prepared statement, use the
OraclePreparedStatement class getExecuteBatch method:
Integer batch_val = ((OraclePreparedStatement)ps).getExecuteBatch();
The batch is not processed at this point. The ps.executeUpdate method returns
0.
2. If you enter a set of input values for a second operation and call executeUpdate
again, then the data will still not be sent to the database, because the batch value in
effect for the statement is the connection batch value, which is 20.
ps.setInt (1, 33);
ps.setString (2, "Applications");
ps.setString (3, "Indonesia");
■ If an executeUpdate call results in the batch value being reached and the batch
being processed, then the method will return the total number of rows affected by
all operations in the batch.
Similarly, the sendBatch method of an OraclePreparedStatement object returns
the total number of rows affected by all operations in the batch.
Example 23–1 illustrates the use of Oracle update batching.
PreparedStatement ps =
conn.prepareStatement("insert into dept values (?, ?, ?)");
ps.setInt(1, 23);
ps.setString(2, "Sales");
ps.setString(3, "USA");
ps.executeUpdate(); //JDBC queues this for later execution
ps.setInt(1, 24);
ps.setString(2, "Blue Sky");
ps.setString(3, "Montana");
ps.executeUpdate(); //JDBC queues this for later execution
ps.setInt(1, 25);
ps.setString(2, "Applications");
ps.setString(3, "India");
ps.executeUpdate(); //The queue size equals the batch value of 3
//JDBC sends the requests to the database
ps.setInt(1, 26);
ps.setString(2, "HR");
ps.setString(3, "Mongolia");
ps.executeUpdate(); //JDBC queues this for later execution
ps.close();
...
Note: The execution of the batch always stops with the first element
of the batch that generates an error.
Note:
■ Do not mix standard update batching with Oracle update
batching in the same application. Oracle JDBC driver will
throw exceptions when these are mixed.
■ Disable auto-commit mode if you use either update batching
model. In case an error occurs while you are processing a batch,
this provides you the option of committing or rolling back the
operations that ran successfully prior to the error.
In Oracle JDBC applications, update batching is intended for use with prepared
statements that are being processed repeatedly with different sets of bind values.
The Oracle implementation of standard update batching does not implement true
batching for generic statements and callable statements. Even though Oracle JDBC
supports the use of standard batching for Statement and CallableStatement
objects, you are unlikely to see performance improvement.
For prepared statements, update batching is used to batch multiple runs of the same
statement with different sets of bind parameters. For a PreparedStatement or
OraclePreparedStatement object, the addBatch method takes no input. It simply
adds the operation to the batch using the bind parameters last set by the appropriate
setXXX methods. This is also true for CallableStatement or
OracleCallableStatement objects, but remember that in the Oracle
implementation of standard update batching, you will probably see no performance
improvement in batching callable statements.
For example:
...
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
...
Because a batch is associated with a single prepared statement object, you can batch
only repeated runs of a single prepared statement, as in this example.
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
Starting from Oracle Database 11g Release 1 (11.1), the executeBatch method has
been improved so that when an error occurs in the middle of the batch execution, the
BatchUpdateExecution exception that is thrown contains the position of the error
in the batch. The BatchUpdateExecution.getUpdateCounts method returns an
array of int containing the update counts for the updates that were executed
successfully before this error occurred. So if an error occurs in the 5th element of the
batch, then the size of the array returned is 4 and each value is
Statement.SUCCESS_NO_INFO.
Note:
■ If you are using Oracle update batching in Oracle Database 11g,
then you do not have to clear your batches explicitly in the code
after a rollback. However, it is OK to invoke clearBatch method
after a rollback.
■ If you are using Oracle update batching in an earlier release, then
you have to invoke clearBatch method to clear your batches
explicitly after a rollback.
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
if (...condition...)
{
int[] updateCounts = pstmt.executeBatch();
...
}
else
{
pstmt.clearBatch();
...
}
of -2 indicates that the operation was successful but the number of rows affected
is unknown.
■ For a generic statement batch, the array contains the actual update counts
indicating the number of rows affected by each operation. The actual update
counts can be provided only in the case of generic statements in the Oracle
implementation of standard batching.
■ For a callable statement batch, the server always returns the value 1 as the update
count, irrespective of the number rows affected by each operation.
In your code, upon successful processing of a batch, you should be prepared to handle
either -2, 1, or true update counts in the array elements. For a successful batch
processing, the array contains either all -2, 1, or all positive integers.
Example 23–2 illustrates the use of standard update batching.
PreparedStatement pstmt =
conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.addBatch();
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch();
conn.commit();
pstmt.close();
...
You can process the update counts array to determine if the batch processed
successfully.
After a batch exception, the update counts array can be retrieved using the
getUpdateCounts method of the BatchUpdateException object. This returns an
int array of update counts, just as the executeBatch method does. In the Oracle
implementation of standard update batching, contents of the update counts array are
as follows, after a batch is processed:
■ For a prepared statement batch, it is not possible to know which operation failed.
The array has one element for each operation in the batch, and each element has a
value of -3. According to the JDBC 2.0 specification, a value of -3 indicates that
an operation did not complete successfully. In this case, it was presumably just
one operation that actually failed, but because the JDBC driver does not know
which operation that was, it labels all the batched operations as failures.
You should always perform a ROLLBACK operation in this situation.
■ For a generic statement batch or callable statement batch, the update counts array
is only a partial array containing the actual update counts up to the point of the
error. The actual update counts can be provided because Oracle JDBC cannot use
true batching for generic and callable statements in the Oracle implementation of
standard update batching.
For example, if there were 20 operations in the batch, the first 13 succeeded, and
the 14th generated an exception, then the update counts array will have 13
elements, containing actual update counts of the successful operations.
You can either commit or roll back the successful operations in this situation, as
you prefer.
In your code, upon failed processing of a batch, you should be prepared to handle
either -3 or true update counts in the array elements when an exception occurs. For a
failed batch processing, you will have either a full array of -3 or a partial array of
positive integers.
pstmt.setInt(1, 2000);
pstmt.setString(2, "Milo Mumford");
pstmt.setInt(1, 3000);
pstmt.setString(2, "Sulu Simpson");
pstmt.addBatch(); // Now start a batch
pstmt.setInt(1, 4000);
pstmt.setString(2, "Stan Leland");
pstmt.addBatch();
pstmt.setInt(1, 5000);
pstmt.setString(2, "Amy Feiner");
/*
* Premature batch flush happens here.
*/
pstmt.setInt (1, 22);
pstmt.setString (2, "test22");
int count = pstmt.executeUpdate (); // returns 0
row-prefetch setting to 1, even if you never actually read a value of either of these
types.
Setting the prefetch size can affect the performance of an application. Increasing the
prefetch size will reduce the number of round-trips required to get all the data, but
will increase memory usage. This will depend on the number and size of the columns
in the query and the number of rows expected to be returned. It will also depend on
the memory and CPU loading of the JDBC client machine. The optimum for a
standalone client application will be different from a heavily loaded application
server. Please consider also the speed and latency of the network connection.
Note: Starting from Oracle Database 11g Release 1 (11.1), the Thin
driver can fetch the first prefetch_size number of rows from the
server in the very first roundtrip. This saves one round-trip in select
statements.
If you are migrating an application from earlier releases of Oracle JDBC drivers to 10g
Release 1 (10.1) or later releases of Oracle JDBC drivers, then you should revisit the
optimizations that you had done earlier, because the memory usage and performance
characteristics may have changed substantially.
A common situation that you may encounter is, say, you have a query that selects a
unique key. The query will return only zero or one row. Setting the prefetch size to 1
will decrease memory and CPU usage and cannot increase round-trips. However, you
must be careful to avoid the error of requesting an extra fetch by writing
while(rs.next()) instead of if(rs.next()).
If you are using the JDBC Thin driver, then in the case where only zero or one row is
expected, use the useFetchSizeWithLongColumn connection property, because it
will perform PARSE, EXECUTE, and FETCH in a single round-trip.
Tuning of the prefetch size should be done along with tuning of memory management
in your JVM under realistic loads of the actual application.
Note:
■ Do not mix the JDBC 2.0 fetch size application programming
interface (API) and the Oracle row-prefetching API in your
application. You can use one or the other, but not both.
■ Be aware that setting the Oracle fetch size value can affect not
only queries, but also explicitly refetching rows in a result set
through the result set refreshRow method, which is relevant
for scroll-sensitive/read-only, scroll-sensitive/updatable, and
scroll-insensitive/updatable result sets, and the window size of
a scroll-sensitive result set, affecting how often automatic
refetches are performed. However, the Oracle fetch size value
will be overridden by any setting of the fetch size.
from calls to defineColumnType. Starting from Oracle Database 10g, the JDBC Thin
driver no longer needs the information provided. The JDBC Thin driver achieves
maximum performance without calls to defineColumnType. The JDBC Oracle Call
Interface (OCI) and server-side internal drivers still get better performance when the
application uses defineColumnType.
If your code is used with both the JDBC Thin and OCI drivers, you can disable the
defineColumnType method when using the Thin driver by setting the connection
property disableDefineColumnType to true. Doing this makes
defineColumnType have no effect. Do not set this connection property to true
when using the JDBC OCI or server-side internal drivers.
You can also use defineColumnType to control how much memory the client-side
allocates or to limit the size of variable-length data.
Follow these general steps to define column types for a query:
1. If necessary, cast your statement object to OracleStatement,
OraclePreparedStatement, or OracleCallableStatement, as applicable.
2. If necessary, use the clearDefines method of your Statement object to clear
any previous column definitions for this Statement object.
3. On each column, call the defineColumnType method of your Statement
object, passing it these parameters:
■ Column index (integer)
■ Type code (integer)
Use the static constants of the java.sql.Types class or
oracle.jdbc.OracleTypes class, such as Types.INTEGER,
Types.FLOAT, Types.VARCHAR, OracleTypes.VARCHAR, and
OracleTypes.ROWID. Type codes for standard types are identical in these
two classes.
■ Type name (string)
For structured objects, object references, and arrays, you must also specify the
type name. For example, Employee, EmployeeRef, or EmployeeArray.
■ Maximum field size (integer)
Optionally specify a maximum data length for this column.
You cannot specify a maximum field size parameter if you are defining the
column type for a structured object, object reference, or array. If you try to
include this parameter, it will be ignored.
■ Form of use (short)
Optionally specify a form of use for the column. This can be
OraclePreparedStatement.FORM_CHAR to use the database character set
or OraclePreparedStatement.FORM_NCHAR to use the national character
set. If this parameter is omitted, the default is FORM_CHAR.
For example, assuming stmt is an Oracle statement, use:
stmt.defineColumnType(column_index, typeCode);
If the column is VARCHAR or equivalent and you know the length limit:
stmt.defineColumnType(column_index, typeCode, max_size);
For an NVARCHAR column where the original maximum length is desired and
conversion to the database character set is requested:
stmt.defineColumnType(column_index, typeCode, 0,
OraclePreparedStatement.FORM_CHAR );
Set a maximum field size if you do not want to receive the full default length of
the data. Calling the setMaxFieldSize method of the standard JDBC
Statement class sets a restriction on the amount of data returned. Specifically,
the size of the data returned will be the minimum of the following:
■ The maximum field size set in defineColumnType
■ The maximum field size set in setMaxFieldSize
■ The natural maximum size of the data type
After you complete these steps, use the executeQuery method of the statement to
perform the query.
Example 23–4 illustrates the use of this feature. It assumes you have imported the
oracle.jdbc.* interfaces.
As this example shows, you must cast the Statement object, stmt, to
OracleStatement in the invocation of the defineColumnType method. The
createStatement method of the connection returns an object of type
java.sql.Statement, which does not have the defineColumnType and
clearDefines methods. These methods are provided only in the
OracleStatement implementation.
The define-extensions use JDBC types to specify the desired types. The allowed define
types for columns depend on the internal Oracle type of the column.
All columns can be defined to their natural JDBC types. In most cases, they can be
defined to the Types.CHAR or Types.VARCHAR type code.
Table 23–1 lists the valid column definition arguments you can use in the
defineColumnType method.
It is always valid to use defineColumnType with the original data type of the
column.
This will cause all subsequent getColumns method calls on the connection to include
synonyms. This is similar to setRemarksReporting. Alternatively, you can set the
includeSynonyms connection property. This is similar to the remarksReporting
connection property.
However, bear in mind that if includeSynonyms is true, then the name of the object
returned in the table_name column will be the synonym name, if a synonym exists.
This is true even if you pass the table name to getColumns.
The Java Database Connectivity (JDBC) Oracle Call Interface (OCI) driver connection
pooling functionality is part of the JDBC client. This functionality is provided by the
OracleOCIConnectionPool class.
A JDBC application can have multiple pools at the same time. Multiple pools can
correspond to multiple application servers or pools to different data sources. The
connection pooling provided by the JDBC OCI driver enables applications to have
multiple logical connections, all using a small set of physical connections. Each call on
a logical connection gets routed on to the physical connection that is available at the
time of call.
This chapter contains the following sections:
■ OCI Driver Connection Pooling: Background
■ OCI Driver Connection Pooling and Shared Servers Compared
■ Defining an OCI Connection Pool
■ Connecting to an OCI Connection Pool
■ Sample Code for OCI Connection Pooling
■ Statement Handling and Caching
■ JNDI and the OCI Connection Pool
Note that many more Oracle sessions can be multiplexed over this pool of fewer
shared connections and back-end Oracle processes.
* @return
*
* Notes: Choose a userid and password that can act as proxy for the users
*/
/*
* This will use the user-id, password and connection pool name values set
LATER using the methods setUser, setPassword, setConnectionPoolName.
* @return
*
* Notes:
■ poolConfig.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT,
"2");
As an alternative to the constructor call, you can create an instance of the
OracleOCIConnectionPool class using individual methods to specify the user,
password, and connection string.
OracleOCIConnectionPool cpool = new OracleOCIConnectionPool ( );
cpool.setUser("SCOTT");
cpool.setPassword("TIGER");
cpool.setURL("jdbc:oracle:oci:@(description=(address=(host=
myhost)(protocol=tcp)(port=1521))(connect_data=(INSTANCE_NAME=orcl)))");
cpool.setPoolConfig(poolConfig); // In case you want to specify a different
// configuration other than the default
// values.
Retrieves the number of physical connections that are open. This should be used
only as an estimate and for statistical analysis.
■ int getActiveSize()
Retrieves the number of physical connections that are open and busy. This should
be used only as an estimate and for statistical analysis.
■ boolean isPoolCreated()
Retrieves if the pool has been created. The pool is actually created when
OracleOCIConnection(user, password, url, poolConfig) is called or
when setUser, setPassword, and setURL has been done after calling
OracleOCIConnection().
/*
* For getting a connection to the database.
*
* @param us Connection user-id
* @param p Connection password
* @return connection object
*/
public synchronized OracleConnection getConnection(String us, String p)
throws SQLException
((conPoolAppl)t[0]).startAllThreads ();
try
{
Thread.sleep (200);
}
catch (Exception ea) {}
displayPoolConfig(cpool);
for (int i = 0; i < _maxCount; ++i)
t[i].join ();
}
catch(Exception ex)
{
System.out.println("Error: " + ex);
ex.printStackTrace ();
return;
}
finally
{
for (int i = 0; i < _maxCount; ++i)
if (conn[i] != null)
conn[i].close ();
}
} //end of main
try
{
pstmt = conn.prepareStatement (query);
rs = pstmt.executeQuery ();
while (rs.next ())
{
//System.out.println ("Object name: " +rs.getString (1));
}
}
catch (Exception ea)
{
System.out.println ("Error during execution: " +ea);
ea.printStackTrace ();
}
finally
{
if (rs != null)
rs.close ();
if (pstmt != null)
pstmt.close ();
if (conn != null)
conn.close ();
}
} // end of doQuery (Connection)
■ Interfaces
– AQAgent
Used to represent and identify a user of the queue or a producer or consumer
of the message
– AQMessage
Represents a message that is enqueued or dequeued
– AQMessageProperties
Contains message properties such as Correlation, Sender, Delay and
Expiration, Recipients, and Priority and Ordering
– AQNotificationListener
Is a listener interface for receiving AQ notification events
– AQNotificationRegistration
Represents your interest in being notified when a new message is enqueued in
a particular queue
These classes and interfaces enable you to access an existing queue, create messages,
and enqueue and dequeue messages.
Note: Oracle JDBC drivers do not provide any API to create a queue.
Queues must be created through the DBMS_AQADM PL/SQL package.
See Also: For more information about the APIs, refer to the Javadoc.
Example
Example 25–1 illustrates the use of the new JDBC AQ interface which is new feature of
the JDBC Thin driver in release 11.1. It shows how to enqueue and dequeue from a
RAW type single-consumer and multiple-consumer queue. It also shows how AQ
asynchronous notification works. In this example, the SCOTT user is connecting to the
database. Therefore, in the database, you must grant the following privileges to the
user:
GRANT EXECUTE ON DBMS_AQ to SCOTT;
GRANT EXECUTE ON DBMS_AQADM to SCOTT;
GRANT AQ_ADMINISTRATOR_ROLE TO SCOTT;
GRANT ADMINISTER DATABASE TRIGGER TO SCOTT;
/**
* Single consumer queue demo:
* This method enqueues a dummy message into the RAW_SINGLE_QUEUE queue and
dequeues it.
* Then it registers for AQ notification on this same queue and enqueues a
* message again. The AQ listener will be notified that a new message has
arrived
* in the queue and it will dequeue it.
*/
void demoSingleConsumerQueue(OracleConnection connection) throws SQLException
{
System.out.println("\n ============= Start single consumer queue demo
============= \n");
enqueueDummyMessage(connection,queueName,null);
dequeue(connection,queueName,queueType,null);
connection,queueName);
DemoAQRawQueueListener single_li = new DemoAQRawQueueListener(
queueName,queueType);
reg.addListener(single_li);
enqueueDummyMessage(connection,queueName,null);
connection.commit();
while(single_li.getEventsCount() < 1)
{
try
{ Thread.currentThread().sleep(1000); }
catch (InterruptedException e)
{ }
}
single_li.closeConnection();
connection.unregisterAQNotification(reg);
}
/**
* Multi consumer queue demo:
* This method first registers for AQ notification upon the agent "BLUE". It
* then enqueues a message for "RED" and "BLUE"
*/
void demoMultipleConsumerQueue(OracleConnection connection) throws SQLException
{
System.out.println("\n ============= Start multi consumer queue demo
============= \n");
String queueType = "RAW";
String queueName = USERNAME+".RAW_MULTIPLE_QUEUE";
enqueueDummyMessage(connection,queueName,recipients);
connection.commit();
while(multi_li.getEventsCount() < 1)
{
try
{ Thread.currentThread().sleep(1000); }
catch (InterruptedException e)
{ }
}
dequeue(connection,queueName,queueType,"RED");
multi_li.closeConnection();
connection.unregisterAQNotification(reg);
}
/**
* This method enqueues a dummy message in the queue specified by its name.
*/
public void enqueueDummyMessage(OracleConnection conn,
String queueName,
AQAgent[] recipients) throws SQLException
{
System.out.println("----------- Enqueue start ------------");
// First create the message properties:
AQMessageProperties msgprop = AQFactory.createAQMessageProperties();
msgprop.setCorrelation("mycorrelation");
msgprop.setExceptionQueue("MY_EXCEPTION_QUEUE");
System.out.println(msgprop.toString());
if(mesgId != null)
{
String mesgIdStr = byteBufferToHexString(mesgId,20);
System.out.println("Message ID from enqueue call: "+mesgIdStr);
}
System.out.println("----------- Enqueue done ------------");
}
/**
* This methods dequeues the next available message from the queue specified
* by "queueName".
*/
public void dequeue(OracleConnection conn,
String queueName,
String queueType,
String consumerName
) throws SQLException
{
// dequeue operation:
AQMessage msg = conn.dequeue(queueName,deqopt,queueType);
/**
*
*/
private void setup(Connection conn) throws SQLException
{
doUpdateDatabase(conn,
"BEGIN "+
"DBMS_AQADM.CREATE_QUEUE_TABLE( "+
" QUEUE_TABLE => '"+USERNAME+".RAW_SINGLE_QUEUE_TABLE',
"+
" QUEUE_PAYLOAD_TYPE => 'RAW', "+
" COMPATIBLE => '10.0'); "+
"END; ");
doUpdateDatabase(conn,
"BEGIN "+
"DBMS_AQADM.CREATE_QUEUE( "+
" QUEUE_NAME => '"+USERNAME+".RAW_SINGLE_QUEUE', "+
" QUEUE_TABLE => '"+USERNAME+".RAW_SINGLE_QUEUE_TABLE'); "+
"END; ");
doUpdateDatabase(conn,
"BEGIN "+
" DBMS_AQADM.START_QUEUE('"+USERNAME+".RAW_SINGLE_QUEUE'); "+
"END; ");
tryUpdateDatabase(conn,
"BEGIN "+
" DBMS_AQADM.STOP_QUEUE('"+USERNAME+".RAW_MULTIPLE_QUEUE'); "+
"END; ");
tryUpdateDatabase(conn,
"BEGIN "+
" DBMS_AQADM.DROP_QUEUE_TABLE( "+
" QUEUE_TABLE =>
'"+USERNAME+".RAW_MULTIPLE_QUEUE_TABLE', "+
" FORCE => TRUE); "+
"END; ");
}
/**
* Creates a connection the database.
*/
/**
* Utility method: executes a DML query but doesn't throw any exception if
* an error occurs.
*/
private void tryUpdateDatabase(Connection conn,String sql)
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
stmt.executeUpdate(sql);
}catch(SQLException sqlex)
{
System.out.println("Exception ("+sqlex.getMessage()+") while trying to
execute \""+sql+"\"");
}
finally
{
if(stmt != null)
{
try
{
stmt.close();
}catch(SQLException exx){exx.printStackTrace();}
}
}
}
/**
* Utility method: executes a DML query and throws an exception if
* an error occurs.
*/
private void doUpdateDatabase(Connection conn,String sql) throws SQLException
{
Statement stmt = null;
try
{
stmt = conn.createStatement();
stmt.executeUpdate(sql);
}
finally
{
if(stmt != null)
{
try
{
stmt.close();
}catch(SQLException exx){}
}
}
}
deqopt.setVisibility(AQDequeueOptions.DEQUEUE_IMMEDIATE);
}
AQMessage msg = conn.dequeue(queueName,deqopt,typeName);
byte[] msgId = msg.getMessageId();
if(msgId != null)
{
String mesgIdStr = DemoAQRawQueue.byteBufferToHexString(msgId,20);
System.out.println("ID of message dequeued = "+mesgIdStr);
}
System.out.println(msg.getMessageProperties().toString());
byte[] payload = msg.getPayload();
if(typeName.equals("RAW"))
{
String payloadStr = new String(payload,0,10);
System.out.println("payload.length="+payload.length+", value="+payloadStr);
}
System.out.println("----------- DemoAQRawQueueListener: Dequeue done
-----------");
}
catch(SQLException sqlex)
{
System.out.println(sqlex.getMessage());
}
eventsCount++;
}
public int getEventsCount()
{
return eventsCount;
}
public void closeConnection() throws SQLException
{
conn.close();
}
}
Creating Messages
Before you enqueue a message, you must create the message. An instance of a class
implementing the AQMessage interface represents an AQ message. An AQ message
contains properties (metadata) and a payload (data). Perform the following to create
an AQ message:
1. Create an instance of AQMessageProperties.
2. Set the property attributes.
3. Create the AQ message using the AQMessageProperties object.
4. Set the payload.
AQ Message Properties
The properties of the AQ message are represented by an instance of the
AQMessageProperties interface. You can set or get the following message
properties:
■ Dequeue Attempts Count: Specifies the number of attempts that have been made
to dequeue the message. This property cannot be set.
■ Correlation: Is an identifier supplied by the producer of the message at the time of
enqueuing the message.
■ Delay: Is the number of seconds for which the message is in the WAITING state.
After the specified delay, the message is in the READY state and available for
dequeuing. Dequeuing a message by using the message ID (msgid) overrides the
delay specification.
msgprop.setSender(ag);
msgprop.setRecipientList(recipients);
AQ Message Payload
Depending on the type of the queue, the payload of the AQ message can be specified
using the setPayload method of the AQMessage interface. The following code
snippet illustrates how to set the payload:
...
byte[] rawPayload = new byte[500];
for(int i=0;i<rawPayload.length;i++)
rawPayload[i] = 'b';
mesg.setPayload(new oracle.sql.RAW(rawPayload));
...
You can retrieve the payload of an AQ message using the getPayload method or the
appropriate getXXXPayload method. These methods are defined in the AQMessage
interface.
Enqueuing Messages
After you create a message and set the message properties and payload, you can
enqueue the message using the enqueue method of the OracleConnection
interface. Before you enqueue the message, you can specify some enqueue options.
The AQEnqueueOptions class enables you to specify the following enqueue options:
■ Delivery mode: Specifies the delivery mode. Delivery mode can be set to either
persistent (ENQUEUE_PERSISTENT) or buffered (ENQUEUE_BUFFERED).
■ Retrieve Message ID: Specifies whether or not the message ID has to be retrieved
from the server when the message has been enqueued. By default, the message ID
is not retrieved.
■ Transformation: Specifies a transformation that will be applied before enqueuing
the message. The return type of the transformation function must match the type
of the queue.
■ Visibility: Specifies the transactional behavior of the enqueue request. The default
value for this option is ENQUEUE_ON_COMMIT. It indicates that the enqueue
operation is part of the current transaction. ENQUEUE_IMMEDIATE indicates that
the enqueue operation is an autonomous transaction, which commits at the end of
the operation. For buffered messaging, you must use ENQUEUE_IMMEDIATE.
The following code snippet illustrates how to set the enqueue options and enqueue the
message:
...
// Set the enqueue options
AQEnqueueOptions opt = new AQEnqueueOptions();
opt.setRetrieveMessageId(true);
Dequeuing Messages
Enqueued messages can be dequeued using the dequeue method of the
OracleConnection interface. Before you dequeue a message you must set the
dequeue options. The AQDequeueOptions class enables you to specify the following
dequeue options:
■ Condition: Specifies a conditional expression based on the message properties, the
message data properties, and PL/SQL functions. A dequeue condition is specified
as a Boolean expression using syntax similar to the WHERE clause of a SQL query.
■ Consumer name: If specified, only the messages matching the consumer name are
accessed.
■ Correlation: Specifies a correlation criterion (or search criterion) for the dequeue
operation.
■ Delivery Filter: Specifies the type of message to be dequeued. You dequeue
buffered messages only (DEQUEUE_BUFFERED) or persistent messages only
(DEQUEUE_PERSISTENT), which is the default, or both
(DEQUEUE_PERSISTENT_OR_BUFFERED).
■ Dequeue Message ID: Specifies the message identifier of the message to be
dequeued. This can be used to dequeue a unique message whose ID is known.
■ Dequeue mode: Specifies the locking behavior associated with the dequeue
operation. It can take one of the following values:
– DequeueMode.BROWSE: Message is dequeued without acquiring any lock.
– DequeueMode.LOCKED: Message is dequeued with a write lock that lasts for
the duration of the transaction.
– DequeueMode.REMOVE: (default) Message is dequeued and deleted. The
message can be retained in the queue based on the retention properties.
– DequeueMode.REMOVE_NO_DATA: Message is marked as updated or deleted.
■ Maximum Buffer Length: Specifies the maximum number of bytes that will be
allocated when dequeuing a message from a RAW queue. The default maximum is
DEFAULT_MAX_PAYLOAD_LENGTH but it can be changed to any other nonzero
value. If the buffer is not large enough to contain the entire message, then the
exceeding bytes will be silently ignored.
■ Navigation: Specifies the position of the message that will be retrieved. It can take
one of the following values:
– NavigationOption.FIRST_MESSAGE: The first available message
matching the search criteria is dequeued.
■ Visibility: Specifies whether or not the message is dequeued as part of the current
transaction. It can take one of the following values:
– VisibilityOption.ON_COMMIT: (default) The dequeue operation is part of
the current transaction.
– VisibilityOption.IMMEDIATE: The dequeue operation is an autonomous
transaction that commits at the end of the operation.
■ Wait: Specifies the wait time for the dequeue operation, if none of the messages
matches the search criteria. The default value is DEQUEUE_WAIT_FOREVER
indicating that the operation waits forever. If set to DEQUEUE_NO_WAIT, then the
operation does not wait. If a number is specified, then the dequeue operation
waits for the specified number of seconds.
The following code snippet illustrates how to set the dequeue options and dequeue the
message:
...
// Set the dequeue options
AQDequeueOptions deqopt = new AQDequeueOptions();
deqopt.setRetrieveMessageId(true);
deqopt.setConsumerName(consumerName);
// Dequeue the message
// conn is an OracleConnection object
The Fast Connection Failover mechanism depends on the implicit connection cache
feature. As a result, for Fast Connection Failover to be available, implicit connection
caching must be enabled.
This chapter is divided into the following sections:
■ Overview of Fast Connection Failover
■ Using Fast Connection Failover
■ Understanding Fast Connection Failover
■ Comparison of Fast Connection Failover and TAF
within ons.config is defined in simple name and value pairs. There are three values
that should always be configured within ons.config. The first is localport, the
port that ONS binds to on the localhost interface to talk to local clients. An example of
the localport configuration is the following:
localport=4100
The second value is remoteport, the port that ONS binds to on all interfaces for
talking to other ONS daemons. An example of the remoteport configuration is the
following:
remoteport=4200
The third value specifies nodes, a list of other ONS daemons to talk to. Node values
are given as a comma-delimited list of either host names or IP addresses plus ports.
Note that the port value that is given is the remote port that each ONS instance is
listening on. In order to maintain an identical file on all nodes, the host:port of the
current ONS node can also be listed in the nodes list. It will be ignored when reading
the list.
The nodes listed in the nodes line correspond to the individual nodes in the RAC
instance. Listing the nodes ensures that the middle-tier node can communicate with
the RAC nodes. At least one middle-tier node and one node in the RAC instance must
be configured to see one another. As long as one node on each side is aware of the
other, all nodes are visible. You need not list every single cluster and middle-tier node
in the ONS config file of each Oracle RAC node. In particular, if one ONS config file
cluster node is aware of the middle tier, then all nodes in the cluster are aware of it.
An example of the nodes configuration is the following:
nodes=myhost.example.com:4200,123.123.123.123:4200
There are also several optional values that can be provided in ons.config.
The first optional value is a loglevel. This specifies the level of messages that should
be logged by ONS. This value is an integer that ranges from 1, which indicates least
messages logged, to 9, which indicates most messages logged. The default value is 3.
The following is an example:
loglevel=3
The second optional value is a logfile name. This specifies a log file that ONS
should use for logging messages. The default value for logfile is
$ORACLE_HOME/opmn/logs/ons.log. The following is an example:
logfile=/private/oraclehome/opmn/logs/myons.log
The third optional value is a walletfile name. A wallet file is used by the Oracle
Secure Sockets Layer (SSL) to store SSL certificates. If a wallet file is specified to ONS,
it will use SSL when communicating with other ONS instances and require SSL
certificate authentication from all ONS instances that try to connect to it. This means
that if you want to turn on SSL for one ONS instance, then you must turn it on for all
instances that are connected. This value should point to the directory where your
ewallet.p12 file is located. The following is an example:
walletfile=/private/oraclehome/opmn/conf/ssl.wlt/default
One optional value is reserved for use on the server-side. useocr=on is used to tell
ONS to store all Oracle RAC nodes and port numbers in Oracle Cluster Registry
(OCR) instead of in the ONS configuration file. Do not use this option on the
client-side.
The ons.config file allows blank lines and comments on lines that begin with the
number sign (#).
After configuring ONS, you start the ONS daemon with the onsctl command. It is
the user's responsibility to make sure that an ONS daemon is running at all times.
to the middle-tier. When running on a cluster, always configure the ONS hosts and
ports not by using the ONS configuration files but using racgons. The racgons
command stores the ONS hosts and ports in OCR, where every node can see it. That
way, you do not need to edit a file on every node to change the configuration, just run
a single command on one of the cluster nodes.
The racogns command enables you to specify hosts and ports on one node, then
propagate your changes among all nodes in a cluster. The command takes two forms:
racgons add_config hostname:port [hostname:port] [hostname:port] ...
racgons remove_config hostname[:port] [hostname:port] [hostname:port] ...
The add_config version adds the listed host name(s), the remove_config version
removes them. Both commands propagate the changes among all instances in a cluster.
If multiple port numbers are configured for a host, the specified port number is
removed from hostname. If only hostname is specified, all port numbers for that
host are removed.
The remoteONSConfig parameter is a list of name and value pairs of the form
name=value that are separated by a new line character (\n). name can be one of
nodes, walletfile, or walletpassword. This parameter should specify at least
the nodes ONS configuration attribute, which is a list of host:port pairs, each pair
separated by comma (,). The hosts and ports denote the remote ONS daemons
available on the Oracle RAC nodes.
SSL could be used in communicating with the ONS daemons when the walletfile
attribute is specified as an Oracle wallet file. In such cases, if the walletpassword
attribute is not specified, single sign-on (SSO) would be assumed.
Following are a few examples, assuming ods is an OracleDataSource instance:
ods.setONSConfiguration("nodes=racnode1.example.com:4200,racnode2.example.com:4200
");
ods.setONSConfiguration("nodes=racnode1:4200,racnode2:4200\nwalletfile=/mydir/Wall
et\nwalletpassword=mypasswd");
ods.setONSConfiguration("nodes=racnode1:4200,racnode2:4200\nwalletfile=/mydir/conf
/Wallet");
...
Note: The application should not try to roll back the transaction. The
transaction was already rolled back in the database by the time the
application received the exception.
How It Works
Under Fast Connection Failover, each connection in the cache maintains a mapping to
a service, instance, database, and host name.
When a database generates an Oracle RAC event, that event is forwarded to the JVM
in which JDBC is running. A daemon thread inside the JVM receives the Oracle RAC
event and passes it on to the Connection Cache Manager. The Connection Cache
Manager then throws SQL exceptions to the applications affected by the Oracle RAC
event.
A typical failover scenario may work like the following:
1. A database instance fails, leaving several stale connections in the cache.
2. The RAC mechanism in the database generates an Oracle RAC event which is sent
to the JVM containing JDBC.
3. The daemon thread inside the JVM finds all the connections affected by the Oracle
RAC event, notifies them of the closed connection through SQL exceptions, and
rolls back any open transactions.
4. Each individual connection receives a SQL exception and must retry.
Note:
■ TAF is always active and does not have to be set.
■ TAF does not work with the OCI connection pool.
re-authenticated on the server side, but open cursors in the OCI can continue
fetching. This implies that the client-side logic maintains fetch-state of each open
cursor.
■ FO_NONE
Is equivalent to FAILOVER_MODE=NONE in the tnsnames.ora file
CONNECT_DATA flags. This is the default, in which no failover functionality is
used. This can also be explicitly specified to prevent failover from happening.
Additionally, FO_TYPE_UNKNOWN implies that a bad failover type was returned
from the OCI driver.
■ FO_BEGIN
Indicates that failover has detected a lost connection and failover is starting.
■ FO_END
Indicates successful completion of failover.
■ FO_ABORT
Indicates that failover was unsuccessful and there is no option of retrying.
■ FO_REAUTH
Indicates that a user handle has been re-authenticated.
■ FO_ERROR
Indicates that failover was temporarily unsuccessful, but it gives the application
the opportunity to handle the error and retry failover. The usual method of error
handling is to issue the sleep method and retry by returning the value
FO_RETRY.
■ FO_RETRY
Indicates that the application should retry failover.
■ FO_EVENT_UNKNOWN
Indicates a bad failover event.
TAF Callbacks
TAF callbacks are used in the event of the failure of one database connection, and
failover to another database connection. TAF callbacks are callbacks that are registered
in case of failover. The callback is called during the failover to notify the JDBC
application of events generated. The application also has some control of failover.
This part provides information about transaction management in Oracle Java Database
Connectivity (JDBC). It includes a chapter that discusses the Oracle JDBC
implementation of distributed transactions.
Part VII contains the following chapter:
■ Chapter 28, "Distributed Transactions"
28
Distributed Transactions
This chapter discusses the Oracle Java Database Connectivity (JDBC) implementation
of distributed transactions. These are multiphased transactions, often using multiple
databases, which must be committed in a coordinated way. There is also related
discussion of XA, which is a general standard, and not specific to Java, for distributed
transactions.
The following topics are discussed:
■ Overview of Distributed Transactions
■ XA Components
■ Error Handling and Optimizations
■ Implementing a Distributed Transaction
■ Native-XA in Oracle JDBC Drivers
For further introductory and general information about distributed transactions, refer
to the Sun Microsystems specifications for the JDBC 2.0 Optional Package and the Java
Transaction API (JTA).
If none of these rules is applicable, then the mode does not change.
Oracle XA Packages
Oracle supplies the following three packages that have classes to implement
distributed transaction functionality according to the XA standard:
■ oracle.jdbc.xa
■ oracle.jdbc.xa.client
■ oracle.jdbc.xa.server
Classes for XA data sources, XA connections, and XA resources are in both the client
package and the server package. An abstract class for each is in the top-level
package. The OracleXid and OracleXAException classes are in the top-level
oracle.jdbc.xa package, because their functionality does not depend on where the
code is running.
In middle-tier scenarios, you will import OracleXid, OracleXAException, and the
oracle.jdbc.xa.client package.
If you intend your XA code to run in the target Oracle Database, however, you will
import the oracle.jdbc.xa.server package instead of the client package.
If code that will run inside a target database must also access remote databases, then
do not import either package. Instead, you must fully qualify the names of any classes
that you use from the client package to access a remote database or from the
server package to access the local database. Class names are duplicated between
these packages.
XA Components
This section discusses the XA components, that is, standard XA interfaces specified in
the JDBC 2.0 Optional Package, and the Oracle classes that implement them. The
following topics are covered:
■ XADatasource Interface and Oracle Implementation
■ XAConnection Interface and Oracle Implementation
■ XAResource Interface and Oracle Implementation
■ OracleXAResource Method Functionality and Input Parameters
Note:
■ Because there must always be a one-to-one correlation between
XA connection instances and OracleXAResource instances,
an OracleXAResource instance is implicitly closed when the
associated XA connection instance is closed.
■ If a transaction is opened by a given OracleXAResource
instance, then it must also be closed by the same
OracleXAResource instance.
start
Starts work on behalf of a transaction branch, associating the transaction branch with a
distributed transaction.
void start(Xid xid, int flags)
■ XAResource.TMRESUME
Resume the transaction branch specified by xid.
■ OracleXAResource.ORATMSERIALIZABLE
Start a serializable transaction with transaction ID xid.
■ OracleXAResource.ORATMREADONLY
Start a read-only transaction with transaction ID xid.
■ OracleXAResource.ORATMREADWRITE
Start a read/write transaction with transaction ID xid.
■ OracleXAResource.ORATRANSLOOSE
Start a loosely coupled transaction with transaction ID xid.
TMNOFLAGS, TMJOIN, TMRESUME, ORATMSERIALIZABLE, ORATMREADONLY, and
ORATMREADWRITE are defined as static members of the XAResource interface and
OracleXAResource class. ORATMSERIALIZABLE, ORATMREADONLY, and
ORATMREADWRITE are the isolation-mode flags. The default isolation behavior is READ
COMMITTED.
Note:
■ Instead of using the start method with TMRESUME, the
transaction manager can cast to OracleXAResource and use
the resume(Xid xid) method, an Oracle extension.
■ If you use TMRESUME, then you must also use TMNOMIGRATE,
as in start(xid, XAResource.TMRESUME |
OracleXAResource.TMNOMIGRATE). This prevents the
application from receiving the error ORA 1002: fetch out
of sequence.
■ If you use the isolation-mode flags incorrectly, then an
exception with code XAER_INVAL is raised. Furthermore, you
cannot use isolation-mode flags when resuming a global
transaction, because you cannot set the isolation level of an
existing transaction. If you try to use the isolation-mode flags
when resuming a transaction, then an external Oracle exception
with code ORA-24790 is raised.
■ In order to avoid Error ORA 1002: fetch out of
sequence, include the TMNOMIGRATE flag as part of the
start method. For example:
start(xid, XAResource.TMSUSPEND |
OracleXAResource.TMNOMIGRATE);
end
Ends work on behalf of the transaction branch specified by xid, disassociating the
transaction branch from its distributed transaction.
void end(Xid xid, int flags)
Note:
■ Instead of using the end method with TMSUSPEND, the
transaction manager can cast to OracleXAResource and use
the suspend(Xid xid) method, an Oracle extension.
■ This XA functionality to suspend a transaction provides a way
to switch between various transactions within a single JDBC
connection. You can use the XA classes to accomplish this, even
if you are not in a distributed transaction environment and
would otherwise have no need for the XA classes.
■ If you use TMSUSPEND, then you must also use TMNOMIGRATE,
as in end(xid, XAResource.TMSUSPEND |
OracleXAResource.TMNOMIGRATE). This prevents the
application from receiving the error ORA 1002: fetch out
of sequence.
■ In order to avoid Error ORA 1002: fetch out of
sequence, include the TMNOMIGRATE flag as part of the end
method. For example:
end(xid, XAResource.TMSUSPEND |
OracleXAResource.TMNOMIGRATE);
prepare
Prepares the changes performed in the transaction branch specified by xid. This is the
first phase of a two-phase commit operation, to ensure that the database is accessible
and that the changes can be committed successfully.
int prepare(Xid xid)
Note:
■ Always call the end method on a branch before calling the
prepare method.
■ If there is only one transaction branch in a distributed
transaction, then there is no need to call the prepare method.
You can call the OracleXAResource commit method without
preparing first.
commit
Commits prepared changes in the transaction branch specified by xid. This is the
second phase of a two-phase commit and is performed only after all transaction
branches have been successfully prepared.
void commit(Xid xid, boolean onePhase)
rollback
Rolls back prepared changes in the transaction branch specified by xid.
void rollback(Xid xid)
forget
Tells the resource manager to forget about a heuristically completed transaction
branch.
public void forget(Xid xid)
recover
The transaction manager calls this method during recovery to obtain the list of
transaction branches that are currently in prepared or heuristically completed states.
public Xid[] recover(int flag)
The resource manager returns zero or more Xids for the transaction branches that are
currently in a prepared or heuristically completed state. If an error occurs during the
operation, then the resource manager throws the appropriate XAException.
isSameRM
To determine if two OracleXAResource instances correspond to the same resource
manager, call the isSameRM method from one OracleXAResource instance,
specifying the other OracleXAResource instance as input. In the following example,
presume xares1 and xares2 are OracleXAResource instances:
boolean sameRM = xares1.isSameRM(xares2);
fId is an integer value for the format identifier, gId[] is a byte array for the global
transaction identifier, and bId[] is a byte array for the branch qualifier.
The Xid interface specifies the following getter methods:
■ public int getFormatId()
■ public byte[] getGlobalTransactionId()
■ public type[] getBranchQualifier()
public OracleXAException()
The error value is an error code that combines an Oracle SQL error value and an XA
error value. The JDBC driver determines exactly how to combine the Oracle and XA
error values.
The OracleXAException class has the following methods:
■ public int getOracleError()
This method returns the Oracle SQL error code pertaining to the exception, a
standard ORA error number or 0 if there is no Oracle SQL error.
■ public int getXAError()
This method returns the XA error code pertaining to the exception. XA error
values are defined in the javax.transaction.xa.XAException class.
XA Error Handling
The following example uses the OracleXAException class to process an XA
exception:
try {
...
...Perform XA operations...
...
} catch(OracleXAException oxae) {
int oraerr = oxae.getOracleError();
System.out.println("Error " + oraerr);
}
catch(XAException xae)
{...Process generic XA exception...}
In case the XA operations did not throw an Oracle-specific XA exception, the code
drops through to process a generic XA exception.
Oracle XA Optimizations
Oracle JDBC has functionality to improve performance if two or more branches of a
distributed transaction use the same database instance, meaning that the
OracleXAResource instances associated with these branches are associated with the
same resource manager.
In such a circumstance, the prepare method of only one of these
OracleXAResource instances will return XA_OK or will fail. The rest will return
XA_RDONLY, even if updates are made. This allows the transaction manager to
implicitly join all the transaction branches and commit or roll back, in case of failure,
the joined transaction through the OracleXAResource instance that returned XA_OK
or failed.
The transaction manager can use the OracleXAResource class isSameRM method to
determine if two OracleXAResource instances are using the same resource manager.
This way it can interpret the meaning of XA_RDONLY return values.
Note that for simplicity, this example combines code that would typically be in a
middle tier with code that would typically be in a transaction manager, such as the
OracleXAResource method invocations and the creation of transaction IDs.
For brevity, the specifics of creating transaction IDs and performing SQL operations
are not shown here. The complete example is shipped with the product.
This example performs the following sequence:
1. Start transaction branch #1.
2. Start transaction branch #2.
3. Execute DML operations on branch #1.
4. Execute DML operations on branch #2.
5. End transaction branch #1.
6. End transaction branch #2.
7. Prepare branch #1.
8. Prepare branch #2.
9. Commit branch #1.
10. Commit branch #2.
// You need to import the java.sql package to use JDBC
import java.sql.*;
import javax.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.*;
import oracle.jdbc.xa.OracleXid;
import oracle.jdbc.xa.OracleXAException;
import oracle.jdbc.xa.client.*;
import javax.transaction.xa.*;
class XA4
{
public static void main (String args [])
throws SQLException
{
try
{
String URL1 = "jdbc:oracle:oci:@";
// You can put a database name after the @ sign in the connection URL.
String URL2 ="jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))";
// Create first DataSource and get connection
OracleDataSource ods1 = new OracleDataSource();
ods1.setURL(URL1);
ods1.setUser("scott");
ods1.setPassword("tiger");
Connection conna = ods1.getConnection();
try
{
// Drop the test table
stmta.execute ("drop table my_table");
}
catch (SQLException e)
{
// Ignore an error here
}
try
{
// Create a test table
stmta.execute ("create table my_table (col1 int)");
}
catch (SQLException e)
{
// Ignore an error here too
}
try
{
// Drop the test table
stmtb.execute ("drop table my_tab");
}
catch (SQLException e)
{
// Ignore an error here
}
try
{
// Create a test table
stmtb.execute ("create table my_tab (col1 char(30))");
}
catch (SQLException e)
{
// Ignore an error here too
}
oxds2.setURL("jdbc:oracle:thin:@(description=(address=(host=dlsun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))");
oxds2.setUser("scott");
oxds2.setPassword("tiger");
if (prp1 == XAResource.XA_OK)
if (do_commit)
oxar1.commit (xid1, false);
else
oxar1.rollback (xid1);
if (prp2 == XAResource.XA_OK)
if (do_commit)
oxar2.commit (xid2, false);
else
oxar2.rollback (xid2);
// Close connections
conn1.close();
conn1 = null;
conn2.close();
conn2 = null;
pc1.close();
pc1 = null;
pc2.close();
pc2 = null;
rset.close();
rset = null;
rset.close();
rset = null;
stmta.close();
stmta = null;
stmtb.close();
stmtb = null;
conna.close();
conna = null;
connb.close();
connb = null;
OCI Native XA
Native XA is enabled through the use of the tnsEntry and nativeXA properties of
the OracleXADataSource class.
See Also: Table 8–2, " Oracle Extended Data Source Properties" on
page 8-4 for explanation of these properties.
Exception Handling
When using the Native XA feature in distributed transactions, it is recommended that
the application simply check for XAException or SQLException, rather than
OracleXAException or OracleSQLException.
Thin Native XA
Like the JDBC OCI driver, the JDBC Thin driver also provides support for Native XA.
However, the JDBC Thin driver provides support for Native XA by default. This is
unlike the case of the JDBC OCI driver in which the support for Native XA is not
enabled by default.
You can disable Native XA by calling setNativeXA(false) on the XA data source
as follows:
...
// Create a XADataSource instance
OracleXADataSource oxds = new OracleXADataSource();
...
// Disabling Native XA
oxds.setNativeXA(false);
...
For example, you may need to disable Native XA as a workaround for a bug in the
Native XA code.
This part discusses the database management and diagnosability support in Oracle
Java Database Connectivity (JDBC) drivers.
Part VIII contains the following chapters:
■ Chapter 29, "Database Management"
■ Chapter 30, "Diagnosability in JDBC"
■ Chapter 31, "JDBC DMS Metrics"
29
Database Management
Oracle Database 11g Release 1 (11.1) provides many new features for managing the
database. This chapter describes the following:
■ Database Startup and Shutdown
■ Database Change Notification
2. Connect to database as SYSDBA and run the following commands from SQL*Plus:
GRANT SYSDBA TO system;
PASSWORD system
Changing password for system
New password: password
Retype new password: password
To start a database instance using the startup method, the application must first
connect to the database as a SYSDBA or SYSOPER in the PRELIM_AUTH mode, which is
the only connection mode that is permitted when the database is down. You can do
this by setting the new connection property prelim_auth to true. In the PRELIM_
AUTH mode, you can only start up a database instance that is down. You cannot run any
SQL statements in this mode.
The startup method only starts up a database instance. It does not mount it nor open
it. You have to reconnect as SYSDBA or SYSOPER, but without the PRELIM_AUTH
mode, and run the following commands to mount and open the database instance:
ALTER DATABASE MOUNT
ALTER DATABASE OPEN
Note: The startup method will start up the database using the
server parameter file. Oracle JDBC drivers do not support database
startup using the client parameter file.
The startup method takes a parameter that specifies the database startup option.
Table 29–1 lists the supported database startup options. These options are defined in
the oracle.jdbc.OracleConnection.DatabaseStartupMode class.
The shutdown method enables you to shut down an Oracle Database instance. To use
this method, you must be connected to the database as a SYSDBA or SYSOPER.
Like the startup method, the shutdown method also takes a parameter. In this case,
the parameter specifies the database shutdown option. Table 29–2 lists the supported
database shutdown options. These options are defined in the
oracle.jdbc.OracleConnection.DatabaseShutdownMode class.
For shutdown options other than ABORT and FINAL, you must call the shutdown
method again with the FINAL option to actually shut down the database.
Example
Example 29–1 illustrates the use of the startup and shutdown methods.
prop1.setProperty("user","sys");
prop1.setProperty("password","manager");
prop1.setProperty("internal_logon","sysdba");
ds1.setConnectionProperties(prop1);
ds1.setURL(DB_URL);
OracleConnection conn1 = (OracleConnection)ds1.getConnection();
Statement stmt = conn1.createStatement();
stmt.executeUpdate("ALTER DATABASE MOUNT");
stmt.executeUpdate("ALTER DATABASE OPEN");
stmt.close();
conn1.close();
Creating a Registration
Creating a registration is a one-time process and is done outside of the currently used
transaction. The API for creating a registration in the server is executed in its own
transaction and is committed immediately. You need a JDBC connection to create a
registration, however, the registration is not attached to the connection. You can close
the connection after creating a registration, and the registration survives. In an Oracle
RAC environment, a registration is a persistent entity that exists on all nodes. If a node
goes down, then the registration continues to exist and will be notified when the tables
change.
There are two ways to create a registration:
■ The JDBC-style of registration: Use the JDBC driver to create a registration on the
server. The JDBC driver launches a new thread that listens to notifications from the
server (through a dedicated channel) and converts these notification messages into
Java events. The driver then notifies all the listeners registered with this
registration.
■ The PL/SQL-style of registration: If you want a PL/SQL stored procedure to
handle the notifications, then create a PL/SQL-style registration. As in the
JDBC-style of registration, the JDBC drivers enable you to attach statements
(queries) to this registration. However the JDBC drivers do not get notifications
from the server because the notifications are handled by the PL/SQL stored
procedure.
See: Refer to the Javadoc for more information about the APIs.
...
// conn is a OracleConnection object.
// prop is a Properties object containing the registration options.
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotifictaion(prop);
...
Statement stmt = conn.createStatement();
// associating the query with the registration
((OracleStatement)stmt).setDatabaseChangeRegistration(dcr);
// any query that will be executed with the 'stmt' object will be associated with
// the registration 'dcr' until 'stmt' is closed or
// '((OracleStatement)stmt).setDatabaseChangeRegistration(null);' is executed.
...
Note: The listener code must not slow down the JDBC notification
mechanism. If the code is time-consuming, for example, if it refreshes
the data cache by querying the database, then it needs to be executed
within its own thread.
You can attach a listener to a registration using the addListener method. The
following code snippet illustrates how to attach a listener to a registration:
...
// conn is a OracleConnection object.
// prop is a Properties object containing the registration options.
DatabaseChangeRegistration dcr = conn.registerDatabaseChangeNotifictaion(prop);
...
// Attach the listener to the registration.
// Note: DCNListener is a custom listener and not a predefined or standard
// lsiener
DCNListener list = new DCNListener();
dcr.addListener(list);
...
Deleting a Registration
You need to explicitly unregister a registration to delete it from the server and release
the resources in the driver. You can unregister a registration using a connection
different from one that was used for creating it. To unregister a registration, you can
use the unregisterDatabaseChangeNotification method defined in
oracle.jdbc.OracleConnection.
You must pass the DatabaseChangeRegistration object as a parameter to this
method. This method deletes the registration from the server and the driver and closes
the listener socket.
If the registration was created outside of JDBC, say using PL/SQL, then you must pass
the registration ID instead of the DatabaseChangeRegistration object. The
method will delete the registration from the server, however, it does not free any
resources in the driver.
Example
Example 29–2 illustrates how to use the Database Change Notification feature. In this
example, the SCOTT user is connecting to the database. Therefore in the database you
need to grant the following privilege to the user:
grant change notification to scott;
System.exit(1);
}
URL = argv[0];
DBChangeNotification demo = new DBChangeNotification();
try
{
demo.run();
}
catch(SQLException mainSQLException )
{
mainSQLException.printStackTrace();
}
}
// if connected through the VPN, you need to provide the TCP address of the
client.
// For example:
// prop.setProperty(OracleConnection.NTF_LOCAL_HOST,"14.14.13.12");
// Ask the server to send the ROWIDs as part of the DCN events (small
performance
// cost):
prop.setProperty(OracleConnection.DCN_NOTIFY_ROWIDS,"true");
try
{
// add the listenerr:
DCNDemoListener list = new DCNDemoListener(this);
dcr.addListener(list);
synchronized( this )
{
// The following code modifies the dept table and commits:
try
{
OracleConnection conn2 = connect();
conn2.setAutoCommit(false);
Statement stmt2 = conn2.createStatement();
stmt2.executeUpdate("insert into dept (deptno,dname) values ('45','cool
dept')",Statement.RETURN_GENERATED_KEYS);
ResultSet autoGeneratedKey = stmt2.getGeneratedKeys();
if(autoGeneratedKey.next())
System.out.println("inserted one row with
ROWID="+autoGeneratedKey.getString(1));
stmt2.executeUpdate("insert into dept (deptno,dname) values ('50','fun
dept')",Statement.RETURN_GENERATED_KEYS);
autoGeneratedKey = stmt2.getGeneratedKeys();
if(autoGeneratedKey.next())
System.out.println("inserted one row with
ROWID="+autoGeneratedKey.getString(1));
stmt2.close();
conn2.commit();
conn2.close();
}
catch(SQLException ex) { ex.printStackTrace(); }
// At the end: close the registration (comment out these 3 lines in order
// to leave the registration open).
OracleConnection conn3 = connect();
conn3.unregisterDatabaseChangeNotification(dcr);
conn3.close();
}
/**
* Creates a connection the database.
*/
OracleConnection connect() throws SQLException
{
OracleDriver dr = new OracleDriver();
Properties prop = new Properties();
prop.setProperty("user",DBChangeNotification.USERNAME);
prop.setProperty("password",DBChangeNotification.PASSWORD);
return (OracleConnection)dr.connect(DBChangeNotification.URL,prop);
}
}
/**
* DCN listener: it prints out the event details in stdout.
*/
class DCNDemoListener implements DatabaseChangeListener
{
DBChangeNotification demo;
DCNDemoListener(DBChangeNotification dem)
{
demo = dem;
}
public void onDatabaseChangeNotification(DatabaseChangeEvent e)
{
Thread t = Thread.currentThread();
System.out.println("DCNDemoListener: got an event ("+this+" running on thread
"+t+")");
System.out.println(e.toString());
synchronized( demo ){ demo.notify();}
}
}
This code will also work with Oracle Database 10g Release 2 (10.2). This code uses
table registration. That is, when you register a SELECT query, what you register is the
name of the tables involved and not the query itself. In other words, you might select
one single row of a table and if another row is updated, you will be notified although
the result of your query has not changed.
When using Oracle Database 11g, you can use a different option, the query registration
with finer granularity. This can be done by setting the DCN_QUERY_CHANGE_
NOTIFICATION option.
In this example, if you leave the registration open instead of closing it, then the
database change notification thread continues to run. Now if you run a DML query
that changes the SCOTT.DEPT table and commit it, say from SQL*Plus, then the Java
program prints the notification.
In Oracle Database 11g, the JDBC drivers have been enhanced by including new
diagnosabilty features and improving existing diagnosabilty features. These features
enable users to diagnose problems in the applications that use Oracle JDBC drivers
and the problems in the drivers themselves. They also reduce the effort required to
develop and maintain Java applications that access an Oracle Database instance using
Oracle JDBC drivers.
Oracle JDBC drivers provide the following diagnosabilty features that enable users to
identify and fix problems in their JDBC applications:
■ Logging
■ Diagnosability Management
Logging
This feature logs information about events that occur when JDBC driver code runs.
Events can include user-visible events, such as SQL exceptions, running of SQL
statements, and detailed JDBC internal events, such as entry to and exit from internal
JDBC methods. Users can enable this feature to log specific events or all the events.
Prior to Oracle Database 11g, JDBC drivers supported J2SE 2.0 and 3.0. These versions
of J2SE did not include java.util.logging. Therefore, the logging feature
provided by JDBC driver releases prior to Oracle Database 11g, differs from the
java.util.logging framework.
In Oracle Database 11g, the JDBC drivers no longer support J2SE 2.0 and 3.0.
Therefore, the logging feature of JDBC drivers makes full use of the standard
java.util.logging package. The enhanced logging system makes effective use of
log levels to enable users to restrict log output to things of interest. It logs specific
classes of information more consistently, making it easier for the user to understand
the log file.
This feature does not introduce new APIs or configuration files. Only new parameters
are added to the existing standard java.util.logging configuration file. These
parameters are identical in use to the existing parameters and are intrinsic to using
java.util.logging.
Note: Oracle does not guarantee the exact content of the generated
logs. To a large extent the log content is dependent on the details of
the implementation. The details of the implementation change with
every release, and therefore, the exact content of the logs are likely to
change from release to release.
Enabling Logging
You can enable logging in the following ways:
■ Setting a Java system property
You can enable logging by setting the oracle.jdbc.Trace system property.
java -Doracle.jdbc.Trace=true ...
Setting the system property enables global logging, which means that logging is
enabled for the entire application. You can use global logging if you want to debug
the entire application, or if you cannot or do not want to change the source code of
the application.
■ Programmatically
You can programmatically enable or disable logging in the following way:
First, get the ObjectName of the Diagnosability MBean. The ObjectName is
com.oracle.jdbc:type=diagnosability,name=<loader>
// enable logging
mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled", true));
// disable logging
mbs.setAttribute(name, new javax.management.Attribute("LoggingEnabled",
false));
Programmatic enabling and disabling of logging helps you to control what parts
of your application need to generate log output.
Configuring Logging
To generate a useful and detailed log, you must configure java.util.logging. This
can be done either through a configuration file or programmatically.
A sample configuration file, OracleLog.properties, is provided as part of the
JDBC installation in the demo directory. It contains basic information about how to
configure java.util.logging and provides some initial settings that you can start
with. You may use this sample file as is, edit the file and use it, rename the file and edit
it, or create an entirely new file of any name.
To use a configuration file, you must identify it to the Java run-time. This can be done
by setting a system property. For example:
java -Djava.util.logging.config.file=/jdbc/demo/OracleLog.properties.
You can use the default OracleLog.properties file. It may or may not get you the
desired output. You can also create and use your own configuration file by following
these steps:
1. Create a file named myConfig.properties. You can use any name you choose.
2. Insert the following lines of text in the file:
.level=SEVERE
oracle.jdbc.level=INFO
oracle.jdbc.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
filepath is the path of the folder where you have saved the
myConfig.properties file.
You can also configure java.util.logging to dump the log output into a file. To
do so, modify the configuration file as follows:
.level=SEVERE
oracle.jdbc.level=INFO
oracle.jdbc.handlers=java.util.logging.FileHandler
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.pattern=jdbc.log
java.util.logging.FileHandler.count=1
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
This will generate exactly the same log output and save it in a file named jdbc.log in
the current directory.
You can control the amount of detail by changing the level settings. The defined levels
from the least detailed to the most detailed are the following:
■ OFF
Turns off logging.
■ SEVERE
Logs SQLExceptions and internal errors.
■ WARNING
Logs SQLWarnings and bad but not fatal internal conditions.
■ INFO
Logs infrequent but significant events and errors. It produces a relatively low
volume of log messages.
■ CONFIG
Logs SQL strings that are executed.
■ FINE
Logs the entry and exit to every public method providing a detailed trace of JDBC
operations. It produces a fairly high volume of log messages.
■ FINER
Note: Levels more detailed than FINE generate huge log volumes.
In the example provided earlier, to reduce the amount of detail, change the
java.util.logging.FileHandler.level setting from ALL to INFO:
java.util.logging.FileHandler.level=INFO
Although you can, it is not necessary to change the level of the oracle.jdbc logger.
Setting the FileHandler level will control what log messages are dumped into the
log file.
Using Loggers
Setting the level reduces all the logging output from JDBC. However, sometimes you
need a lot of output from one part of the code and very little from other parts. To do
that you must understand more about loggers.
Loggers exist in a tree structure defined by their names. The root logger is named "",
the empty string. If you look at the first line of the configuration file you see
.level=SEVERE. This is setting the level of the root logger. The next line is
oracle.jdbc.level=INFO. This sets the level of the logger named oracle.jdbc.
The oracle.jdbc logger is a member of the logger tree. Its parent is named oracle.
The parent of the oracle logger is the root logger (the empty string).
Logging messages are sent to a particular logger, for example, oracle.jdbc. If the
message passes the level check at that level, then the message is passed to the handler
at that level, if any, and to the parent logger. So a log message sent to oracle.log is
compared against that logger's level, INFO if you are following along. If the level is the
same or less (less detailed) then it is sent to the FileHandler and to the parent logger,
'oracle'. Again it is checked against the level. If as in this case, the level is not set then it
uses the parent level, SEVERE. If the message level is the same or less it is passed to the
handler, which there is not one, and sent to the parent. In this case the parent in the
root logger.
All this tree structure did not help you reduce the amount of output. What will help is
that the JDBC drivers use several subloggers. If you restrict the log messages to one of
the subloggers you will get substantially less output. The loggers used by Oracle JDBC
drivers include the following:
■ oracle.jdbc
■ oracle.jdbc.driver
■ oracle.jdbc.pool
■ oracle.jdbc.rowset
■ oracle.jdbc.xa
■ oracle.sql
Note: The loggers used by the drivers may vary from release to
release.
An Example
Suppose you want to trace what is happening in the oracle.sql component and
also want to capture some basic information about the rest of the driver. This is a more
complex use of logging. The following are the entries in the config file:
#
# set levels
#
.level=SEVERE
oracle.level=INFO
oracle.jdbc.driver.level=INFO
oracle.jdbc.pool.level=OFF
oracle.jdbc.util.level=OFF
oracle.sql.level=INFO
#
# configure handlers
#
oracle.handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
Sets the logging level of the root logger to SEVERE. We do not want to see any logging
from other, non-Oracle components unless something fails badly. Therefore, we set the
default level for all loggers to SEVERE. Each logger inherits its level from its parent
unless set explicitly. By setting the level of the root logger to SEVERE we ensure that all
other loggers inherit that level except for the ones we set otherwise.
oracle.level=INFO
We want log output from both the oracle.sql and oracle.jdbc.driver loggers.
Their common ancestor is oracle. Therefore, we set the level of the oracle logger to
INFO. We will control the detail more explicitly at lower levels.
oracle.jdbc.driver.level=INFO
We are using a DataSource in our test and do not want to see all of that logging.
Therefore, we turn it OFF.
oracle.jdbc.util.level=OFF
We do not want to see the logging from the oracle.jdbc.util package. If we were
using XA or rowsets we would turn them off as well.
oracle.sql.level=INFO
We are going to dump everything to stderr. When we run the test we will redirect
stderr to a file.
java.util.logging.ConsoleHandler.level=INFO
We want to dump everything to the console which is System.err. In this case, we are
doing the filtering with the loggers rather than the handler.
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
Security Concerns
When full logging is enabled, it is almost guaranteed that all sensitive information will
be exposed in the log files. This is intrinsic to the logging feature. However, only
certain JDBC JAR files include the JDBC logging feature. The following JAR files
include full logging and should not be used in a sensitive environment:
■ ojdbc5_g.jar
■ ojdbc5dms_g.jar
■ ojdbc6_g.jar
■ ojdbc6dms_g.jar
The following JAR files include a limited logging capability:
■ ojdbc5dms.jar
■ ojdbc6dms.jar
Note: Database user names and passwords do not appear in log files
created by these JAR files. However, sensitive user data that is part of
a SQL statement, a defined value, or a bind value can appear in a log
created using one of these JAR files.
Diagnosability Management
The JDBC diagnosability management feature introduces an MBean,
oracle.jdbc.driver.OracleDiagnosabilityMBean. This MBean provides
means to enable and disable JDBC logging.
See Also: Refer to the JDBC JavaDoc for information about the
OracleDiagnosabilityMBean API.
In future releases, the MBean will be enhanced to provide additional statistics about
JDBC internals.
Security Concerns
This feature can enable JDBC logging. Enabling JDBC logging does not require any
special permission. However, once logging is enabled, generating any log output
requires the standard Java permission LoggingPermission. Without this
permission, any JDBC operation that would generate log output will throw a security
exception. This is a standard Java mechanism.
There are two kinds of metrics, end-to-end metrics and Dynamic Monitoring Service
(DMS) metrics. End-to-end metrics are used for tagging application activity from the
entry into the application code through JDBC to the database and back. DMS metrics
are used to measure the performance of application components. Customer use of
end-to-end metrics in JDBC is generally discouraged.
This chapter discusses the DMS metrics generated by Oracle JDBC 11.1 the in
following sections:
■ Overview of JDBC DMS Metrics
■ Determining the Type of Metric to Be Generated
■ Generating the SQLText Metric
■ Accessing DMS Metrics Using JMX
There is only one list of statement metrics that is generated for both consolidated and
individual statement metrics. The only difference between these two lists is the
aggregation of the statements. When individual statement metrics are generated, one
set of metrics is generated for each distinct statement object created by the JDBC
driver. On the other hand, when consolidated statement metrics are generated, all
statements created by a given connection use the same set of statement metrics. For
example, consider an 'execute' phase event. If individual statement metrics are used,
then each statement created will have a distinct 'execute' phase event. So, from two
such statements, it will be possible to distinguish the execution statistics for the two
separate statements. If one has an execution time of 1 second and the other an
execution time of 3 seconds, then there will be two distinct 'execute' phase events, one
with a total time and average of 1 second and the other with a total time and average
of 3 seconds. But, if consolidated statement metrics are used, all statements will use
the single 'execute' phase event common to the connection. So, from two such
statements created by the same connection, it will not be possible to distinguish the
execution statistics for the two statements. If one has an execution time of 1 second
and the other an execution time of 3 seconds, then the common 'execute' phase event
will report a total execution time of 4 seconds and an average of 2 seconds.
Whether or not the SQLText metric will be generated is independent of the use of the
type of statement metrics used, that is, individual statement metrics or consolidated
statement metrics.
This part consists of appendixes that discuss Java Database Connectivity (JDBC)
reference information, tips for coding JDBC applications, JDBC error messages, and
troubleshooting JDBC applications.
Part IX contains the following appendixes:
■ Appendix A, "Reference Information"
■ Appendix B, "Coding Tips"
■ Appendix C, "JDBC Error Messages"
■ Appendix D, "Troubleshooting"
A
Reference Information
Note:
■ The type UROWID is not supported.
■ The oracle.sql.Datum class is abstract. The value passed to
a parameter of type oracle.sql.Datum must be of the Java
type corresponding to the underlying SQL type. Likewise, the
value returned by a method with return type
oracle.sql.Datum must be of the Java type corresponding
to the underlying SQL type.
Table A–3 describes Oracle JDBC support for the ANSI-supported SQL data types.
Table A–4 describes Oracle JDBC driver support for SQL User-Defined types.
Table A–5 describes Oracle JDBC driver support for PL/SQL data types. Note that
PL/SQL data types include these categories:
■ Scalar types
■ Scalar character types, which includes BOOLEAN and DATE data types
■ Composite types
■ Reference types
■ Large object (LOB) types
Note:
■ The types NATURAL, NATURALn, POSITIVE, POSITIVEn, and
SIGNTYPE are subtypes of BINARY INTEGER.
■ The types DEC, DECIMAL, DOUBLE PRECISION, FLOAT, INT,
INTEGER, NUMERIC, REAL, and SMALLINT are subtypes of
NUMBER.
■ The types NCHAR and NVARCHAR2 are supported indirectly.
There is no corresponding java.sql.Types type, but if your
application calls formOfUse(NCHAR), then these types can be
accessed. Refer to "NCHAR, NVARCHAR2, NCLOB and the
defaultNChar Property in JDK 1.5" on page 19-3 for details.
Date Literals
The JDBC drivers support date literals in SQL statements written in the format:
{d 'yyyy-mm-dd'}
Where yyyy-mm-dd represents the year, month, and day. For example:
{d '1995-10-22'}
The JDBC drivers will replace this escape clause with the equivalent Oracle
representation: "22 OCT 1995".
The following code snippet contains an example of using a date literal in a SQL
statement.
// Connect to the database
// You can put a database name after the @ sign in the connection URL.
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
// Create a Statement
Statement stmt = conn.createStatement ();
// Select the ename column from the emp table where the hiredate is Jan-23-1982
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {d '1982-01-23'}");
Time Literals
The JDBC drivers support time literals in SQL statements written in the format:
{t 'hh:mm:ss'}
where, hh:mm:ss represents the hours, minutes, and seconds. For example:
{t '05:10:45'}
The JDBC drivers will replace this escape clause with the equivalent Oracle
representation: "05:10:45".
If the time is specified as:
{t '14:20:50'}
Then the equivalent Oracle representation would be "14:20:50", assuming the server is
using a 24-hour clock.
This code snippet contains an example of using a time literal in a SQL statement.
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp WHERE hiredate = {t '12:00:00'}");
Timestamp Literals
The JDBC drivers support timestamp literals in SQL statements written in the format:
{ts 'yyyy-mm-dd hh:mm:ss.f...'}
Scalar Functions
Oracle JDBC drivers do not support all scalar functions. To find out which functions
the drivers support, use the following methods supported by the Oracle-specific
oracle.jdbc.OracleDatabaseMetaData class and the standard Java
java.sql.DatabaseMetadata interface:
■ getNumericFunctions()
Returns a comma-delimited list of math functions supported by the driver. For
example, ABS, COS, SQRT.
■ getStringFunctions()
Returns a comma-delimited list of string functions supported by the driver. For
example, ASCII, LOCATE.
■ getSystemFunctions()
Returns a comma-delimited list of system functions supported by the driver. For
example, DATABASE, USER.
■ getTimeDateFunctions()
Returns a comma-delimited list of time and date functions supported by the
driver. For example, CURDATE, DAYOFYEAR, HOUR.
// Select the empno column from the emp table where the ename starts with '_'
ResultSet rset = stmt.executeQuery
("SELECT empno FROM emp WHERE ename LIKE '&_%' {ESCAPE '&'}");
Outer Joins
Oracle JDBC drivers do not support the outer join syntax. The workaround is to use
Oracle outer join syntax:
Instead of:
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT ename, dname
FROM {OJ dept LEFT OUTER JOIN emp ON dept.deptno = emp.deptno}
ORDER BY ename");
Function calls:
{ ? = call procedure_name (argument1, argument2,...) }
The following code is the output that prints the comparable SQL syntax.
{call foo(?, ?)} => BEGIN foo(:1, :2); END;
{? = call bar (?, ?)} => BEGIN :1 := bar (:2, :3); END;
{d '1998-10-22'} => TO_DATE ('1998-10-22', 'YYYY-MM-DD')
{t '16:22:34'} => TO_DATE ('16:22:34', 'HH24:MI:SS')
{ts '1998-10-22 16:22:34'} => TO_TIMESTAMP ('1998-10-22 16:22:34', 'YYYY-MM-DD
HH24:MI:SS.FF')
CursorName
Oracle JDBC drivers do not support the get getCursorName and setCursorName
methods, because there is no convenient way to map them to Oracle constructs. Oracle
recommends using ROWID instead.
See Also: "Oracle ROWID Type" on page 4-13 for more information
about how to use and manipulate ROWIDs.
SQLWarning Class
The java.sql.SQLWarning class provides information about a database access
warning. Warnings typically contain a description of the warning and a code that
identifies the warning. Warnings are silently chained to the object whose method
caused it to be reported. Oracle JDBC drivers generally do not support SQLWarning.
As an exception to this, scrollable result set operations do generate SQL warnings, but
the SQLWarning instance is created on the client, not in the database.
This capability to bind by name using the setXXX methods is not part of the JDBC
specification, and Oracle does not support it. The JDBC drivers can throw a
SQLException or produce unexpected results. Starting from Oracle Database 10g
JDBC drivers, bind by name is supported using the setXXXAtName methods.
The bound values are not copied by the drivers until you call the execute method.
So, changing the bound value before calling the execute method could change the
bound value. For example, consider the folllowing code snippet:
PreparedStatement p;
.......
Date d = new Date(1181676033917L);
p.setDate(1, d);
d.setTime(0);
p.executeUpdate();
Performance Optimization
You can significantly enhance the performance of your JDBC programs by using any of
these features:
■ Disabling Auto-Commit Mode
■ Standard Fetch Size and Oracle Row Prefetching
■ Standard and Oracle Update Batching
■ Statement Caching
■ Mapping Between Built-in SQL and Java Types
In auto-commit mode, the COMMIT operation occurs either when the statement
completes or the next execute occurs, whichever comes first. In the case of statements
returning a ResultSet object, the statement completes when the last row of the
Result Set has been retrieved or when the Result Set has been closed. In more complex
cases, a single statement can return multiple results as well as output parameter
values. Here, the COMMIT occurs when all results and output parameter values have
been retrieved.
If you disable auto-commit mode with a setAutoCommit(false) call, then you
must manually commit or roll back groups of operations using the commit or
rollback method of the connection object.
Example
The following example illustrates loading the driver and connecting to the database.
Because new connections are in auto-commit mode by default, this example shows
how to disable auto-commit. In the example, conn represents the Connection object,
and stmt represents the Statement object.
// Connect to the database
// You can put a database host name after the @ sign in the connection URL.
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:oci:@");
ods.setUser("scott");
ods.setPassword("tiger");
Connection conn = ods.getConnection();
// Create a Statement
Statement stmt = conn.createStatement ();
...
Statement Caching
Statement caching improves performance by caching executable statements that are
used repeatedly, such as in a loop or in a method that is called repeatedly. Applications
use the statement cache to cache statements associated with a particular physical
connection. When you enable Statement caching, a statement object is cached when
you call the close method. Because each physical connection has its own cache,
multiple caches can exist if you enable Statement caching for multiple physical
connections.
When you enable Statement caching on a connection cache, the logical connections
benefit from the Statement caching that is enabled on the underlying physical
connection. If you try to enable Statement caching on a logical connection held by a
connection cache, then this will throw an exception.
Table B–1 Mapping of SQL Data Types to Java Classes that Represent SQL Data Types
ORACLE Mapping - Java Classes
SQL Data Type Representing SQL Data Types
CHAR oracle.sql.CHAR
VARCHAR2 oracle.sql.CHAR
DATE oracle.sql.DATE
DECIMAL oracle.sql.NUMBER
DOUBLE PRECISION oracle.sql.NUMBER
FLOAT oracle.sql.NUMBER
INTEGER oracle.sql.NUMBER
REAL oracle.sql.NUMBER
RAW oracle.sql.RAW
LONG RAW oracle.sql.RAW
REF CURSOR java.sql.ResultSet
CLOB LOCATOR oracle.sql.CLOB
BLOB LOCATOR oracle.sql.BLOB
BFILE oracle.sql.BFILE
nested table oracle.sql.ARRAY
varray oracle.sql.ARRAY
Table B–1 (Cont.) Mapping of SQL Data Types to Java Classes that Represent SQL Data
ORACLE Mapping - Java Classes
SQL Data Type Representing SQL Data Types
SQL object value If there is no entry for the object value in the type map:
■ oracle.sql.STRUCT
If there is an entry for the object value in the type map:
■ customized Java class
REF to SQL object type class that implements oracle.sql.SQLRef, typically by
extending oracle.sql.REF
This mapping provides the most efficient conversion between SQL and Java data
representations. It stores the usual representations of SQL data as byte arrays. It avoids
re-formatting the data. It is information-preserving. This Oracle mapping is the most
efficient type-mapping for applications that "shovel" data from SQL to Java, or vice
versa.
The most efficient way to access numeric data is as primitive Java types like int,
float, long, and double. However, the range of values of these types do not exactly
match the range of values of the SQL NUMBER data type. As a result, there may be
some loss of information.
All character data is converted to the UCS2 character set of Java. The most efficient
way to access character data is as java.lang.String. In worst case, this can cause a
loss of information when two or more characters in the database character set map to a
single UCS2 character. In Oracle Database 11g, all characters in the character set map
to the characters in the UCS2 character set. However, some characters do map to
surrogate pairs.
This appendix briefly discusses the general structure of Java Database Connectivity
(JDBC) error messages, then lists general JDBC error messages and TTC error
messages that Oracle JDBC drivers can return. The appendix is organized as follows:
■ General Structure of JDBC Error Messages
■ General JDBC Messages
■ Native XA Messages
■ TTC Messages
Each of the message lists is first sorted by ORA number, and then alphabetically.
This indicates that the exception was thrown during a call to the next method (of a
result set object).
In some cases, the user can find the same information in a stack trace.
Native XA Messages
The following sections cover the JDBC error messages that are specific to the Native
XA feature:
■ Native XA Messages Sorted by ORA Number
■ Native XA Messages Sorted in Alphabetic Order
TTC Messages
This section lists TTC error messages, first sorted by the ORA number and then in
alphabetic order in the following subsections:
■ TTC Messages Sorted by ORA Number
■ TTC Messages Sorted in Alphabetic Order
Common Problems
This section describes some common problems that you might encounter while using
Oracle JDBC drivers. These problems include:
■ Memory Consumption for CHAR Columns Defined as OUT or IN/OUT Variables
■ Memory Leaks and Running Out of Cursors
■ Boolean Parameters in PL/SQL Stored Procedures
■ Opening More Than 16 OCI Connections for a Process
■ Using statement.cancel
■ Using JDBC with Firewalls
Troubleshooting D-1
Common Problems
initialization file, or that the per-process file descriptors limit was exceeded. It is
important to note that one JDBC-OCI connection can use more than one file descriptor
(it might use anywhere between 3 and 4 file descriptors).
If the server allows more than 16 processes, then the problem could be with the
per-process file descriptor limit. The possible solution would be to increase this limit.
Using statement.cancel
The JDBC standard method Statement.cancel attempts to cleanly stop the
execution of a SQL statement by sending a message to the database. In response, the
database stops execution and replies with an error message. The Java thread that
invoked Statement.execute waits on the server, and continues execution only
when it receives the error reply message invoked by the other thread's call to
Statement.cancel.
As a result, Statement.cancel relies on the correct functioning of the network and
the database. If either the network connection is broken or the database server is hung,
the client does not receive the error reply to the cancel message. Frequently, when the
server process dies, JDBC receives an IOException that frees the thread that invoked
Statement.execute. In some circumstances, the server is hung, but JDBC does not
receive an IOException. Statement.cancel does not free the thread that initiated
the Statement.execute.
When JDBC does not receive an IOException, Oracle Net may eventually time out
and close the connection. This causes an IOException and frees the thread. This
process can take many minutes. For information about how to control this time-out,
see the description of the readTimeout property for
OracleDatasource.setConnectionProperties. You can also tune this time-out
with certain Oracle Net settings. See the Oracle Database Net Services Administrator's
Guide for more information.
The JDBC standard method Statement.setQueryTimeout relies on
Statement.cancel. If execution continues longer than the specified time-out
interval, then the monitor thread calls Statement.cancel. This is subject to all the
same limitations described previously. As a result, there are cases when the time-out
does not free the thread that invoked Statement.execute.
The length of time between execution and cancellation is not precise. This interval is
no less than the specified time-out interval but can be several seconds longer. If the
application has active threads running at high priority, then the interval can be
arbitrarily longer. The monitor thread runs at high priority, but other high priority
threads may keep it from running indefinitely. Note that the monitor thread is started
only if there are statements executed with non zero time-out. There is only one
monitor thread that monitors all Oracle JDBC statement execution.
Statement.cancel and Statement.setQueryTimeout are not supported in the
server-side internal driver. The server-side internal driver runs in the single-threaded
server process; the Oracle JVM implements Java threads within this single-threaded
process. If the server-side internal driver is executing a SQL statement, then no Java
thread can call Statement.cancel. This also applies to the Oracle JDBC monitor
thread.
Troubleshooting D-3
Basic Debugging Procedures
■ If you are using connection caching or connection pooling, then always set the
inactivity timeout value on the connection cache to be shorter than the firewall idle
timeout value.
■ Pass oracle.net.READ_TIMEOUT as connection property to enable read timeout
on socket. The timeout value is in milliseconds.
■ For both JDBC OCI and JDBC Thin drivers, use net descriptor to connect to the
database and specify the ENABLE=BROKEN parameter in the DESCRIPTION clause
in the connect descriptor. Also, set a lower value for tcp_keepalive_interval.
■ Enable Oracle Net DCD by setting SQLNET.EXPIRE_TIME=1 in the sqlnet.ora
file on the server-side.
Note: The trace facility uses a large amount of disk space and
might have significant impact upon system performance. Therefore,
enable tracing only when necessary.
Client-Side Tracing
Set the following parameters in the SQLNET.ORA file on the client system.
TRACE_LEVEL_CLIENT
Purpose:
Turns tracing on/off to a certain specified level.
Default Value:
0 or OFF
Available Values:
■ 0 or OFF - No trace output
■ 4 or USER - User trace information
■ 10 or ADMIN - Administration trace information
■ 16 or SUPPORT - WorldWide Customer Support trace information
Example:
TRACE_LEVEL_CLIENT=10
TRACE_DIRECTORY_CLIENT
Purpose:
Specifies the destination directory of the trace file.
Default Value:
ORACLE_HOME/network/trace
Example:
UNIX: TRACE_DIRECTORY_CLIENT=/oracle/traces
Windows: TRACE_DIRECTORY_CLIENT=C:\ORACLE\TRACES
TRACE_FILE_CLIENT
Purpose:
Specifies the name of the client trace file.
Default Value:
SQLNET.TRC
Example:
TRACE_FILE_CLIENT=cli_Connection1.trc
TRACE_UNIQUE_CLIENT
Purpose:
Gives each client-side trace a unique name to prevent each trace file from being
overwritten with the next occurrence of a client trace. The PID is attached to the end of
the file name.
Default Value:
OFF
Example:
TRACE_UNIQUE_CLIENT = ON
Troubleshooting D-5
Basic Debugging Procedures
Server-Side Tracing
Set the following parameters in the SQLNET.ORA file on the server system. Each
connection will generate a separate file with a unique file name.
TRACE_LEVEL_SERVER
Purpose:
Turns tracing on/off to a certain specified level.
Default Value:
0 or OFF
Available Values:
■ 0 or OFF - No trace output
■ 4 or USER - User trace information
■ 10 or ADMIN - Administration trace information
■ 16 or SUPPORT - WorldWide Customer Support trace information
Example:
TRACE_LEVEL_SERVER=10
TRACE_DIRECTORY_SERVER
Purpose:
Specifies the destination directory of the trace file.
Default Value:
ORACLE_HOME/network/trace
Example:
TRACE_DIRECTORY_SERVER=/oracle/traces
TRACE_FILE_SERVER
Purpose:
Specifies the name of the server trace file.
Default Value:
SERVER.TRC
Example:
TRACE_FILE_SERVER= svr_Connection1.trc
Index-1
cancel() method, 4-21 using, 5-4
cancelling using multiple managers, 5-5
SQL statements, D-3 writing the connection string, 5-5
cancelRowUpdates() method (result set), 17-12 connection properties, 8-8
casting return values, 11-10 put() method, 8-10
catalog arguments (DatabaseMetaData), A-12 connection string
CHAR columns Connection Manager, 5-5
using setFixedCHAR() to match in connections
WHERE, 11-13 read-only, B-4
character sets, 4-13 constants for SQL types, 4-23
checksums CREATE DIRECTORY statement
code example, 9-9 for BFILEs, 14-17
setting parameters in Java, 9-9 CREATE TABLE statement
support by OCI drivers, 9-7 to create BFILE columns, 14-17
support by Thin driver, 9-8 to create BLOB, CLOB columns, 14-9
CLASSPATH environment variable, specifying, 2-3 CREATE TYPE statement, 13-20
clearBatch() method, 23-10 create() method
clearDefines() method, 23-17 for ORADataFactory interface, 13-15
CLOB createDescriptor() method, 13-5
class, 4-8 createStatement(), 20-3
creating and populating, 14-8 createStatement() method, 20-7
introduction, 14-1 createTemporary() method, 14-13
locators, 14-2 CursorName
getting from result set, 14-3 limitations, A-11
passing to callable statements, 14-4 cursors, D-2
passing to prepared statement, 14-4 custom collection classes
locators, selecting, 4-9 and JPublisher, 16-14
manipulating data, 14-10 defined, 16-1, 16-13
reading data, 14-5, 14-6 custom Java classes, 4-3
writing data, 14-7, 14-8 defined, 13-1
close method, 20-9 custom object classes
close(), 20-3 creating, 13-6
close() method, D-2 defined, 13-1
for caching statements, 20-5, 20-6 custom reference classes
closeWithKey(), 20-3 and JPublisher, 15-5
closeWithKey() method, 20-7 defined, 15-1, 15-5
CMAN.ORA file, creating, 5-4
CODE, parameter for APPLET tag, 5-8
D
CODEBASE, parameter for APPLET tag, 5-9
collections data conversions, 11-3
defined, 16-1 LONG, 12-2
collections (nested tables and arrays), 16-5 LONG RAW, 12-2
column types data sources
defining, 23-17 creating and connecting (with JNDI), 8-6
redefining, 23-15 creating and connecting (without JNDI), 8-6
commit a distributed transaction branch, 28-11 Oracle implementation, 8-2
commit changes to database, 2-13 properties, 8-2
commit() method, 4-21 standard interface, 8-2
CONCUR_READ_ONLY result sets, 17-5 data streaming
CONCUR_UPDATABLE result sets, 17-5 avoiding, 12-5
concurrency types in result sets, 17-3 data type classes, 4-5
CONNECT / feature, 9-21 data type mappings, 11-1
connection data types
closing, 2-13 Java, 11-1
opening, 2-8 Java native, 11-1
connection attributes, 21-6 JDBC, 11-1
connection cache properties, 21-8 Oracle SQL, 11-1
Connection Manager database
installing, 5-4 connecting
starting, 5-4 from an applet, 5-2
Index-2
via multiple Connection Managers, 5-5 running statements, 4-27
with server-side internal driver, 7-1 Double.NaN
connection testing, 2-5 restrictions on use, 4-9
database specifiers, 8-11 driverType, 8-4
database URL
including userid and password, 2-9
E
database URL, specifying, 2-8
database URLs encryption
and database specifiers, 8-11 code example, 9-9
DatabaseMetaData calls, A-12 overview, 9-6
DatabaseMetaData class, A-9 setting parameters in Java, 9-9
datasources, 8-1 support by OCI drivers, 9-7
and JNDI, 8-6 to 8-7 support by Thin driver, 9-8
DATE class, 4-9 end a distributed transaction branch, 28-10
DBMS_SERVICE.SERVICE_TIME, 22-2 Enterprise Java Beans (EJB), 18-8
DBMS_SERVICE.THROUGHPUT, 22-2 environment variables
debugging JDBC programs, D-4 specifying, 2-3
DEFAULT_CHARSET character set value, 4-12 errors
defaultConnection() method, 7-1 general JDBC message structure, C-1
defineColumnType() method, 4-22, 12-5, 23-17 general JDBC messages, listed, C-1
DELETE in a result set, 17-11 processing exceptions, 2-15
deleteRow() method (result set), 17-11 TTC messages, listed, C-10
deletesAreDetected() method (database exceptions
metadata), 17-18 retrieving error code, 2-16
distributed transaction ID component, 28-12 retrieving message, 2-16
distributed transactions retrieving SQL state, 2-16
branch qualifier, 28-12 execute() method, 18-10
check for same resource manager, 28-12 executeBatch() method, 23-10
commit a transaction branch, 28-11 executeUpdate() method, 23-6
components and scenarios, 28-2 explicit Statement caching
concepts, 28-2 definition of, 20-3
distributed transaction ID component, 28-12 null data, 20-8
end a transaction branch, 28-10 extensions to JDBC, Oracle, 4-1, 11-1, 13-1, 15-1, 16-1,
example of implementation, 28-15 23-1
forget, 28-12 external changes (result set)
global transaction identifier, 28-12 defined, 17-16
ID format identifier, 28-12 seeing, 17-17
obtain the list of transaction brances during visibility vs. detection, 17-18
recovery, 28-12 external file
Oracle XA connection implementation, 28-6 defined, 12-6
Oracle XA data source implementation, 28-6
Oracle XA ID implementation, 28-12 F
Oracle XA optimizations, 28-15
Oracle XA resource implementation, 28-7 failover
overview, 28-1 fast connection, 26-1 to 26-8
prepare a transaction branch, 28-11 Fast Connection Failover, 26-1 to 26-8
roll back a transaction branch, 28-11 fast connection failover
start a transaction branch, 28-8 prerequisites, 26-2
transaction branch ID component, 28-12 fetch direction in result sets, 17-10
XA connection interface, 28-6 fetch size, result sets, 17-15
XA data source interface, 28-6 FilteredRowSet, 18-12
XA error handling, 28-14 finalizer methods, D-2
XA exception classes, 28-13 firewalls
XA ID interface, 28-12 configuring for applets, 5-6
XA resource functionality, 28-8 connection string, 5-7
XA resource interface, 28-7 described, 5-6
DML Returning, 4-4, 4-26 required rule list items, 5-6
example, 4-27 using with applets, 5-6
limitations, 4-28 Firewalls, using with JDBC, D-3
Oracle-specific APIs, 4-26 floating-point compliance, A-12
Index-3
Float.NaN getOracleObject() method
restrictions on use, 4-9 casting return values, 11-10
format identifier, transaction ID, 28-12 return types, 11-6, 11-7
forward-only result sets, 17-2 using in callable statement, 11-7
freeTemporary() method, 14-13 using in result set, 11-6
function call syntax, SQL92 syntax, A-10 getOraclePlsqlIndexTable() method, 4-29, 4-32
argument
int paramIndex, 4-33
G
code example, 4-33
getARRAY() method, 16-6 getORAData() method, 13-15, 13-16
getArray() method, 16-4, 16-6 getPassword() method, 8-3
using type maps, 16-8 getPlsqlIndexTable() method, 4-29, 4-32, 4-33
getAsciiStream() method arguments
for reading CLOB data, 14-5 Class primitiveType, 4-34
getAttributes() method int paramIndex, 4-33
used by Structs, 13-10 code example, 4-32, 4-34
getAutoBuffering() method getProcedureColumns() method, 23-19
of the oracle.sql.ARRAY class, 16-4 getProcedures() method, 23-19
of the oracle.sql.STRUCT class, 13-6 getREF() method, 15-4
getBaseType() method, 16-9 getRow() method (result set), 17-9
getBaseTypeName() method, 15-2 getRowPrefetch() method, 4-22
getBinaryStream() method, 12-3 getSQLState() method (SQLException), 2-16
for reading BFILE data, 14-16 getSQLTypeName() method, 13-3, 16-9
for reading BLOB data, 14-5 getStatementCacheSize() method
getBytes() method, 4-7, 12-4 code example, 20-5
getCallWithKey(), 20-3 getStatementWithKey(), 20-3
getCallWithKey() method, 20-7, 20-8 getStatementWithKey() method, 20-7, 20-8
getCharacterStream() method getString() method, 4-13
for reading CLOB data, 14-5 to get ROWIDs, 4-14
getColumns() method, 23-19 getStringFunctions() method, A-9
getConcurrency() method (result set), 17-7 getStringWithReplacement() method, 4-13
getConnection() method, 7-1, 24-6 getSTRUCT() method, 13-4
getCursor() method, 4-15, 4-16 getSubString() method
getCursorName() method for reading CLOB data, 14-5, 14-6
limitations, A-11 getSystemFunctions() method, A-9
getDefaultExecuteBatch() method, 4-21, 23-5 getTimeDateFunctions() method, A-9
getDefaultRowPrefetch() method, 4-21 getTransactionIsolation() method, B-4
getDescriptor() method, 13-3 getType() method (result set), 17-7
getDirAlias() method, 14-18 getTypeMap() method, 13-9
getErrorCode() method (SQLException), 2-16 getUpdateCounts() method
getExecuteBatch() method, 23-4, 23-5 (BatchUpdateException), 23-13
getFetchSize() method, 17-15 getValue() method, 15-3
getJavaSQLConnection() method, 13-3 for object references, 15-3
getJavaSqlConnection() method, 4-25 getXXX() methods
getMessage() method (SQLException), 2-16 casting return values, 11-10
getName() method, 14-18 for specific data types, 11-9
getNumericFunctions() method, A-9 Oracle extended properties, 8-5
getObject() method global transaction identifier (distributed
casting return values, 11-10 transactions), 28-12
for object references, 15-3 global transactions, 28-1
for ORAData objects, 13-15 globalization, 19-1 to ??
for SQLInput streams, 13-11 using, 19-1
for SQLOutput streams, 13-12
for Struct objects, 13-4
return types, 11-6, 11-7
H
to get BFILE locators, 14-15 HEIGHT, parameter for APPLET tag, 5-8
to get Oracle objects, 13-4 HTML tags, to deploy applets, 5-8
used with ORAData interface, 13-17
getOracleArray() method, 16-6, 16-9
getOracleAttributes() method, 13-3, 13-4
Index-4
I basic program, 2-7
data types, 11-1
IEEE 754 floating-point compliance, A-12
defined, 1-1
implicit connection cache, 21-1
importing packages, 2-8
example, 21-5
limitations of Oracle extensions, A-11
implicit Statement caching
sample files, 2-4
definition of, 20-2
testing, 2-5
Least Recently Used (LRU) algorithm, 20-2
version support, 3-1 to 3-6
IN OUT parameter mode, 4-31
JDBC 2.0 support
IN parameter mode, 4-29
data type support, 3-2
INSERT in a result set, 17-13
extended feature support, 3-2
INSERT INTO statement
introduction, 3-1
for creating BFILE columns, 14-17
JDK 1.2.x vs. JDK 1.1.x, 3-1, 3-2
insertRow() method (result set), 17-14
standard feature support, 3-2
insertsAreDetected() method (database
JDBC drivers
metadata), 17-18
applets, 5-2
installation
choosing a driver for your needs, 1-4
directories and files, 2-2
common features, 1-2
verifying on the client, 2-2
common problems, D-1
Instant Client feature, 6-3
determining driver version, 2-5
integrity
introduction, 1-1
code example, 9-9
restrictions, D-2
overview, 9-6
SQL92 syntax, A-6
setting parameters in Java, 9-9
JDBC mapping (for attributes), 13-31
support by OCI drivers, 9-7
JdbcCheckup program, 2-5
support by Thin driver, 9-8
JDBCRowSet, 18-9
internal changes (result set)
JDBCSpy, D-6
defined, 17-16
JDBCTest, D-6
seeing, 17-17
JDeveloper, 1-5
isAfterLast() method (result set), 17-9
JDK
isBeforeFirst() method (result set), 17-9
versions supported, 1-5
isFirst() method (result set), 17-9
JNDI
isLast() method (result set), 17-9
and datasources, 8-6 to 8-7
isSameRM() (distributed transactions), 28-12
looking up data source, 8-7
isTemporary() method, 14-13
overview of Oracle support, 8-1
registering data source, 8-7
J JoinRowSet, 18-13
JPublisher, 13-17, 13-30
Java
JPublisher utility, 13-7
compiling and running, 2-4
creating custom collection classes, 16-13
data types, 11-1
creating custom Java classes, 13-30
native data types, 11-1
creating custom reference classes, 15-5
stored procedures, 2-15
SQL type categories and mapping options, 13-31
stream data, 12-1
type mapping modes and settings, 13-31
Java Naming and Directory Interface (JNDI), 8-1
type mappings, 13-31
Java Sockets, 1-3
JVM, 7-1
Java Virtual Machine (JVM), 7-1
java.math, Java math packages, 2-8
java.sql, JDBC packages, 2-8 K
java.sql.Connection interface KPRB driver
close method, 20-9 overview, 1-3
java.sql.SQLException() method, 2-15 relation to the SQL engine, 7-1
java.sql.Statement interface session context, 7-4
close method, 20-9 testing, 7-4
java.sql.Struct class transaction context, 7-4
getSQLTypeName() method, 13-3 URL for, 7-2
java.sql.Types class, 23-17
java.util.Map class, 16-9
java.util.Properties, 24-5 L
JDBC LD_LIBRARY_PATH environment variable,
and IDEs, 1-5
Index-5
specifying, 2-4 thrown when converting Double.NaN and
LDAP Float.NaN, 4-9
and SSL, 8-13 NUMBER class, 4-9
Least Recently Used (LRU) algorithm, 20-2, 24-5
libheteroxa11_g.so shared library, 28-20
O
libheteroxa11.so shared library, 28-20
LIKE escape characters, SQL92 syntax, A-9 object references
limitations on setBytes() and setString(), use of accessing object values, 15-3, 15-5
streams to avoid, 12-9 described, 15-1
load balancing advisory, 22-2 passing to prepared statements, 15-4
LOB retrieving, 15-3
defined, 12-6 retrieving from callable statement, 15-4
introduction, 14-1 updating object values, 15-3, 15-5
locators, 14-2 object-JDBC mapping (for attributes), 13-31
reading data, 14-5 OCI driver
LOB locators described, 1-3
getting from callable statements, 14-3 ODBCSpy, D-6
passing, 14-4 ODBCTest, D-6
locators ONS
getting for BFILEs, 14-15 configuring, 26-2 to 26-4
getting for BLOBs, 14-2 ons.config file, 26-2, 26-4
getting for CLOBs, 14-2 optimization, performance, B-1
LOB, 14-2 Oracle Advanced Security
passing to callable statements, 14-4 support by JDBC, 9-1
passing to prepared statement, 14-4 support by OCI drivers, 9-2
LONG support by Thin driver, 9-3
data conversions, 12-2 Oracle Connection Manager, 5-3
LONG RAW Oracle data types
data conversions, 12-2 using, 11-1
LRU algorithm, 20-2 Oracle extensions, 4-2
data type support, 4-2
limitations, A-11
M catalog arguments to DatabaseMetaData
make() method, 4-12 calls, A-12
memory leaks, D-2 CursorName, A-11
moveToCurrentRow() method (result set), 17-13 IEEE 754 floating-point compliance, A-12
moveToInsertRow() method (result set), 17-13 PL/SQL TABLE, BOOLEAN, RECORD
mutable arrays, 16-13 types, A-11
read-only connection, B-4
SQL92 outer join escapes, A-11
N
SQLWarning class, A-12
named arrays, 16-1 object support, 4-3
defined, 16-5 result sets, 11-5
nativeXA, 8-4, 28-20 statements, 11-5
NCLOB to JDBC, 4-1, 11-1, 13-1, 15-1, 16-1, 23-1
creating and populating, 14-8 Oracle JPublisher, 4-3
reading data, 14-7 generated classes, 13-25
network events, trapping, D-4 Oracle mapping (for attributes), 13-31
next() method, 18-5 Oracle Notification Service. See ONS
next() method (result set), 17-10 Oracle objects
NLS. See globalization and JDBC, 13-1
NLS_LANG variable converting with ORAData interface, 13-14
desupported, 19-1 converting with SQLData interface, 13-10
NULL getting with getObject() method, 13-4
testing for, 11-4 Java classes which support, 13-2
NULL data mapping to custom object classes, 13-6
converting, 11-4 reading data by using SQLData interface, 13-12
null data working with, 13-1
explicit Statement caching, 20-8 writing data by using SQLData interface, 13-14
NullPointerException Oracle SQL data types, 11-1
Index-6
OracleCallableStatement interface, 4-22 and nested tables, 4-8
getOraclePlsqlIndexTable() method, 4-29 and VARRAYs, 4-8
getPlsqlIndexTable() method, 4-29 getAutoBuffering() method, 16-4
getXXX() methods, 11-9 methods for Java primitive types, 16-4
registerIndexTableOutParameter() method, 4-29, setAutoBuffering() method, 16-4
4-31 setAutoIndexing() method, 16-4
registerOutParameter() method, 11-11 oracle.sql.BFILE class, 4-8
setPlsqlIndexTable() method, 4-29 oracle.sql.BLOB class, 4-8
OracleCallableStatement object, 20-2 oracle.sql.CHAR class
OracleConnection class, 4-21 getString() method, 4-13
OracleConnection interface, 24-2 getStringWithReplacement() method, 4-13
OracleConnection object, 20-2 toString() method, 4-13
OracleDatabaseMetaData class, A-9 oracle.sql.CharacterSet class, 4-12
OracleDataSource class, 8-2, 24-2 oracle.sql.CLOB class, 4-8
oracle.jdbc. package, 4-19 oracle.sql.data types
oracle.jdbc., Oracle JDBC extensions, 2-8 support, 4-6
oracle.jdbc.OracleCallableStatement interface, 4-22 oracle.sql.DATE class, 4-9
oracle.jdbc.OracleConnection interface, 4-21 oracle.sql.Datum array, 4-33
cancel() method, 4-21 oracle.sql.Datum class, described, 4-5
commit() method, 4-21 oracle.sql.NUMBER class, 4-9
getDefaultExecuteBatch() method, 4-21 oracle.sql.ORAData interface, 13-14
getDefaultRowPrefetch() method, 4-21 oracle.sql.ORADataFactory interface, 13-14
getTransactionIsolation() method, B-4 OracleSql.parse() method, A-10
setDefaultExecuteBatch() method, 4-21 oracle.sql.RAW class, 4-9
setDefaultRowPrefetch() method, 4-22 oracle.sql.REF class, 4-8, 15-1
setTransactionIsolation() method, B-4 getBaseTypeName() method, 15-2
oracle.jdbc.OraclePreparedStatement interface, 4-22 getValue() method, 15-3
oracle.jdbc.OracleResultSet, 11-5 setValue() method, 15-3
oracle.jdbc.OracleResultSet interface, 4-23 oracle.sql.ROWID class, 4-13
oracle.jdbc.OracleResultSetMetaData interface, 4-23, oracle.sql.STRUCT class, 4-7, 13-3
11-14 getAutoBuffering() method, 13-6
using, 11-14 getDescriptor() method, 13-3
oracle.jdbc.OracleSql class, A-10 getJavaSQLConnection() method, 13-3
oracle.jdbc.OracleStatement, 11-5 getOracleAttributes() method, 13-3
oracle.jdbc.OracleStatement interface, 4-22 setAutoBuffering() method, 13-6
defineColumnType(), 4-22 toJDBC() method, 13-3
getRowPrefetch() method, 4-22 oracle.sql.StructDescriptor class
setRowPrefetch() method, 4-22 createDescriptor() method, 13-5
oracle.jdbc.OracleTypes class, 4-23, 23-17 OracleStatement interface, 4-22
oracle.jdbc.pool package, 24-3 OracleTypes class, 4-23
oracle.jdbc.xa package and subpackages, 28-5 OracleTypes class for typecodes, 4-23
OracleOCIConnection class, 24-2 OracleTypes.CURSOR variable, 4-16
OracleOCIConnectionPool class, 24-1, 24-2 OracleXAConnection class, 28-6
OraclePreparedStatement interface, 4-22 OracleXADataSource class, 28-6
getOraclePlsqlIndexTable() method, 4-29 OracleXAResource class, 28-7, 28-8
getPlsqlIndexTable() method, 4-29 OracleXid class, 28-12
registerIndexTableOutParameter() method, 4-29 ORAData interface, 4-3
setPlsqlIndexTable() method, 4-29 additional uses, 13-18
OraclePreparedStatement object, 20-2 advantages, 13-8
OracleResultSet interface, 4-23 Oracle object types, 13-1
getXXX() methods, 11-9 reading data, 13-16
OracleResultSetCache interface, 17-4 writing data, 13-17
OracleResultSetMetaData interface, 4-23 orai18n.jar file, 19-2
OracleServerDriver class othersDeletesAreVisible() method (database
defaultConnection() method, 7-2 metadata), 17-17
oracle.sql data type classes, 4-5 othersInsertsAreVisible() method (database
oracle.sql package metadata), 17-18
data conversions, 11-3 othersUpdatesAreVisible() method (database
described, 4-5 metadata), 17-18
oracle.sql.ARRAY class, 16-1 OUT parameter mode, 4-31, 4-32
Index-7
outer joins, SQL92 syntax, A-10 RAW class, 4-9
ownDeletesAreVisible() method (database meta read-only result set concurrency type, 17-3
deta), 17-17 readSQL() method, 13-10, 13-11
ownInsertsAreVisible() method (database meta implementing, 13-11
data), 17-17 recover (distributed transactions), 28-12
ownUpdatesAreVisible() method (database meta REF class, 4-8
data), 17-17 REF CURSORs, 4-15
materialized as result set objects, 4-15
refetching rows into a result set, 17-16, 17-18
P
refreshRow() method (result set), 17-16
parameter modes registerIndexTableOutParameter() method, 4-29,
IN, 4-29 4-31
IN OUT, 4-31 arguments
OUT, 4-31, 4-32 int elemMaxLen, 4-31
password, specifying, 2-8 int elemSqlType, 4-31
PATH environment variable, specifying, 2-4 int maxLen, 4-31
PDA, 18-8 int paramIndex, 4-31
performance enhancements, standard vs. Oracle, 3-2 code example, 4-31
performance extensions registerOutParameter() method, 11-11
defining column types, 23-17 relative positioning in result sets, 17-2
TABLE_REMARKS reporting, 23-19 remarksReporting flag, 23-15
performance optimization, B-1 Remote Method Invocation (RMI), 18-8
Personal Digital Assistant (PDA), 18-8 resource managers, 28-2
PL/SQL result set
limit on BLOB size, 14-4 auto-commit mode, B-2
restrictions, D-2 getting BFILE locators, 14-15
stored procedures, 2-15 getting LOB locators, 14-3
PL/SQL index-by tables, 4-28 metadata, 4-23
mapping, 4-32 Oracle extensions, 11-5
scalar data types, 4-29 using getOracleObject() method, 11-6
PL/SQL types result set enhancemennts
corresponding JDBC types, 4-29 positioning result sets, 17-8
limitations, A-11 result set enhancements
PoolConfig() method, 24-5 concurrency types, 17-3
populate() method, 18-7 downgrade rules, 17-7
positioning in result sets, 17-2 fetch size, 17-15
prefetching rows, 23-15 limitations, 17-6
suggested default, 23-15 Oracle scrollability requirements, 17-3
prepare a distributed transaction branch, 28-11 Oracle updatability requirements, 17-4
prepareCall(), 20-3 positioning, 17-2
prepareCall() method, 20-6, 20-7 processing result sets, 17-10
prepared statement refetching rows, 17-16, 17-18
passing BFILE locator, 14-16 result set types, 17-2
passing LOB locators, 14-4 scrollability, 17-2
PreparedStatement object seeing external changes, 17-17
creating, 2-11 seeing internal changes, 17-17
prepareStatement(), 20-3 sensitivity to database changes, 17-2
prepareStatement() method, 20-6, 20-7 specifying scrollability, updatability, 17-5
code example, 20-6 summary of visibility of changes, 17-18
previous() method (result set), 17-10 updatability, 17-2
put() method updating result sets, 17-11
for Properties object, 8-10 visibility vs. detection of external changes, 17-18
for type maps, 13-9 result set fetch size, 17-15
Result Set Holdability, 3-6
Q result set object
closing, 2-10
query, executing, 2-9 result set types for scrollability and sensitivity, 17-2
result set, processing, 2-10
R ResultSet class, 2-9
ResultSet() method, 16-4
racgons, 26-4
Index-8
Retrieval of Auto-Generated Keys, 3-4 server-side Thin driver, overview, 1-3
return types session context
for getXXX() methods, 11-9 for KPRB driver, 7-4
getObject() method, 11-7 setAsciiStream() method
getOracleObject() method, 11-7 for writing CLOB data, 14-5, 14-6
return values setAutoBuffering() method
casting, 11-10 of the oracle.sql.ARRAY class, 16-4
RMI, 18-8 of the oracle.sql.STRUCT class, 13-6
roll back a distributed transaction branch, 28-11 setAutoCommit() method, B-1
roll back changes to database, 2-13 setAutoIndexing() method, 16-4
row prefetching setBFILE() method, 14-16
and data streams, 12-9 setBinaryStream() method
ROWID class for writing BLOB data, 14-5
CursorName methods, A-11 setBLOB() method, 14-4
defined, 4-13 setBytes() limitations, using streams to avoid, 12-9
ROWID, use for result set updates, 17-4 setCharacterStream() method
RowSet for writing CLOB data, 14-5, 14-6
events and event listeners, 18-3 setCLOB() method, 14-4
overview, 18-1 setCursorName() method, A-11
properties, 18-2 setDefaultExecuteBatch() method, 4-21, 23-4
traversing, 18-4 setDefaultRowPrefetch() method, 4-22
run-time connection load balancing, 22-1 setDisableStatementCaching() method, 20-6
enabling, 22-2 setEscapeProcessing() method, A-7
how it works, 22-1 setExecuteBatch() method, 23-4
load balancing advisory, 22-2 setFetchSize() method, 17-15
overview, 22-1 setFixedCHAR() method, 11-13
setMaxFieldSize() method, 23-18
setNCLOB() method, 14-4
S
setNull(), 11-5
savepoints setNull() method, 11-11
transaction, 3-3 to ?? setObejct() method, 11-11
scalar functions, SQL92 syntax, A-9 setObject() method
Schema Naming, 4-4 for BFILES, 14-16
scripts, authenticating users in, 9-21 for CustomDatum objects, 13-16
scrollability in result sets, 17-2 for object references, 15-4
scrollable result sets for STRUCT objects, 13-6
creating, 17-5 to write object data, 13-18
fetch direction, 17-10 setOracleObject() method, 11-11
implementation of scroll-sensitivity, 17-19 for BFILES, 14-16
positioning, 17-8 for BLOBs and CLOBs, 14-4
processing backward/forward, 17-10 setORAData() method, 13-15, 13-18
refetching rows, 17-16, 17-18 setPlsqlIndexTable() method, 4-29
scroll-insensitive result sets, 17-2 arguments
scroll-sensitive result sets, 17-2 int curLen, 4-30
seeing external changes, 17-17 int elemMaxLen, 4-30
visibility vs. detection of external changes, 17-18 int elemSqlType, 4-30
scroll-sensitive result sets int maxLen, 4-30
limitations, 17-6 int paramIndex, 4-30, 4-32
security Object arrayData, 4-30
authentication, 9-3 code example, 4-30
encryption, 9-6 setPoolConfig() method, 24-4
integrity, 9-6 setREF() method, 15-4
Oracle Advanced Security support, 9-1 setRemarksReporting() method, 23-19
SELECT statement setResultSetCache() method, 17-5
to retrieve object references, 15-3 setRowPrefetch() method, 4-22
to select LOB locator, 14-10 setString() limitations, using streams to avoid, 12-9
sendBatch() method, 23-5, 23-7 setString() method
sensitivity in result sets to database changes, 17-2 to bind ROWIDs, 4-14
server-side internal driver setTransactionIsolation() method, B-4
connection to database, 7-1 setValue() method, 15-3
Index-9
setXXX() methods closing, 12-8
Oracle extended properties, 8-5 example, 12-3
setXXX() methods, for specific data types, 11-11 external files, 12-6
signed applets, 5-3 LOBs, 12-6
Solaris LONG columns, 12-2
shared libraries, 28-20 LONG RAW columns, 12-2
specifiers multiple columns, 12-7
database, 8-11 precautions, 12-8
SQL RAW columns, 12-5
data converting to Java data types, 11-3 row prefetching, 12-9
types, constants for, 4-23 UPDATE/COMMIT statements, 14-6
SQL engine use to avoid setBytes() and setString()
relation to the KPRB driver, 7-1 limitations, 12-9
SQL syntax (Oracle), A-7 VARCHAR columns, 12-5
SQL92 syntax, A-6 stream data column
function call syntax, A-10 bypassing, 12-7
LIKE escape characters, A-9 STRUCT class, 4-7
outer joins, A-10 STRUCT descriptor, 13-5
scalar functions, A-9 STRUCT object, 4-7
time and date literals, A-7 attributes, 4-7
translating to SQL example, A-10 creating, 13-5
SQLData interface, 4-3 embedded object, 13-3
advantages, 13-8 nested objects, 4-8
described, 13-10 retrieving, 13-3
Oracle object types, 13-1 retrieving attributes as oracle.sql types, 13-4
reading data from Oracle objects, 13-12 StructDescriptor object
using with type map, 13-10 creating, 13-5
writing data from Oracle objects, 13-14 SYS.ANYDATA, 4-16
SQLInput interface, 13-10 SYS.ANYTYPE, 4-16
described, 13-11
SQLInput streams, 13-11
T
SQLNET.ORA
parameters for tracing, D-4 TABLE_REMARKS columns, 23-15
SQLOutput interface, 13-10 TABLE_REMARKS reporting
described, 13-11 restrictions on, 23-19
SQLOutput streams, 13-12 TAF, definition of, 27-1
SQLWarning class, limitations, A-12 TCP/IP protocol, 8-12
SSL testing
and LDAP, 8-13 for NULL values, 11-4
start a distributed transaction branch, 28-8 Thin driver
Statement caching applets, 5-2
explicit LDAP over SSL, 8-13
definition of, 20-3 overview, 1-2
null data, 20-8 server-side, overview, 1-3
implicit time and date literals, SQL92 syntax, A-7
definition of, 20-2 tnsEntry, 8-4, 28-20
Least Recently Used (LRU) algorithm, 20-2 toDatum() method
Statement object applied to CustomDatum objects, 13-8, 13-15
closing, 2-10 called by setORAData() method, 13-18
creating, 2-9 toJDBC() method, 13-3
statement.cancel(), D-3 toJdbc() method, 4-7
statements toString() method, 4-13
Oracle extensions, 11-5 trace facility, D-4
stopping trace parameters
statement execution, D-3 client-side, D-4
stored procedures server-side, D-6
Java, 2-15 transaction branch, 28-1
PL/SQL, 2-15 transaction branch ID component, 28-12
stream data, 12-1, 14-5 transaction context
CHAR columns, 12-5 for KPRB driver, 7-4
Index-10
transaction IDs (distributed transactions), 28-3 update counts, 23-6
transaction managers, 28-2 update batching (standard model)
transaction savepoints, 3-3 to ?? adding to batch, 23-9
transactions clearing the batch, 23-10
switching between local and global, 28-4 to 28-5 committing changes, 23-10
Transparent Application Failover (TAF), definition error handling, 23-12
of, 27-1 example, 23-12
TTC error messages, listed, C-10 executing the batch, 23-10
type map, 4-3, 11-6 intermixing batched and non-batched, 23-13
adding entries, 13-9 overview, 23-8
and STRUCTs, 13-10 update counts, 23-11
creating a new map, 13-10 update counts upon error, 23-13
used with arrays, 16-8 update conflicts in result sets, 17-14
used with SQLData interface, 13-10 update counts
using with arrays, 16-12 Oracle update batching, 23-6
type map (SQL to Java), 13-6 standard update batching, 23-11
type mapping upon error (standard batching), 23-13
BigDecimal mapping, 13-32 UPDATE in a result set, 17-12
JDBC mapping, 13-31 updateRow() method (result set), 17-12
object JDBC mapping, 13-31 updatesAreDetected() method (database
Oracle mapping, 13-31 metadata), 17-18
type mappings updateXXX() methods (result set), 17-12, 17-13
JPublisher options, 13-31 updating result sets, 17-11
type maps url, 8-4
relationship to database connection, 7-3 URLs
TYPE_FORWARD_ONLY result sets, 17-5 for KPRB driver, 7-2
TYPE_SCROLL_INSENSITIVE result sets, 17-5 userid, specifying, 2-8
TYPE_SCROLL_SENSITIVE result sets, 17-5
typecodes, Oracle extensions, 4-23
W
WebRowSet, 18-10
U WIDTH, parameter for APPLET tag, 5-8
unicode data, 4-10 window, scroll-sensitive result sets, 17-19
updatability in result sets, 17-2 writeSQL() method, 13-10, 13-12
updatable result set concurrency type, 17-3 implementing, 13-11
updatable result sets
creating, 17-5
X
DELETE operations, 17-11
INSERT operations, 17-13 XA
limitations, 17-6 connection implementation, 28-6
refetching rows, 17-16, 17-18 connections (definition), 28-3
seeing internal changes, 17-17 data source implementation, 28-6
update conflicts, 17-14 data sources (definition), 28-2
UPDATE operations, 17-12 definition, 28-1
update batching error handling, 28-14
overview, Oracle vs. standard model, 23-2 example of implementation, 28-15
overview, statements supported, 23-2 exception classes, 28-13
update batching (Oracle model) Oracle optimizations, 28-15
batch value, checking, 23-5 Oracle transaction ID implementation, 28-12
batch value, overriding, 23-5 resource implementation, 28-7
committing changes, 23-6 resources (definition), 28-3
connection batch value, setting, 23-4 transaction ID interface, 28-12
connection vs. statement batch value, 23-3 XAException, 28-12
default batch value, 23-3 Xids, 28-12
disable auto-commit, 23-3
example, 23-7
limitations and characteristics, 23-3
overview, 23-3
statement batch value, setting, 23-4
stream types not allowed, 23-3
Index-11
Index-12