You are on page 1of 550

Oracle9i: Access the Database

with Java and JDBC


Instructor Guide

D11678GC31
Edition 3.1
August 2002
D37106
Authors Copyright © Oracle Corporation, 2002. All rights reserved.

Michael Curtis This documentation contains proprietary information of Oracle Corporation. It is


provided under a license agreement containing restrictions on use and disclosure and
Patrice Daux is also protected by copyright law. Reverse engineering of the software is prohibited.
Lynn Munsinger If this documentation is delivered to a U.S. Government Agency of the Department of
Defense, then it is delivered with Restricted Rights and the following legend is
applicable:

Restricted Rights Legend


Technical Contributors
and Reviewers Use, duplication or disclosure by the Government is subject to restrictions for
commercial computer software and shall be deemed to be Restricted Rights software
Edward Dowgiallo under Federal law, as set forth in subparagraph (c)(1)(ii) of DFARS 252.227-7013,
Christian.Dugas Rights in Technical Data and Computer Software (October 1988).

Kuassi Mensah This material or any portion of it may not be copied in any form or by any means
Ekkehard Rohwedder without the express prior written permission of Oracle Corporation. Any other copying
is a violation of copyright law and may result in civil and/or criminal penalties.
Glenn Stokol
If this documentation is delivered to a U.S. Government Agency not within the
Department of Defense, then it is delivered with “Restricted Rights,” as defined in
FAR 52.227-14, Rights in Data-General, including Alternate III (June 1987).

The information in this document is subject to change without notice. If you find any
Publisher problems in the documentation, please report them in writing to Education Products,
Oracle Corporation, 500 Oracle Parkway, Box SB-6, Redwood Shores, CA 94065.
Michael Sebastian Oracle Corporation does not warrant that this document is error-free.

Oracle and all references to Oracle products are trademarks or registered trademarks
of Oracle Corporation.

All other products or company names are used for identification purposes only, and
may be trademarks of their respective owners.
Contents

Preface
Introduction
Objectives I-2
Course Overview I-3
Java Developer Courses I-4
Course Environment I-5
About the Course Applications I-6
The Order Entry Database Schema I-7
1 Introduction to Database Programming with Java
Objectives 1-2
Java, J2EE, and Oracle9i 1-3
How Java Connects to a Database 1-4
JDBC 1-5
SQLJ 1-6
Java Stored Procedures 1-7
Integrated Development Environment 1-8
Exploring the JDeveloper Environment 1-9
Examining Workspaces 1-10
What Are Projects? 1-11
Creating JDeveloper Items 1-12
Summary 1-13
Practice 1-1 Overview 1-14
Practice 1 -1 1-15
2 Performing Basic SQL Statements to Access the Database
Objectives 2-2
JDBC 2-3
Preparing JDBC use 2-4
Steps for Using JDBC to Execute SQL Statements 2-5
Stage 1: Registering the Driver 2-6
Stage 2: Getting a Database Connection 2-7
Stage 3: Creating a Statement 2-8
Stage 4: Executing a SQL Statement 2-9
Executing a Query 2-10
The ResultSet Object 2-11
Processing the Query Results 2-12
Stage 5: Closing Unneeded objects 2-13
A Basic Query Example 2-14
Submitting DML Statements 2-15
Submitting DDL Statements 2-16
Handling an Unknown SQL Statement 2-17

iii
Handling Exceptions 2-18
Managing Transactions 2-19
Summary 2-20
Practice 2-1 Overview 2-21
Practice 2 -1 2-22
3 More About JDBC
Objectives 3-2
More on the Connect Stage 3-3
Connecting to the Database 3-4
Oracle JDBC Drivers: Thin Client Driver 3-5
Oracle JDBC Drivers: OCI Client Drivers 3-6
Oracle JDBC Drivers: KPRB Server-Side Driver 3-7
Oracle JDBC Drivers: Thin Server-Side Driver 3-8
Other JDBC Drivers 3-9
Choosing the Right Driver 3-10
About JDBC URLs 3-11
JDBC URLs with Oracle Drivers 3-12
Stage 4: More on Processing Result for the Select 3-13
How to Process the Results 3-14
Mapping Database Types to Java Types 3-15
How to Handle SQL Null Values 3-17
Advanced Data Types 3-18
Working with Large Objects 3-19
Reading BLOBs 3-20
Writing BLOBs 3-21
Reading CLOBs 3-22
Writing CLOBs 3-23
Populating LOBs in a New Table from Files 3-24
Working with BFILEs 3-26
Reading BFILEs 3-27
Working with Oracle Objects 3-28
STRUCT Object and Descriptor 3-30
Working with Oracle Object References 3-32
Working with Oracle Collections 3-33
Working with ARRAYS 3-34
Manipulating ARRAYS 3-35
The DatabaseMetaData Object 3-36
How to Obtain Database Metadata 3-37
The ResultSetMetaData Object For Dynamic SQL 3-38
How to Obtain Result Set Metadata 3-39
Summary of JDBC Classes and Interfaces 3-40

iv
Summary 3-41
Practice 3: Part I Overview 3-42
Practice 3-1 3-44
Practice 3: Part II Overview 3-45
Practice 3-2 Overview 3-46
Practice 3-2 3-47

4 JDBC Advanced Topics and Performance Extensions


Objectives 4-2
Navigating in the Result Set 4-3
Result Set Navigation 4-4
Result Set Implementation 4-5
Setting Navigation for Result Set 4-6
Positioning in the Result Set 4-7
Updating the Result Set 4-9
Inserting in the Result Set 4-10
Scrollable and Updateable Restrictions with Result Sets 4-11
The PreparedStatement Object 4-13
How to Create a PreparedStatement 4-14
How to Execute a PreparedStatement 4-15
The CallableStatement Object 4-16
CallableStatement for a Procedure Call(1) 4-18
CallableStatement for a Procedure Call(2) 4-19
REF CURSOR 4-20
Prefetching Rows in a Query 4-22
Prefetching Rows: Example 4-23
Prespecifying Column Types 4-24
Prespecifying Types: Example 4-25
Objectives of Update Batching 4-26
Batched Updates of Prepared Statements 4-27
Managing Batch Execution 4-30
The ROWID Pseudocolumn 4-31
Example: Using ROWID for In-Place Updates 4-32
Summary 4-33
Practice 4-1 Overview 4-34

5 JDBC Optional Package and JDBC in Web Applications


Objectives 5-2
J2EE/JDBC 2.0 Features 5-3
Database Connection Flexibility 5-4
Java Naming Directory Interface 5-5

v
Using JNDI 5-6
Creating a Data Source 5-7
Registering the Data Source 5-8
Using the Data Source 5-9
Connection Pooling 5-10
Connection Cache 5-12
Using a Connection Cache 5-13
Connection Cache Properties 5-14
Distributed Transactions Overview 5-15
Using Distributed Connections 5-16
Performing a Distributed Transaction 5-18
Distributed Transaction Branch Testing 5-19
Statement Caching 5-21
Implicit Statement Caching 5-22
Explicit Statement Caching 5-23
Implicit Statement Caching Use 5-24
Explicit Caching Code Example 5-25
Client Security with JDBC 5-26
Authentication Encryption and Integrity 5-27
Setting Encryption and Integrity Parameters for Thin 5-28
JDBC in Applets 5-29
Connecting to the Database Through an Applet 5-30
Connection Manager 5-31
Applet Connection String 5-32
Applets and Firewalls 5-33
Applet Using Thin Driver and Firewall 5-34
Packaging Applets 5-35
Summary 5-36
Practice 5 Overview 5-37
Practice 5-1 5-38
Practice 5-2 5-43
6 Developing and Deploying Stored Procedures
Objectives 6-2
Overview 6-3
What Is a Java Stored Procedure? 6-4
Why Use Java Stored Procedures? 6-5
How Do You Use Java Stored Procedures? 6-7
The Oracle9i Database 6-8
The Oracle9i JVM 6-9
Overview of Creating and Running a Stored Procedure 6-11
Step 1: Develop the Stored Procedure 6-12
Writing a Java Class for Deployment as Stored Procedures 6-13
The Database Server Default Connection 6-14
Internal Connection to the Database 6-16

vi
Example: Rentals.beginOrder() 6-17
Step 2: Load the Stored Procedure 6-18
Loading Java in the Database 6-19
Loading Java Code in the Server 6-20
Step 3: Publish the Stored Procedure 6-22
Publishing a Java Procedure 6-23
Writing a Call Spec 6-24
Deploying a Java Stored Procedure with JDeveloper 6-25
Steps for Deployment 6-26
Deployment Profile 6-27
Selecting the Methods to Publish 6-28
Publishing the Methods 6-29
Deploying in the Database 6-30
Database Browsing 6-31
How to Delete a Java Stored Procedure 6-32
Step 4: Call the Stored Procedure 6-33
Calling a Stored Procedure Using JDBC(1) 6-34
Calling a Stored Procedure Using JDBC(2) 6-36
Calling a Stored Procedure Using SQLJ 6-37
Calling a Stored Function Using SQLJ 6-38
Calling Java from SQL*Plus 6-39
Calling Java from a Database Trigger 6-40
How to Develop a Trigger in Java 6-41
Developing a Trigger in Java 6-42
Calling Java from SQL DML 6-43
Calling Java from PL/SQL 6-44
Access Control 6-45
Summary 6-46
Practice 6 Overview 6-47
Practice 6 6-48
7 Embedding SQL Statements in Java Code with SQLJ
Objectives 7-2
SQLJ 7-3
Advantages of SQLJ Compared to JDBC 7-4
The SQLJ Translator 7-5
Preparing SQLJ Use 7-6
Running SQLJ in Command Line 7-8
SQL Statement with SQLJ 7-9
Selecting a Single Row with SQLJ 7-10
Overview of Querying a Database with SQLJ 7-11
Register the Driver and Connect Using Oracle.connect 7-12
How to Manually Register the Driver and Connect 7-13
Register Manually the Driver and Connect 7-14

vii
What Is a Connection Context? 7-15
Connection Code Example 7-16
How to Query a Database with SQLJ 7-17
Exception Handling 7-18
How to Handle SQL Null Values 7-19
Guided Practice 7-1: Writing SQLJ Statements 7-20
Guided Practice 7-2: Writing SQLJ Statements 7-21
What Is an Iterator? 7-22
How to Execute a Multirow Query by Using a Named Iterator 7-23
Selecting a Calculated Field or Function Call into a Named Iterator 7-25
How to Execute a Query by Using a Positional Iterator 7-26
Named Iterator Versus Positional Iterator 7-28
Embedding PL/SQL with SQLJ 7-30
Calling a Procedure with SQLJ 7-31
Calling a Function with SQLJ 7-32
How to Add a New SQLJ File to a JDeveloper Project 7-33
Deploying SQLJ Code in JDeveloper 7-35
Configuring SQLJ Translator Options in JDeveloper 7-36
SQLJ Translator Options: Translator Warnings 7-37
SQLJ Translator Options: Online SQL Checking 7-38
Summary 7-39
Practice 7 Overview 7-40
Practice 7 7-41

Appendix A

Appendix B

Appendix C

viii
Preface
Oracle9i: Access the Database with Java and JDBC - Preface - 2
Profile

Before You Begin This Course


Before you begin this course, you should have the following qualifications:
• Thorough knowledge of Java and SQL languages
• Working experience with a Java development tool
Prerequisites
Required
• SQL1 (AKA Introduction to Oracle) or equivalent experience in SQL programming
• Java Programming or Equivalent experience with Java
Suggested
• Familiarity with the JDeveloper IDE, as provided by the Oracle Java Programming course, or
through self-study courses such as " Oracle9i JDeveloper: Introduction for J2EE Developers"
How This Course Is Organized
Oracle9i: Access the Database with Java and JDBC is an instructor-led course featuring lecture and
hands-on exercises. Online demonstrations and written practice sessions reinforce the concepts and
skills introduced.

Oracle9i: Access the Database with Java and JDBC - Preface - 3


Related Publications

Oracle Publications
Title Part Number
Oracle9i SQLJ Developer’s Guide and Reference A90212-01
Oracle9i JDBC Developer’s Guide and Reference A90211-01
Oracle9i JPublisher User’s Guide A90214-01
Oracle9i Java Stored Procedures Developer’s Guide A90210-01
Oracle9i Enterprise JavaBeans Developer’s Guide and Reference A90188-01

Additional Publications
• System release bulletins
• Installation and user’s guides
• read.me files
• International Oracle User’s Group (IOUG) articles
• Oracle Magazine

Oracle9i: Access the Database with Java and JDBC - Preface - 4


Typographic Conventions
Typographic Conventions in Text

Convention Element Example

Bold italic Glossary term (if there is The algorithm inserts the new key.
a glossary)

Caps and Buttons, Click the Executable button.


lowercase check boxes, Select the Can’t Delete Card check box.
triggers, Assign a When-Validate-Item trigger to the
windows ORD block.
Open the Master Schedule window.

Courier new, Code output, Code output: debug.set (‘I”, 300);


case sensitive directory names, Directory: bin (DOS), $FMHOME (UNIX)
(default is filenames, Filename: Locate the init.ora file.
lowercase) passwords, Password: User tiger as your password.
pathnames, Pathname: Open c:\my_docs\projects
URLs, URL: Go to http://www.oracle.com
user input, User input: Enter 300
usernames Username: Log on as scott

Initial cap Graphics labels Customer address (but Oracle Payables)


(unless the term is a
proper noun)

Italic Emphasized words and Do not save changes to the database.


phrases,
titles of books and For further information, see Oracle7 Server
courses, SQL Language Reference Manual.
variables
Enter user_id@us.oracle.com, where
user_id is the name of the user.

Quotation Interface elements with Select “Include a reusable module component”


marks long names that have and click Finish.
only initial caps;
lesson and chapter titles This subject is covered in Unit II, Lesson 3,
in cross-references “Working with Objects.”

Uppercase SQL column names, Use the SELECT command to view information
commands, functions, stored in the LAST_NAME
schemas, table names column of the EMP table.

Oracle9i: Access the Database with Java and JDBC - Preface - 5


Convention Element Example
Arrow Menu paths Select File—> Save.
Brackets Key names Press [Enter].

Commas Key sequences Press and release keys one at a time:


[Alternate], [F], [D]
Plus signs Key combinations Press and hold these keys simultaneously:
[Ctrl]+[Alt]+[Del]

Typographic Conventions in Code

Convention Element Example

Caps and Oracle Forms When-Validate-Item


lowercase triggers

Lowercase Column names, SELECT last_name


table names FROM s_emp;

Passwords DROP USER scott


IDENTIFIED BY tiger;

PL/SQL objects OG_ACTIVATE_LAYER


(OG_GET_LAYER (‘prod_pie_layer’))

Lowercase italic Syntax variables CREATE ROLE role

Uppercase SQL commands SELECT userid


and functions FROM emp;

Typographic Conventions in Navigation Paths


This course uses simplified navigation paths, such as the following example, to direct you through
Oracle Applications.
(N) Invoice—>Entry—>Invoice Batches Summary (M) Query—>Find (B) Approve

This simplified path translates to the following:


1. (N) From the Navigator window, select Invoice—>Entry—>Invoice Batches Summary.
2. (M) From the menu, select Query—>Find.
3. (B) Click the Approve button.
N = Navigator, M = Menu, B = Button

Oracle9i: Access the Database with Java and JDBC - Preface - 6


Introduction

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

20 minutes Lecture
20 minutes Total
Objectives

After completing this course, you should be able to


do the following:
• Use JDBC to connect to a database and execute
SQL statements in a Java application
• Deploy Java stored procedures in an Oracle9i
database
• Use SQLJ to embed SQL statements in Java code

I-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Additional Information
Additional information on the course topics can be found at the following URLs:
• http://otn.oracle.com/docs/tech/java/sqlj_jdbc/content.html
• http://developer.java.sun.com/developer/Books/JDBCTutorial/
• http://java.sun.com/docs/books/tutorial/index.html.

Oracle9i: Access the Database with Java and JDBC I-2


Course Overview

• Lesson 1 introduces database programming in


Java and reviews Oracle9i JDeveloper.
• Lessons 2, 3, 4, and 5 teach you how to access a
database using JDBC and how to use Oracle JDBC
extensions with J2EE.
• Lesson 6 shows you how to develop Java stored
procedures and use JDeveloper to deploy them in
an Oracle9i database.
• Lesson 7 teach you how to use SQLJ to embed
SQL statements in Java code.

I-3 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC I-3


Java Developer Courses

Java Programming Oracle9i: Access Oracle9i:

the Database with Develop Enterprise


Java and JDBC JavaBeans

Oracle9i: Oracle9i Oracle9i


Introduction for JDeveloper: JDeveloper:
J2EE Developers Develop Class Modeling
Applications Activity Modeling
with BC4J
Oracle9i Oracle9i
JDeveloper: Oracle9i: Create JDeveloper:
Create Product Servlets and Create Swing
Extensions JavaServer Pages Clients for BC4J
BC4J
(Related subjects)
Class Modeling

I-4 Copyright © Oracle Corporation, 2002. All rights reserved.

Java Developer: Curriculum Map


The diagram shows major courses in the Oracle9i Java curriculum. This should help you to
understand the position of the course that you are currently attending.
inClass Courses
Note that certain inClass (classroom) courses may become available in some training regions
later than others. Please check with Oracle University for specific availability.
BC4J Courses
Business Components for Java (BC4J) courses are highlighted in the diagram. These are
specific to the BC4J developer track, for developers who are using the framework.
Oracle University Online Learning (OUOL)
The self-paced titles shown on this diagram are indicated by “monitor” icons.
Instructor Note
The scope of your coverage for this page will naturally depend upon student interest. We
suggest that you at least indicate its presence in the book, and point out that its main purpose is
to help students understand where this course fits in the larger curriculum. It is not intended as
a heavy marketing exercise.

Oracle9i: Access the Database with Java and JDBC I-4


Course Environment

• The development tool is Oracle9i JDeveloper


• The database is Oracle9i (Release, 9.0.1)

I-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Course Environment
Oracle provides a server-side Java engine for the Oracle9i database. It consists of the
following components:
• Java Virtual Machine
• Server JDBC driver
• SQLJ run time

Oracle9i: Access the Database with Java and JDBC I-5


About the Course Applications

• The course uses applications that support the


Order Entry system.
• The applications access the common schema
database.
• In the practices, you will write applications that
access the database and manipulates the database
objects.

I-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC I-6


The Order Entry Schema

From Product Media Schema

I-7 Copyright © Oracle Corporation, 2002. All rights reserved.

The Order Entry Database Schema


All of the courses use a common database schema. The schema used for this course uses the
Order Entry subset of this common schema. The common schema is packaged with the
Oracle9i database.
• CREATE TABLE customers
• CREATE TABLE order_items
• CREATE TABLE orders
• CREATE TABLE inventories
• CREATE TABLE product_information
• CREATE TABLE product_descriptions
Additionally, two other objects are created:
• CREATE TYPE cust_address_typ AS OBJECT
• CREATE TYPE phone_list_typ AS VARRAY(5) OF VARCHAR2(25);
Note: Appendix A contains a detailed description of each table.

Oracle9i: Access the Database with Java and JDBC I-7


Introduction to Database Programming
with Java

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

20 minutes Lecture
15 minutes Practice
35 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Describe how Java applications connect to the
database
• Describe how Java database functionality is
supported by Oracle9i
• Identify the main components in JDeveloper

1-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
This lesson introduces you to the different types of database applications that can be written in
Java in a J2EE environment, including:
• Client applets and applications
• Servlets and JSPs
• Java stored procedures
It also presents how JDBC and SQLJ are used to connect to the database.
Finally, a brief overview of Oracle9i JDeveloper Integrated Development Environment
(JDeveloper IDE) is covered to describe the organization of the tool.

Oracle9i: Access the Database with Java and JDBC 1-2


Java, J2EE, and Oracle9i
Web Application
Client server server Data
Business
Presentation
logic

OC4J OC4J
Oracle
Oracle9i Database
Application Server
J2EE Certified Environment

1-3 Copyright © Oracle Corporation, 2002. All rights reserved.

Java and Oracle9i

Oracle provides a complete and integrated platform called Oracle9i, which supports all of the
server-side requirements for Java applications. Oracle9i consists of the following:
Oracle database
In addition to its database management features, the Oracle database (currently Oracle9i)
provides support for a variety of Java-based structures, including Java components and Java
stored procedures. These Java structures are executed in the database by its built-in Java
Virtual Machine, called the Oracle Java Virtual Machine (Oracle JVM).
Oracle9i Application Server
Oracle9i Application Server maintains and executes all of your application logic, including
Enterprise JavaBeans, through its own built-in JVM, the Enterprise Java Engine. Oracle9i
Application Server uses the Apache Web server to execute servlets and JSPs.
J2EE Architecture
J2EE is a standard technology which provides a set of APIs and a run time infrastructure for
hosting and managing applications. It specifies roles and interfaces for applications and the run
time onto which applications could be deployed. And hence the application developers just
need to focus on the application logic and related services, while leveraging the run time for
all infrastructure related services.
Instructor Note
For more architectural information on Oracle 9i Application Server, direct participants to the
various eClasses available from Oracle Learning Network.

Oracle9i: Access the Database with Java and JDBC 1-3


How Java Connects to a Database

Client applications, applets, and servlets use JDBC

JDBC

Client application
or applet

1-4 Copyright © Oracle Corporation, 2002. All rights reserved.

How Java Connects to a Database


To query an Oracle database, any Java application must have a way to connect to the database.
This is performed by using JDBC.
Java Database Connectivity (JDBC) is a standard application programming interface (API)
that is used for connecting a Java application to relational databases. The networking protocol
used depends on which JDBC driver you are using; for example, the Oracle thin JDBC driver
uses Oracle Net.
Running SQL from a Server-side Application
Applications that run inside the database use JDBC to execute their SQL queries. This includes
Java stored procedures.

Oracle9i: Access the Database with Java and JDBC 1-4


JDBC

• JDBC is a standard interface for accessing


relational databases from Java.
• The JDBC class library is part of the Java 2,
Standard Edition (J2SE).
• JDBC is used by client applications, applets,
servlets, and Java stored procedures.

Database
JDBC calls commands
Driver Database

1-5 Copyright © Oracle Corporation, 2002. All rights reserved.

About Java Database Connectivity (JDBC)


The java.sql package contains a set of interfaces that specify the JDBC API. This package
is part of the Java 2, Standard Edition. Database vendors implement these interfaces in
different ways, but the JDBC API itself is standard.
Using JDBC, you can write code that:
• Connects to one or more data servers
• Executes any SQL statement
• Obtains a result set so that you can navigate through query results
• Obtains metadata from the data server
Each database vendor provides one or more JDBC drivers. A JDBC driver implements the
interfaces in the java.sql package, providing the code to connect to and query a specific
database.

Oracle9i: Access the Database with Java and JDBC 1-5


SQLJ

• SQLJ is Java with embedded SQL.


• SQLJ is passed through a translator.
– It can check SQL against the database.
– It generates Java code with JDBC calls.

SQLJ Java
Translator compiler

SQLJ code Java code


Java class
Oracle with
JDBC calls

1-6 Copyright © Oracle Corporation, 2002. All rights reserved.

About SQLJ

SQLJ provides a way to embed SQL statements and constructs in Java programs.
SQLJ statements are embedded directly in a Java program. When the program is compiled, the
SQLJ translator first translates the SQLJ statements into JDBC calls.
You can write a program that contains a mixture of JDBC calls and SQLJ statements. That
way, you get all of the benefits of static SQL compilation and query checking offered by
SQLJ, plus the run-time flexibility of JDBC if you need it.
Advantages of SQLJ Compared to JDBC
• SQLJ is less intricate than JDBC, because you write SQL statements to interact with the
database. SQLJ provides more concise and less error-prone static SQL constructs than
JDBC.
• SQLJ provides stronger typing than JDBC code, because the SQL code is checked at
compile time rather than run time. A server connection is used to check your embedded
SQL code to verify that it is syntactically and semantically correct.
Note: You can think of SQLJ translator within the SQLJ technology as a precompiler in the
PRO* environment.
Oracle9i: Access the Database with Java and JDBC 1-6
Java Stored Procedures

• Procedures that are compiled, verified, and stored


in Oracle9i
• Fast, because they run in DBMS memory space
• Portable within the Java environment, because
they are written in Java

1-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Java Stored Procedures and Triggers


Java stored procedures are Java methods that reside and run in an Oracle9i database. To
publish Java methods, you write call statements, that map Java method names, parameter
types, and return types to their SQL counterparts. You can call a Java stored procedure from a
Java class, from SQL, or from PL/SQL.
A Java stored procedure executes several SQL statements with a single call from the client
application. This minimizes network traffic. Also, because the procedure is stored on the
server, it runs faster than a client process. As with PL/SQL stored procedures, a stored
procedure’s executable code is cached and shared among users, that reduces memory
requirements.
A database trigger is a stored procedure associated with a specific table or view. Oracle9i
invokes the trigger automatically whenever the table or view is modified.
Deploying Stored Procedures from JDeveloper
The JDeveloper Deployment Wizard loads your stored procedures into the database and
automatically generates the SQL call specifications for your procedures.

Oracle9i: Access the Database with Java and JDBC 1-7


Integrated Development Environment

Development Debug

UML Exchange

Multi-tier Database

XML Synchronized changes HTML

SCM Deployment

1-8 Copyright © Oracle Corporation, 2002. All rights reserved.

Integrated Development Environment


The IDE's addin architecture means that the tool is extensible and all the components (for
example, navigator, editor, modeler) share memory models and event systems. In this way, an
update in one tool is notified to another tool so that it can refresh its image or take other
appropriate actions.
In Release 9i, the JDeveloper IDE has been completely redeveloped in pure Java.
Customizable Environment
You can customize the JDeveloper Integrated Development Environment, and arrange its look,
to better suit your project needs and programming style. To suit the IDE to your individual
taste. You can:
• Change the look and feel of the IDE
• Create and manipulate custom navigators
• Customize the Component Palette
• Customize the IDE environment
• Select JDeveloper's internal Web server
• Arrange the windows in the IDE
Instructor Note
SCM stands for Source Control Management. Exchange is provided through XMI files
allowing you to import UML definitions coming from third party tools like Rational,
TogetherJ etc.
Oracle9i: Access the Database with Java and JDBC 1-8
Exploring the JDeveloper Environment

Command Area

Viewer Project Navigator Inspector

1-9 Copyright © Oracle Corporation, 2002. All rights reserved.

The Oracle9i JDeveloper Environment


JDeveloper contains four major user interface components. These components are what you
use to edit code, design and manage the user interface, and navigate around your program.
The Command Area
The Command Area in JDeveloper is the “control center,” that contains the main menu and a
toolbar with shortcuts to commonly used menu items. The Command Area also holds the
Component Palette, which contains components such as buttons, grids, and so on.
The Project Navigator Window
The Project Navigator window is made of two components. The navigator pane shows a list of
files or classes in a project. The files may be Java source files, .class files, graphics files,
HTML, XML documents, and so on. The structure pane lists all the methods, attributes, and
graphical user interface (GUI) components in a selected class.
Viewers
Viewers are where most of the work takes place; this is where you write code and design user
interfaces. Open a viewer by double-clicking the item that you want to edit or view. Each open
viewer has sections or tabs specific to the type of item being viewed (Source, Design, Bean,
and Doc.).
Property Inspector
The Property Inspector is the pane that shows the properties and events that are associated with
a selected component in the design section of a viewer.

Oracle9i: Access the Database with Java and JDBC 1-9


Examining Workspaces

• Contain multiple projects


• Views onto currently used
objects
Workspace

Navigator
window

Structure
window

1-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Project Organization
Oracle9i JDeveloper uses a well-defined structure to manage Java programming projects. The
structure is hierarchical and supports workspaces, projects, applications, images, .html files,
and more.
Workspaces
The workspace is the highest level in the control structure. It is a view of all the objects you
currently need, while working. A workspace keeps track of the projects and the environment
settings that you use, while you are developing your Java program. When you open
JDeveloper, the last workspace used is opened by default, so you can pick up where you left
off.
Workspaces are stored in files with the extension .jws. You do not edit a workspace file
directly. Whenever you save your workspace, you are prompted to save all of the current open
files. Saving the workspace does not save the open files, but only the current environment
configuration. To save the open and modified files, select the Save or Save All option from the
File menu.
Note: You can view the content of a workspace file by using any text editor.
Determining Workareas
Consider workareas to be a view onto the objects currently used. You may choose to create
workareas that include projects that were created in different workarea. Workarea object
groupings could be based around a business area (AP,GL,AR), the phase in a life cycle
(analysis, design, deploy) or the structure of the application (UI, business logic, data structure).

Oracle9i: Access the Database with Java and JDBC 1-10


What Are Projects?

• Contain related files


• Manage project and
environment settings
• Manage compiler and
debug options
Project

Project
files

1-11 Copyright © Oracle Corporation, 2002. All rights reserved.

Projects

JDeveloper projects organize file elements used to create your program. A project file has the
file extension .jpr and keeps track of the source files, packages, classes, images, and other
elements that might be needed for your program. You can add multiple projects to your
workspace to easily access, modify, and reuse your source code. You can view the content of a
project file using any text editor.
Projects also manage environment variables such as the source and output paths used for
compiling and running your program. Projects also maintain compiler, run time, and
debugging options so you can customize the behavior of those tools per project.
In the System Navigator window, projects show as the second level in the hierarchy under the
workspace.
When you select a .java or .html file in the navigation window, the structure window
displays the elements of the file in a tree format. For example, when you select a .java
source file, the classes, interfaces, methods, and variables are displayed.
To edit source code, double-click the file in the navigation window to display the contents in
the appropriate viewer. The structure window can be used to quickly locate specific areas of
code in your Java source files and browse the class hierarchy.
When you are working with the visual designer, the structure window displays the components
of your user interface and their associated event handling methods in a hierarchical tree
format.
Note: The italic font is used to indicate the file names that haven’t been saved yet.

Oracle9i: Access the Database with Java and JDBC 1-11


Creating JDeveloper Items

• Invoked in the Menu


with File | New
• Categorized by type
• Create any
JDeveloper element

1-12 Copyright © Oracle Corporation, 2002. All rights reserved.

New Elements
You can create any JDeveloper item from this window. The context for creating the item must
be correct. You must have the correct element selected in the Category column, in order to
create the appropriate Item.
The JDK used for development can be any version, but must be compatible with the intended
deployment run-time environment.
While creating the workspace your can define the paths used for the files stored. All the files
are stored using the following convention: workspace\project\package

Oracle9i: Access the Database with Java and JDBC 1-12


Summary

• JDBC provides database connectivity for various


Java constructs, including servlets and client
applications
• JDBC is a standard Java interface and part of the
J2SE
• SQLJ is a precompiler facility that generates Java
code with embedded JDBC calls
• Stored procedures are for data-intensive
processing in the database
• Java is supported in the Oracle database by the
Oracle Java Virtual Machine (Oracle JVM)

1-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 1-13


Practice 1 Overview

This practice covers:


• Starting Oracle9i JDeveloper
• Creating a workspace and a project
• Loading a .java file and compiling it
• Invoking the online help

1-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 1-14


Practice 1
Goal
The goal of this practice is to review JDeveloper IDE and refresh your understanding of
some basic operations in order to feel comfortable with the tool.
Your Assignment
You launch JDeveloper, and create a workspace and a project. You then upload a .java
file in your project, you compile it and run it. Finally you invoke the online help and do
some research on Class documentation.
Start Oracle9i JDeveloper
• Click the JDeveloper icon on the desktop
• Create a new workspace and a project
– Use the File | New menu option
– In the New Gallery select Projects in the Categories pane and double-click the
Workspace object in the Items pane
– In the directory name, leave the path and replace the Workspace name by
Lesson01
– Change the File Name to Lesson01.jws and click OK
– In the New Project dialog box, leave the indicated path , for the Directory
Name, and replace the Project name by Intro
– Change the File Name to Intro.jws and click OK
Load a .java file
• Load a .Java file into your current project
– Use the File | Open menu option
– In the Location, specify the C:\ labs\ directory
– Select the HelloWorld.java file and click OK
– On the Add Project Source Path question, answer Yes to update the project
source path
– HelloWorld.java appears in the System Navigator
Run a .java file
• Run a .Java file into your current project
– Read the HelloWorld.java file in the Editor window
– Right-click HelloWorld.java entry in the System Navigator
– Select the Run HelloWorld option in the menu
– Does the file compile?
– What is displayed in the Log window?
– Hello World should appear.
Use the Online Help
• Searching for Java classes info
– Select Help in the menu
– In the Contents tab open the Reference node

Oracle9i: Access the Database with Java and JDBC 1-15


Practice 1 (continued)
– Locate the Oracle JDBC entry
– Select the oracle.jdbc.driver package
– How many classes does this package contain?
– There are 11 classes in this package
– Locate the OracleConnection class and scroll through the documentation
to see class details
– Use the Back icon
– Click the left arrow
– Select the Oracle.jdbc package
– OracleConnection exists in this package as an interface
– Select the OracleConnection hyperlink to view the details
– Since which version of the database is this interface available?
– The interface is available since 8.1.7
– Select the Tree hyperlink in the Menu Items
– Scroll through the Package/Class/Interface hierarchy
– How many references to OracleResultSet do you find?

Oracle9i: Access the Database with Java and JDBC 1-16


Performing Basic SQL Statements
to Access the Database

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

40 minutes Lecture
60 minutes Practice
100 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Set PATH and CLASSPATH variables in order to use
JDBC drivers
• Load and register a JDBC driver
• Connect to an Oracle database
• Execute the steps to perform a SELECT statement
• Map simple Oracle database types to Java types
• Execute a simple a DML and a DDL statement
• Control Transactions

2-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
The Java Database Connectivity (JDBC) API contains Java classes and interfaces that
provide low-level access to databases. In this lesson, you learn how to use the JDBC API to
access data in a database.

Oracle9i: Access the Database with Java and JDBC 2-2


JDBC

• JDBC is a standard interface for connecting to


relational databases from Java.
– The JDBC Core API package in java.sql.
– JDBC 2.0 Optional Package API in javax.sql
– JDBC 3.0 API includes the Core API and Optional
Package API

• Include the vendor JDBC driver archive in the


CLASSPATH.
• Use the classes12.jar file for Oracle JDBC
drivers
2-3 Copyright © Oracle Corporation, 2002. All rights reserved.

About Java Database Connectivity (JDBC)


The java.sql package contains a set of interfaces, which specifies the JDBC API . This
package is part of Java 1.1.8 and Java 2, and is supported by JDeveloper. Database vendors
implement these interfaces in different ways, but the JDBC API itself is standard.
Instructor Note
JDBC 1.22 is part of JDK 1.1; JDBC 2.0 is part of Java 2.

Oracle9i: Access the Database with Java and JDBC 2-3


Preparing JDBC Use

• Setting the PATH


[Oracle Home]\bin

• Setting the CLASSPATH


[Oracle Home]\jdbc\lib\classes12.jar
• Importing JDBC packages
// Standard packages
import java.sql.*;
import java.math.*; // optional
// Oracle extension to JDBC packages
import oracle.jdbc.*;
import oracle.sql.*;

2-4 Copyright © Oracle Corporation, 2002. All rights reserved.

Requirements for Using Oracle JDBC


This section describes the environment variables that must be set for the JDBC OCI driver
and the JDBC Thin driver, focusing on the Sun Microsystems Solaris and Microsoft
Windows NT platforms.
You must set the CLASSPATH for your installed JDBC OCI or Thin driver.
Depending on whether you are using the SDK 1.2.x versions or JDK 1.1.x versions, you
must set one of these values for the CLASSPATH:
• [Oracle Home]/jdbc/lib/classes12.jar
(and optionally [Oracle Home]/jdbc/lib/nls_charset12.jar) for full
NLS character support)
OR
• [Oracle Home]/jdbc/lib/classes111.jar
(and optionally [Oracle Home]/jdbc/lib/nls_charset11.jar) for full
NLS character support)
Ensure that there is only one classes*.zip file version and one nls_charset*.zip
file version in your CLASSPATH.
JDBC OCI driver
If you are installing the JDBC OCI driver, you must also set the following value for the
library path environment variable [Oracle Home]/lib
The JDBC package
Your Java class must import java.sql.* to be able to use the JDBC classes, and include
the JDBC driver classes from your database vendor in the CLASSPATH.
For more information about required path and classpath settings for Oracle JDBC, refer to
the Oracle9i JDBC Developer’s Guide and Reference.
Oracle9i: Access the Database with Java and JDBC 2-4
Steps for Using JDBC to Execute
SQL Statements
Load/Register
JDBC Driver

Connect

SQL statement SELECT


statement

DML/ DDL Process


statement results

Close

2-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Steps to Execute an SQL Statement with JDBC


The following are the key steps:
• Load and register the driver (Use the java.sql.DriverManager class)
• Obtain a Connection object (Use java.sql.DriverManager to do this)
• Create a Statement object (Use the Connection object)
• Execute a query, DML, or DDL (Use the Statement object)
• While executing a query if you obtain a ResultSet object, then iterate through the
ResultSet to process the data for each row that satisfies the query.
• Close the ResultSet, Statement, and Connection object when finished
Dealing with Exceptions
When using JDBC, all of the methods that access the database throw SQLException if
anything goes wrong. You should always deal with this exception in your JDBC code.
SQLException has a number of methods that you can call to get information about the
exception, including:
• getMessage(): Returns a string that describes the error
• getErrorCode(): Retrieves the vendor-specific exception code
• getSQLState(): Retrieves the SQL state value
• Class.forName(): Throws a ClassNotFoundException if the specified class
cannot be found.

Oracle9i: Access the Database with Java and JDBC 2-5


Stage 1: Registering the Driver

• Register the driver in the code:


– DriverManager.registerDriver (new
oracle.jdbc.OracleDriver());
– Class.forName
("oracle.jdbc.OracleDriver");
• Register the driver when launching the class:
– java -Djdbc.drivers =
oracle.jdbc.OracleDriver <ClassName>;

2-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Loading the Driver


JDBC drivers must register themselves with the driver manager. There are two ways to
perform this:
1. Use the registerDriver() method of DriverManager.
2. Use the forName() method of the java.lang.Class class to load the JDBC
drivers directly, as follows:
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}

catch (ClassNotFoundException e) {}
Using the Class.forName() method calls the static initializer of the driver class. The
driver class does not need to be present at compile time.
However, this method is valid only for JDK-compliant Java virtual machines.
You can register the driver at execution time. In this case, the registering statements that may
exist in your Java class is ignored.
Example of use with –Djdbc option in command line:
C:>java -Djdbc.drivers=oracle.jdbc.OracleDriver MyClass
Instructor Note
oracle.jdbc.OracleDriver package provides new interfaces and classes that can be
used in place of the previous oracle.jdbc.driver.OracleDriver classes.

Oracle9i: Access the Database with Java and JDBC 2-6


Stage 2: Getting a Database Connection

In JDBC 1.0 use the DriverManager class


• Provides overloaded getConnection() methods
– All require a JDBC URL to specify the connection
details
• Example:
Connection conn =
DriverManager.getConnection(
"jdbc:oracle:thin:@myhost:1521:ORCL",
"scott","tiger");

• Vendors can provide different types of JDBC


drivers

2-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Getting a Connection to the Database


Use the DriverManager to create a connection by calling the getConnection() method.
The getConnection() method is overloaded, for example:
• getConnection(String url)
• getConnection(String url, Properties props), where properties must
include at least a value for the following key names: user and password.
• getConnection(String url, String user, String password)
In each case you must supply a URL like string that identifies the registered JDBC driver to
use, and the database connection string and security credentials, if required.
Note: JDBC 2.0 and later versions provide other ways of obtaining a connection object such
as by using JNDI instead of a database URL.

Oracle9i: Access the Database with Java and JDBC 2-7


Stage 3: Creating a Statement

JDBC Statement objects are created from the


Connection instance:
• Use the createStatement() method
– Provides a context for executing an SQL statement
• Example:
Connection conn =
DriverManager.getConnection(
"jdbc:oracle:thin:@myhost:1521:ORCL",
"scott","tiger");
Statement stmt = conn.createStatement();

2-8 Copyright © Oracle Corporation, 2002. All rights reserved.

Statement Objects in JDBC


The slide lists the three methods that you can call to execute a SQL statement. The following
slides describe how to call each method. The execute() method is useful for dynamically
executing an unknown SQL string.
JDBC provides two other statement objects:
• PreparedStatement, for precompiled SQL statements
• CallableStatement, for statements that execute stored procedures
Objects and Interfaces
java.sql.Statement is an interface, not an object. When you declare a Statement
object and initialize it using the createStatement() method, you are creating the
implementation of the Statement interface supplied by the Oracle driver that you are
using.

Oracle9i: Access the Database with Java and JDBC 2-8


Stage 4: Executing a SQL Statement

The Statement interface provides three methods to


execute SQL statements:
• Use executeQuery(String sql)for SELECT
statements
– Returns a ResultSet object for processing rows.
• Use executeUpdate(String sql) for DML/DDL
– Returns an int
• Use execute(String) for any SQL statement
– Returns a boolean value

2-9 Copyright © Oracle Corporation, 2002. All rights reserved.

Statement Objects in JDBC (continued)


Use executeQuery(String sql) for SELECT statements
• Returns a ResultSet object for processing rows
Use executeUpdate(String sql) for DML/DDL
• Returns an int value indicating number of rows affected by the DML, otherwise it is 0
for DDL
Use execute(String) for any SQL statement
• Returns boolean value of true if the statement returns a ResultSet(like queries),
otherwise it returns a false

Oracle9i: Access the Database with Java and JDBC 2-9


Executing a Query

Provide SQL query string, without semicolon, as


argument to executeQuery() method
• Returns a ResultSet object
Statement stmt = null;
ResultSet rset = null;
stmt = conn.createStatement();
rset = stmt.executeQuery
("SELECT ename FROM emp");

2-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Execute a Query and Return a Result Set Object


To query the database, use the executeQuery() method of your Statement
object. This method takes a SQL statement as input and returns a JDBC ResultSet
object.
This statement follows standard SQL syntax.

Oracle9i: Access the Database with Java and JDBC 2-10


The ResultSet Object

• The JDBC driver returns the results of a query in a


ResultSet object.
• A ResultSet object maintains a cursor pointing to
its current row of data.
• Provides methods to retrieve column values.

2-11 Copyright © Oracle Corporation, 2002. All rights reserved.

The ResultSet Object


The ResultSet object is a table of data representing a database result set, which is
generated by executing a statement that queries the database.
A ResultSet object maintains a cursor pointing to its current row of data. Initially the
cursor is positioned before the first row.
A default ResultSet object is not updateable and has a cursor that moves forward only.
Thus, it is possible to iterate through it only once and only from the first row to the last row.
New methods in the JDBC 2.0 API make it possible to produce ResultSet objects that are
scrollable and updateable.

Oracle9i: Access the Database with Java and JDBC 2-11


Processing the Query Results

The executeQuery() method returns a ResultSet


• Use the next() method in loop to iterate through
rows.
• Use getXXX() methods to obtain column values
by column position in query, or column name.
stmt = conn.createStatement();
rset = stmt.executeQuery(
"SELECT ename FROM emp");
while (rset.next()) {
System.out.println
(rset.getString("ename"));
}

2-12 Copyright © Oracle Corporation, 2002. All rights reserved.

The getXXX() Methods


The ResultSet class has several methods that retrieve column values for the current row.
Each of these getXXX() methods attempts to convert the column value to the specified
Java type and return a suitable Java value. For example, getInt() gets the column value
as an integer, getString() gets the column value as a string, and getDate() returns
the column value as a date.
• The next() method return true if a row was found, otherwise it returns false. Use it to
check if a row is available, and to step through subsequent rows.
• Many getXXX() methods to get the column values, where XXX is a Java data type, for
example:
getString(pos) returns column in pos as a String
getInt(idx) returns column in pos as an int.
And so on …

Oracle9i: Access the Database with Java and JDBC 2-12


Stage 5: Closing Unneeded objects

Explicitly close a Connection, Statement, and


ResultSet to release resources that are no longer
needed.
• Call their respective close() methods
Connection conn = ...;
Statement stmt = ...;
ResultSet rset = stmt.executeQuery(
"SELECT ename FROM emp");
...
// clean up
rset.close();
stmt.close();
conn.close();
...

2-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Closing the ResultSet, Statement, and Connection Objects


You must explicitly close all ResultSet and Statement objects after you finish using
them. The close() methods clean up memory and release database cursors, so if you do
not explicitly close your ResultSet and Statement objects, serious memory leaks may
occur, and you may run out of cursors in the database. You then need to close the
connection.
The server-side driver runs within a default session. You are already connected, and you
cannot close the default connection made by the driver. Calling close() on the connection
does nothing.

Oracle9i: Access the Database with Java and JDBC 2-13


A Basic Query Example

import java.sql.*;
class TestJdbc {
public static void main (String args [ ]) throws SQLException {
DriverManager.registerDriver (new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myHost:1521:ORCL","scott", "tiger");
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp");
while (rset.next ())
System.out.println (rset.getString ("ename"));
rset.close();
stmt.close();
conn.close();
}
}

2-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 2-14


Submitting DML Statements

1. Create an empty statement object.


Statement stmt = conn.createStatement();

2. Use executeUpdate to execute the statement.


int count = stmt.executeUpdate(SQLDMLstatement);

Example:
Statement stmt = conn.createStatement();
int rowcount = stmt.executeUpdate
("DELETE FROM order_items
WHERE order_id = 2354");

2-15 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Update a Table in the Database


The slide shows the syntax for the methods that execute a database update using a DML
statement.
executeUpdate() returns an int containing the row count, for an INSERT, UPDATE,
or DELETE statement.

Oracle9i: Access the Database with Java and JDBC 2-15


Submitting DDL Statements

1. Create an empty statement object.


Statement stmt = conn.createStatement();

2. Use executeUpdate to execute the statement.


int count = stmt.executeUpdate(SQLDDLstatement);
Example:

Statement stmt = conn.createStatement();


int rowcount = stmt.executeUpdate
("CREATE TABLE temp (col1 NUMBER(5,2),
col2 VARCHAR2(30)");

2-16 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Create DDL Statements


The slide shows the syntax for the methods that execute a DDL statement.
executeUpdate() returns an int containing 0, for a statement with no return value,
such as a SQL DDL statement.

Oracle9i: Access the Database with Java and JDBC 2-16


Handling an Unknown SQL Statement

1. Create an empty statement object.


Statement stmt = conn.createStatement();

2. Use execute to execute the statement.


boolean result = stmt.execute(SQLstatement);

3. Process the statement accordingly.


if (result) { // was a query - process results
ResultSet r = stmt.getResultSet(); ...
}
else { // was an update or DDL - process result
int count = stmt.getUpdateCount(); ...
}

2-17 Copyright © Oracle Corporation, 2002. All rights reserved.

Dynamically Executing an Unknown SQL Statement


An application may not know whether a given statement will return a result set until the
statement has been executed. In addition, some stored procedures may return several
different result sets and update counts.
JDBC provides a mechanism so that an application can execute a statement and then process
an arbitrary collection of result sets and update counts. The mechanism is based on the use of
a general execute() method and then calls to three other methods: getResultSet,
getUpdateCount, and getMoreResults. These methods enable an application to
explore the statement results one at a time and to determine whether a given result is a result
set or an update count.
execute() returns true if the result of the statement is a result set; it returns false if the
result of the statement is an update count. You can then call either getResultSet() or
getUpdateCount() on the statement.
The following example uses execute() to dynamically execute an unknown statement:
public void executeStmt (String statement) throws SQLException
{

Statement stmt = conn.createStatement();// Execute the statement


boolean result = stmt.execute(statement);
if (result) { // statement was a query Process the results
... }
else { // statement was an update or DDL

int updateCount = stmt.getUpdateCount(); // Process the results


... }

Oracle9i: Access the Database with Java and JDBC 2-17


Handling Exceptions

• SQL statements can throw a


java.sql.SQLException.
• Use standard Java error handling methods.
try {
rset = stmt.executeQuery("SELECT empno,
ename FROM emp");
}
catch (java.sql.SQLException e)
{ ... /* handle SQL errors */ }
...
finally { // clean up
try { if (rset != null) rset.close(); }
catch (Exception e)
{ ... /* handle closing errors */ }
...

2-18 Copyright © Oracle Corporation, 2002. All rights reserved.

Handling Exceptions
You can use the try-catch-finally block structure for closing resources.
Code Example
Connection conn = null; Statement stmt = null;
ResultSet rset = null; // initialize
stmt = conn.createStatement();
try {
rset = stmt.executeQuery("SELECT empno, ename FROM emp");
}

catch (java.sql.SQLException e)
{ ... /* handle errors */ }
...
// Clean up resources
finally {
try { if (rset != null) rset.close(); } catch (Exception e) {}
try { if (stmt != null) stmt.close(); } catch (Exception e) {}
try { if (conn != null) conn.close(); } catch (Exception e) {}
}

Oracle9i: Access the Database with Java and JDBC 2-18


Managing Transactions

• By default connections are in auto commit mode


• Use conn.setAutoCommit(false) to turn
autocommit off
• To control transactions when you are not in
autocommit mode, use:
– conn.commit(): Commit a transaction
– conn.rollback(): Rollback a transaction
• Closing a connection commits the transaction
even with the autocommit off option

2-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Transactions with JDBC


After you perform an UPDATE or INSERT operation in a result set, you propagate the
changes to the database in a separate step that you can skip if you want to cancel the
changes.
With JDBC, database transactions are managed by the Connection object. When you create a
Connection object, it is in autocommit mode, meaning that each statement is committed after
it is executed.
You can change the connection’s autocommit mode at any time by calling
setAutoCommit(). The following is a full description of autocommit mode:
• If a connection is in autocommit mode, all of its SQL statements will be executed and
committed as individual transactions.
• If a statement returns a result set, the statement finishes when the last row of the result
set has been retrieved or the result set has been closed.
• If autocommit mode has been disabled, its SQL statements are grouped into transactions,
which must be terminated by calling either commit() or rollback(). commit()
makes permanent all changes since the previous commit or rollback and releases any
database locks held by the connection.
• rollback() drops all changes since the previous commit or rollback and releases any
database locks. commit() and rollback() should be called only when you are not
in autocommit mode.
Note: The server-side driver does not support autocommit mode. You must control
transactions explicitly.
Oracle9i: Access the Database with Java and JDBC 2-19
Summary

• PATH and CLASSPATH variables determine which


components are used
• The steps for using SQL statements in Java are
Register, Connect, Submit, and Close
• You can use three methods to execute SQL
Statements depending on the nature of the
statement
• SQL statements can throw exceptions
• Control default transactions behavior

2-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 2-20


Practice 2 Overview

This practice covers:


• Setting up the Java environment
• Writing and Running a simple Java application that
access to a database

2-21 Copyright © Oracle Corporation, 2002. All rights reserved.

Instructor Note
In the following practices, the SQL statements need to be typed on a single line, or divided
in smaller chunks concatenated together using the + sign. Otherwise there will be an error at
compile time.
There is a solution file that can be used for students that have problems writing the class.
It is important that at the end of this lesson students have their own pictures table created,
since it is required for practices in the following lessons.

Oracle9i: Access the Database with Java and JDBC 2-21


Practice 2-1
Goal
The goal of this practice is to create a simple java class that provides access to the
database and run it in the MS-DOS window. You will have to set up the environment
variables to be able to compile and run a simple Java class that interacts with the Oracle
database. During this practice you perform DDL, DML, and Query statements.
Your assignment
You create the Practice2 class. In this class, you specify the code to connect to the
database, to query a single column from a table, and to disable the autocommit option.
You then, create a new table and populate this table with some values. You commit the
changes, display the values that were populated and insert again the same set of values.
After displaying all the rows, you roll back your last changes and display the final
result.
Modify the PATH environment variable
• Open Notepad
1. Type in the CLASS variable:
set PATH=<JDeveloper9i _home>\jdk\bin\;
<oracle_home>\bin\;
<JDeveloper9i_home>\jdev\bin\;%PATH%;
2. Type in the CLASSPATH variable
set CLASSPATH=.
set CLASSPATH=%CLASSPATH%;
<JDeveloper9i _home>\jdbc\lib\classes12.jar
• Save the file with the name E:\myjdbc.bat
Setting up the environment
• Open an MS-DOS window
– Click Start on the TaskBar
– Select the Start MS/DOS option
– Run the myjdbc.bat file
– Move to the E:\labs directory
Create the java class
• Open Notepad to enter the java code
3. Specify the packages to import
import java.sql.*;
import java.sql.SQLException.*;
import oracle.jdbc.driver.*;
4. Specify the following statements
public class Practice2
{

public static void main (String args [])


throws Exception
{

Oracle9i: Access the Database with Java and JDBC 2-22


Practice 2-1 (continued)
5. Register the Oracle JDBC driver
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
6. Connect to the database using the connection, username, and password that
your instructor provides you with.
// Connect to the database
// You can put a database name after the @ sign
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@hostname:1521:dbname",
"username","password");
Edit and run your Java application
• Save the file in the E:\labs directory with the name Practice2.java, using
File|Save menu option, but keep Notepad running, you will need it again.
• Compile the Practice2.java file (filename capitalization is important)
– a. In the Dos window, ensure the current directory is E:\labs
– b. Check if the Java source file is saved to disk.
– c. Compile the file using command: javac Practice2.java
– d. What file is created if you successfully compile the code?
File Practice2.class now exists
• Run the Practice2 application. (again capitalization is important)
– a. Run the file using command: java Practice2
– b. What is displayed in the ‘DOS’ window?
The DOS prompt displays with no message
Create a query statement in the java class
7. Add a statement to disable the autocommit mode for the connection
conn.setAutoCommit (false);
8. Create a statement object and add a SELECT statement using the
executeQuery method to query the region_id column of the table
regions.
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT region_id FROM regions");
9. Add a loop that displays each region_id using the getInt() method.
while (rset.next ())
{

System.out.println(rset.getInt(1));
}

rest.close();
Note: At this point you should be able to compile and run your .java file

Oracle9i: Access the Database with Java and JDBC 2-23


Practice 2-1 (continued)
Create a DDL statement in the java class
10. Drop the table PICTURES using the execute() method. Use the try
catch block structure to catch the exception when running the class the
first time.
try
{

stmt.execute ("DROP TABLE pictures");
}

catch (SQLException e)
{

// An exception could be raised here if the table  
// did not exist already.
}

11. Create a new table using the execute() method, with the following
definition: CREATE TABLE pictures(id number (8), name 
varchar2(20), pictureblob blob, picturebfile bfile)
stmt.execute ("CREATE TABLE pictures(id NUMBER(8),
name VARCHAR2(20), pictureblob BLOB, picturebfile 
BFILE)");
Create a DML statement in the java class
12. Using the executeUpdate() method, populate the PICTURES table
with the region_id from the regions table.
System.out.println("Table Insert");
stmt.executeUpdate ("INSERT INTO pictures (id)  
SELECT region_id FROM regions");
13. Add a SELECT statement using the executeQuery method to query the
ID column of the table PICTURES.
System.out.println("Start of Table query");
ResultSet rseta = stmt.executeQuery 
("SELECT id FROM pictures");
14. Add a loop that displays each region_id using the getInt() method
while (rseta.next ())
{

System.out.println(rseta.getInt(1));
}

rseta.close();
15. Commit the INSERT
// commit set up
conn.commit();
System.out.println ("end of committed values");

Oracle9i: Access the Database with Java and JDBC 2-24


Practice 2-1 (continued)
16. Using the executeUpdate() method, populate a second time the
PICTURES table with the region_id from the regionstable.
// second set of inserts
stmt.executeUpdate ("INSERT INTO pictures (id)    
SELECT region_id FROM regions");
System.out.println ("committed and uncommitted
values");
17. Add a SELECT statement using the executeQuery method to query the
id column of the table PICTURES.
ResultSet rsetb = stmt.executeQuery
("SELECT id FROM pictures");
18. Add a loop that displays each region_id using the getInt() method.
while (rsetb.next ())
{

System.out.println(rsetb.getInt(1));
}

rsetb.close();
19. Uncommit the changes
// uncommit
conn.rollback();
20. Add a SELECT statement using the executeQuery method to query the
ID column of the table PICTURES.
System.out.println ("final committed rows");
System.out.println("Start of Table query");
ResultSet rsetc = stmt.executeQuery 
("SELECT id FROM pictures");
21. Add a loop that displays each region_id using the getInt() method
while (rsetc.next ())
{

System.out.println(rsetc.getInt(1));
}

rsetc.close();
Closing resources
22. Close the statement object
stmt.close();
23. Close the connection.
conn.close();

Edit and run your Java Application


• Save the file, using File > Save menu option, but keep the Notepad running,
in case compilation errors occur requiring you to edit the source to make
corrections.
• Compile the Practice2.java file (filename capitalization is important)
• Run the Practice2 application. (again capitalization is important)

Oracle9i: Access the Database with Java and JDBC 2-25


Practice 2-2 (if you have time)
Changing methods
1. You can replace the use of executeQuery(), and executeUpdate()
methods by the execute() method.
2. Test the Boolean value returned by the execute statement and display a message
indicating the type of statement performed accordingly.

Oracle9i: Access the Database with Java and JDBC 2-26


More About JDBC

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

80 minutes Lecture
70 minutes Practice
150 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Define and describe the use of Oracle JDBC drivers
• Explore details about the ResultSet class and
methods
• Map database types and Java types
• Handle Database NULL values
• Manage Oracle Large Objects and Objects type
• Obtain database metadata and result set metadata
• Execute dynamic SQL statement

3-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
This lesson covers in a more detailed way the different steps that were described in the previous
lesson.
• You discover different types of drivers, and how to connect using each driver.
• You then, review the mapping between Oracle data types and Java types when performing a
query.
• You see how to work with large objects and other non relational objects stored in a database.
• Finally, you see how database metadata can be used to perform dynamic SQL.

Oracle9i: Access the Database with Java and JDBC 3-2


More on the Connect Stage

Load/Register
JDBC Driver

Connect

SQL statement SELECT


statement

Process
results

Close

3-3 Copyright © Oracle Corporation, 2002. All rights reserved.

More on the Connect Stage


In the previous lesson, you have seen a basic example of how you can connect to the database.
Other available techniques are described in this lesson.
Oracle9i: Access the Database with Java and JDBC 3-3
Connecting to the Database

Using the package oracle.jdbc.driver, Oracle


provides different drivers to establish a connection to
the database.
OracleDriver
Database
JDBC calls • Thin client commands
• OCI Database
• Server Based
•…

3-4 Copyright © Oracle Corporation, 2002. All rights reserved.

About JDBC Drivers

A JDBC driver implements the interfaces in the java.sql package, providing the code to
connect to and query a specific database. A JDBC driver can also provide a vendor’s own
extensions to the standard; Oracle drivers provide extensions to support special Oracle data types.
Oracle provides three drivers:
• Thin client driver
• OCI-based driver
• Server-based driver
The Oracle JDBC driver is located in the file classes111.zip for JDBC 1.0 or in the file
classes12.zip for JDBC 2.0. These archive files contain supporting classes for both the thin
and OCI JDBC drivers.
Supported JDK and JDBC versions
Oracle has two versions of the thin driver and the OCI driver—one that is compatible with
SDK 1.2 and one that is compatible with JDK 1.1.x. The J2SE versions support
standard JDBC 2.0. The JDK 1.1.x versions support most JDBC 2.0 features, but must
do so through Oracle extensions because JDBC 2.0 features are not available in JDK
1.1.x versions.
Notes
• The server-side internal driver supports J2SE.
• JDK 1.0.2 is no longer supported in the current drivers.
Oracle9i: Access the Database with Java and JDBC 3-4
Oracle JDBC Drivers: Thin Client Driver

• Written entirely in Java


• Must be used by applets

Applet

JDBC

Thin driver Oracle 9i

Client Server

3-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Thin Client Driver

This driver can connect to an Oracle9i database but also to either an Oracle7 database or an
Oracle8 database. You should use this driver if you are developing a client application that can
connect to different versions of an Oracle database, to provide maximum portability.
To communicate with the database, the thin client driver uses a lightweight version of SQL*Net or
Net8 over TCP/IP that can be downloaded at run time to the client.
The Oracle JDBC Thin driver is a 100% pure Java, Type IV driver. It is targeted for Oracle JDBC
applets but can be used for applications as well. Because it is written
entirely in Java, this driver is platform-independent. It does not require any additional Oracle
software on the client side. The thin driver communicates with the server using Two Task Common
(TTC), a protocol developed by Oracle to access the Oracle Relational Database management
System (RDBMS).
The JDBC Thin driver allows a direct connection to the database by providing an implementation
of TCP/IP that emulates Oracle Net and TTC (the wire protocol used by OCI) on top of Java
sockets. Both of these protocols are lightweight implementation versions of their counterparts on
the server. The Oracle Net protocol runs over TCP/IP only.
Note: When the JDBC Thin driver is used with an applet, the client browser must have the
capability to support Java sockets.
Oracle9i: Access the Database with Java and JDBC 3-5
Oracle JDBC Drivers: OCI Client Drivers

• Written in C and Java


• Must be installed on the client

Application

JDBC

OCI driver

Oracle 9i
ocixxx.dll

Client Server

3-6 Copyright © Oracle Corporation, 2002. All rights reserved.

OCI Client Drivers

• You should choose an OCI driver if you are developing an application and need
maximum performance.
• The JDBC OCI driver is a Type II driver for use with client-server Java applications.
• This driver requires an Oracle client installation, and therefore is Oracle
platform-specific and not suitable for applets.
• The JDBC OCI driver provides OCI connection pooling functionality, which can either
be part of the JDBC client or a JDBC stored procedure.
• The OCI driver supports Oracle7, Oracle8/8i, and Oracle9i with the highest
compatibility. It also supports all installed Oracle Net adapters, including IPC,
named pipes, TCP/IP, and IPX/SPX.
• The OCI driver, written in a combination of Java and C, converts JDBC invocations to
calls to the Oracle Call Interface (OCI), using native methods to call C-entry points.
These calls are then sent over Oracle Net to the Oracle database server. The OCI driver
communicate with the server using the Oracle-developed TTC protocol.
• The OCI driver uses the OCI libraries, C-entry points, Oracle Net, CORE libraries, and
other necessary files on the client machine on which it is installed.
Instructor Note
In Oracle9i, the OCI driver is a single OCI driver for use with all database versions. It replaces the
distinct OCI8 and OCI7 drivers of previous releases. While the OCI8 and OCI7 drivers are
deprecated for Oracle9i, they are still supported for backward compatibility.
Oracle9i: Access the Database with Java and JDBC 3-6
Oracle JDBC Drivers:
KPRB Server-Side Driver
• KPRB driver
• Runs inside the database
• Must be used by Java stored procedures

Oracle9i

Java Engine
Server Side Thin Driver Stored procedure

JDBC Server-side
Internal driver SQL
engine
C library

3-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Server-Side Internal Driver


The Oracle JDBC server-side internal driver is a type II driver. It supports any Java code that runs
inside an Oracle database, such as in a Java stored procedure or Enterprise JavaBean, and must
access the same database. This driver allows the Java virtual machine (JVM) to communicate
directly with the SQL engine.
The server-side internal driver, the JVM, the database, KPRB, C library, and the SQL engine all
run within the same address space, so the issue of network round trips is irrelevant. The programs
access the SQL engine by using function calls.
The server-side internal driver is fully consistent with the client-side drivers and
supports the same features and extensions.
Note: The server-side internal driver supports only SDK 1.2.x., whereas in Oracle9i, release 2 it
will support JDK 1.3.1
Instructor Note
KPRB stands for Kernel PRogrammatic interface Bundled operations.
Oracle9i: Access the Database with Java and JDBC 3-7
Oracle JDBC Drivers:
Thin Server-Side Driver

• Runs inside the database


• Used to access a remote database

Oracle9i

Java Engine
Server Side Thin Driver
JDBC Server-side
Internal driver SQL
engine
C library
Oracle 9i

3-8 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC Server-Side Thin Driver


The Oracle JDBC server-side Thin driver offers the same functionality as the client-side Thin
driver, but runs inside an Oracle database and accesses a remote database.
This is especially useful in two situations:
• To access a remote Oracle server from an Oracle server acting as a middle tier
• More generally, to access one Oracle server from inside another, such as from any Java stored
procedure or Enterprise JavaBean
There is no difference in your code between using the Thin driver from a client application or from
inside a server.
About Permission for the Server-Side Thin driver
The thin driver opens a socket to use for its connection. Because the Oracle server is enforcing the
Java security model, this means that a check is performed for a SocketPermission object.
To use the JDBC server-side Thin driver, the connecting user must be granted with the appropriate
permission. This is an example of how the permission can be granted to a user.
create role jdbcthin;
call
dbms_java.grant_permission(’JDBCTHIN’,’java.net.SocketPermission’,
’*’, ’connect’ );
grant jdbcthin to user;
Note that JDBCTHIN in the grant_permission call must be in upper case. The '*' is a pattern. It is
possible to limit the permission to allow connecting to specific machines or ports.

Oracle9i: Access the Database with Java and JDBC 3-8


Other JDBC Drivers

• JDBC-ODBC bridge:
– Translates JDBC to open database connectivity
(ODBC) calls
– Allows communication with existing ODBC drivers
when no JDBC driver is available
• Oracle Lite driver:
– For communication with an Oracle Lite database

3-9 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC-ODBC Bridge
The JDBC-ODBC bridge is a JDBC driver supplied by JavaSoft. It enables Java programs to use
JDBC with existing ODBC drivers. JavaSoft no longer supports this driver now that pure Java
drivers are available for all major databases.
Open Database Connectivity (ODBC) is a standardized API for connecting to SQL databases. It
was designed to enable development of database-independent applications.
Oracle Lite driver
The Oracle Lite driver is supplied with the Oracle Lite database. You must use this driver when
connecting to an Oracle Lite database.
The name of the JDBC driver to connect to Oracle9i Lite database is Driver Name:
oracle.lite.poljdbc.POLJDBCDriver (OLite 4.0).

Oracle9i: Access the Database with Java and JDBC 3-9


Choosing the Right Driver

Type of Program Driver

Applet Thin

Client application Thin OCI

Thin
EJB, servlet
(on the middle tier)
OCI

Stored procedure Server side

3-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Choosing the Appropriate Driver


Consider the following when choosing a JDBC driver to use for your application or applet:
• If you are writing an applet, you must use the JDBC Thin driver. JDBC OCI-based driver
classes will not work inside a Web browser, because they call native (C language) methods.
• If you want maximum portability and performance under Oracle9i and earlier, then use the
JDBC Thin driver. You can connect to an Oracle server from either an application or an applet
using the JDBC Thin driver.
• If you are writing a client application for an Oracle client environment and need maximum
performance, then choose the JDBC OCI driver.
• For code that runs in an Oracle server acting as a middle tier, use the server-side Thin driver.
• If performance is critical to your application, you want maximum scalability of the Oracle
server, or you need the enhanced availability features like Transparent Application Failover
(TAF) or the enhanced proxy features like middle-tier authentication, then choose the OCI
driver.
Oracle9i: Access the Database with Java and JDBC 3-10
About JDBC URLs

• JDBC uses a URL like string. The URL identifies


– The JDBC driver to use for the connection
– Database connection details, which varies depending
on the driver used.

jdbc:<subprotocol>:<subname>
Protocol Database Identification

jdbc:oracle:<driver>:@<database>
• Example using Oracle Thin JDBC driver:
– jdbc:oracle:thin:@myhost:1521:ORCL

3-11 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC URLs
JDBC uses a URL to identify the database connection. A JDBC URL looks different from an HTTP
or FTP URL, but like any URL it is a locator for a particular resource, in this case a database. The
structure of a JDBC URL is flexible, allowing the driver writer to specify what to include in the
URL. End users need to learn what structure their vendor uses.
The slide shows the general syntax for a JDBC URL and the syntax that Oracle uses for connecting
with an Oracle driver. The general syntax of a JDBC URL is as follows:
jdbc:<subprotocol>:<subname>
• jdbc is the protocol. All URLs start with their protocol.
• <subprotocol> is the name of a driver or database connectivity mechanism. Driver
developers register their subprotocols with JavaSoft to make sure that no one else uses the same
subprotocol name. For all Oracle JDBC drivers, the subprotocol is oracle.
• <subname> identifies the database. The structure and contents of this string are determined by
the driver developer. For Oracle JDBC drivers, the subname is <driver>:@<database>,
where:
– <driver> is the driver
– <database> provides database connectivity information
The following slides describe the syntax of an Oracle JDBC URL in for the different JDBC drivers
for client-side Java application code.
Oracle9i: Access the Database with Java and JDBC 3-11
JDBC URLs with Oracle Drivers

• Oracle Thin driver


Syntax: jdbc:oracle:thin:@<host>:<port>:<SID>
Example: "jdbc:oracle:thin:@myhost:1521:orcl"

• Oracle OCI driver


Syntax: jdbc:oracle:oci:@<tnsname entry>
Example: "jdbc:oracle:oci:@ORCL"

3-12 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC URLs with Oracle Drivers


The basic structure of the JDBC URL for connecting to a database using one of the Oracle JDBC
drivers is jdbc:<subprotocol>:<driver>:<database>.
Oracle Thin driver
<driver> is thin.
<database> is a string of the form <host>:<port>:<sid>. That is, it is the host name,
TCP/IP port, and Oracle SID of the database to which you want to connect. For example:
jdbc:oracle:thin:@eduhost:1521:ORCL
Oracle OCI driver
<driver> is oci, oci8 or oci7, depending on which OCI driver you are using.
<database> is a TNSNAMES entry from the tnsnames.ora file. For example:
jdbc:oracle:oci:@eduhost
Bridge ODBC-JDBC driver
Use the following syntax: jdbc:odbc:<datasource-name>
Note: For the thin and OCI drivers, <database> can also use the SQL name-value pair syntax. For
example:
(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=<hostname>
) (PORT=<port>)))(CONNECT_DATA=(SID=<sid>))
The server side driver is another type supported inside the Oracle database JVM implementation.
This driver will be discussed in the context of Java stored procedure lesson.

Oracle9i: Access the Database with Java and JDBC 3-12


Stage 4: More on Processing Result
for the Select
Load/Register
JDBC Driver

Connect

SQL statement SELECT


statement

Process
results

Close

3-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 3-13


How to Process the Results

1. Step through the result set.


while (rset.next()) { … }

2. Use getXXX() to get each column value.


String val =
rset.getString(colname);
= String val =
rset.getString(colIndex);

while (rset.next()) {

String ename = rset.getString("ENAME");


String empno = rset.getInt("EMPNO");
… // Process or display the data
}

3-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Obtaining the Column Values


Each of the getXXX() methods has two versions, allowing the programmer to specify the column
by number or by name.
• Specifying columns by number: When column numbers are used as input for the getXXX()
methods, the columns are numbered from 1.
• Specifying columns by name: When column names are used as input for the getXXX()
methods, the column names are case insensitive.
The column names option should be used when column names are used in the SQL query. For
columns that were not explicitly named in the query, it is better to use column numbers.
ResultSet provides a method called findColumn() that returns the column number for a
given column name.
getString
The example on the slide uses getString() to return the column values. getString() can
be used to retrieve any of the basic SQL data types. It is the easiest method to use for visual
applications, when you want to display or print the data. It can also be used when the end user will
update the data, which you then convert to a SQL UPDATE statement.
getBigDecimal
All of the getXXX() methods require a single parameter, except for
getBigDecimal(colname, scale) and getBigDecimal(colindex, scale), both
of which require a second parameter for the number of digits to the right of the decimal point.
Other getXXX() methods are covered in more detail later in this lesson.
Oracle9i: Access the Database with Java and JDBC 3-14
Mapping Database Types
to Java Types
ResultSet maps database types to Java types.
ResultSet rset = stmt.executeQuery
("SELECT empno, hiredate, job
FROM emp");
while (rset.next()){
int id = rset.getInt(1);
Date hiredate = rset.getDate(2);
String job = rset.getString(3);

Col Name Type Method

empno NUMBER getInt()

hiredate DATE getDate()

job VARCHAR2 getString()

3-15 Copyright © Oracle Corporation, 2002. All rights reserved.

Mapping Database Types to Java Types


In many cases, you can get all of the columns in your result set using the getObject() or
getString() methods of ResultSet. For performance reasons, or because you want to
perform complex calculations, it is sometimes important to have your data in a type that exactly
matches the database column.
The JDBC section of the Java tutorial contains a matrix that maps ResultSet.getXXX
methods to ANSI SQL types. For each SQL type, the matrix shows:
• Which getXXX methods can be used to retrieve the SQL type
• Which getXXX method is recommended to retrieve the SQL type
The Java tutorial is available online at
http://java.sun.com/docs/books/tutorial/index.html.
It is also published in two books; the JDBC section is in The Java Tutorial Continued.
Oracle9i: Access the Database with Java and JDBC 3-15
Table of ANSI SQL types and Java types
The following table lists the ANSI SQL types, the corresponding data type to use in Java, and the
name of the method to call in ResultSet to obtain that type of column value.

ANSI SQL Type Java Type ResultSet Method


CHAR, VARCHAR2 java.lang.String getString()
LONGVARCHAR java.io.InputStream getAsciiStream()

NUMERIC,DECIMAL java.math.BigDecimal getBigDecimal()

BIT boolean getBoolean()


TINYINT byte getByte()
SMALLINT short getShort()
INTEGER int getInt()
BIGINT long getLong()
REAL float getFloat()
DOUBLE,FLOAT double getDouble()

BINARY,VARBINARY byte[] getBytes()

LONGVARBINARY java.io.InputStream getBinaryStream()


DATE java.sql.Date getDate()
TIME java.sql.Time getTime()
TIMESTAMP java.sql.Timestamp getTimestamp()

Table of Oracle SQL types

ORACLE SQL Type Oracle Type Type Extension

NUMBER Oracle.Types.NUMBER oracle.sql.NUMBER


CHAR Oracle.Types.CHAR oracle.sql.CHAR
RAW Oracle.Types.RAW oracle.sql.RAW
DATE Oracle.Types.DATE oracle.sql.DATE
ROWID Oracle.Types.ROWID oracle.sql.ROWID
BLOB Oracle.Types.BLOB oracle.sql.BLOB
CLOB Oracle.Types.CLOB oracle.sql.CLOB
BFILE n/a oracle.sql.BFILE
Structured object Oracle.Types.STRUCT oracle.sql.STRUCT
Object reference Oracle.Types.REF oracle.sql.REF
Collection(array) Oracle.Types.ARRAY oracle.sql.ARRAY
Oracle9i: Access the Database with Java and JDBC 3-16
How to Handle SQL Null Values

• Java primitive types cannot have null values.


• Do not use a primitive type when your query might
return a SQL null value.
• Use ResultSet.wasNull() to determine whether
a column has a null value.
while (rset.next()) {
int empno = rset.getInt("empno");
if (rset.wasNull()) {
… // Handle null value
}
…}

3-17 Copyright © Oracle Corporation, 2002. All rights reserved.

Handling SQL Null Values


If your query could return a SQL null value, you should use a getXXX() method that returns an
object type, not one that returns a Java primitive.
The example in the slide shows how to use ResultSet.wasNull() to determine whether a
column has a null value. Note that you must call getXXX() to read the column’s value before you
can determine whether it has a null value.

Oracle9i: Access the Database with Java and JDBC 3-17


Advanced Data Types

• Oracle JDBC drivers support object data.


– oracle.sql (classes to support all Oracle type
extensions)
– oracle.jdbc (interfaces to support database
access and updates in Oracle type formats)
• JDK 1.1 has problems supporting object data:
– Use oracle.jdbc2 package with JDK 1.1.
• The SDK 1.2 package java.sql supports object
data:
– The oracle.jdbc2 package is not included.
– Upgrading can require updating and recompiling of
code.

3-18 Copyright © Oracle Corporation, 2002. All rights reserved.

Advanced Data Types


Oracle provides two implementations of its JDBC drivers—one that supports Sun
Microsystems’ JDK 1.2.x and complies with the Sun JDBC 2.0 standard, and another that
supports JDK 1.1.x and complies with the Sun JDBC 1.22 standard.
Beyond standard features, Oracle JDBC drivers provide Oracle-specific type extensions and
performance extensions.
Both implementations include the following Java packages:
oracle.sql (classes to support all Oracle type extensions)
oracle.jdbc (interfaces to support database access and updates in Oracle type formats)
In addition to these packages, the implementation for JDK 1.1.x includes the following Java
package. This package supports some JDBC 2.0 features by providing interfaces that mimic the
JDBC 2.0 interfaces in the standard java.sql package:
oracle.jdbc2 (interfaces equivalent to standard JDBC 2.0 interfaces)
If you use the oracle.jdbc2 package then upgrading requires updating and recompiling of
code. To avoid this, you can use the classes supplied in oracle.sql instead.

Oracle9i: Access the Database with Java and JDBC 3-18


Working with Large Objects

• Oracle provides corresponding Getter and Setter


methods to manipulate BLOBs and CLOBs
• Data access is performed through a locator
• Getting the LOB locator:
ResultSet rs =
stmt.executeQuery ("SELECT blob_col, clob_col
FROM lob_table");
while (rs.next())
{
// Get LOB locators into Java wrapper classes.
BLOB myBlob = ((OracleResultSet)rs).getBLOB(1);
CLOB myClob = ((OracleResultSet)rs).getCLOB(2);
(... process...)

3-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle Extensions for LOBs and BFILEs


LOBs (large objects) are stored in a way that optimizes space and provides efficient access. The
JDBC drivers provide support for two types of LOBs: BLOBs (unstructured binary data) and
CLOBs (character data). BLOB and CLOB data is accessed and referenced by using a locator,
which is stored in the database table and points to the BLOB or CLOB data, which is outside the
table.
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 these oracle.sql.* classes for BLOBs, CLOBs, and
BFILEs:
oracle.sql.BLOB
oracle.sql.CLOB
The oracle.sql.BLOB and CLOB classes implement the java.sql.Blob and
Clob interfaces, respectively (oracle.jdbc2.Blob and Clob interfaces under
JDK 1.1.x).
Note: All kind of examples of working code using large objects are available in the
<ORACLE_HOME>/jdbc/demo/ directory. (There are examples for BLOB, CLOB, and so on.)

Oracle9i: Access the Database with Java and JDBC 3-19


Reading BLOBs

Use getBinaryStream() method to read BLOB data


from the BLOB locator.
// Read BLOB data from BLOB locator.
InputStream byte_stream =
myBlob.getBinaryStream();
byte [] byte_array = new byte [10];
int bytes_read = byte_stream.read(byte_array);
...

3-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Reading BLOBs
The following example uses the getBinaryStream() method to read BLOB data
into a byte stream and then reads the byte stream into a byte array (returning the
number of bytes read, as well).
Once you have a LOB locator, you can use JDBC methods to read and write the LOB data. LOB
data is materialized as a Java array or stream. However, unlike most Java streams, a locator
representing the LOB data is stored in the table. Thus, you can access the LOB data at any time
during the life of the connection.
To read and write the LOB data, use the methods in the oracle.sql.BLOB or
oracle.sql.CLOB class, as appropriate. These classes provide functionality such as reading
from the LOB into an input stream, writing from an output stream into a LOB, determining the
length of a LOB, and closing a LOB.
Note
• The implementation of the data access API uses direct native calls in the JDBC OCI and server-
side internal drivers, thereby providing better performance. You can use the same API on the
LOB classes in all Oracle JDBC drivers.
• In the case of the JDBC Thin driver only, the implementation of the data access API uses the
PL/SQL DBMS_LOB package internally. You never have to use DBMS_LOB directly. This is
in contrast to the 8.0.x drivers. For more information on the DBMS_LOB package, see the
Oracle9i Supplied PL/SQL Packages Reference.

Oracle9i: Access the Database with Java and JDBC 3-20


Writing BLOBs

Use getBinaryOutputStream() method to write


BLOB data.
java.io.OutputStream outstream;
// read data into a byte array
byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// write the array of binary data to a BLOB
outstream =
((BLOB)myBlob).getBinaryOutputStream();
outstream.write(data);
...

3-21 Copyright © Oracle Corporation, 2002. All rights reserved.

Writing BLOBs
To write to a BLOB, use the getBinaryOutputStream() method of an
oracle.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.

Oracle9i: Access the Database with Java and JDBC 3-21


Reading CLOBs

CLOBs are readable using two different methods:


• Using the getCharacterStream() method
Reader char_stream = myClob.getCharacterStream();
char [] char_array = new char [10];
int chars_read = char_stream.read (char_array, 0, 10)

• Using the getAsciiStream() method


Inputstream asciiChar_stream =
myClob.getAsciiStream();
byte[] asciiChar_array = new byte[10];
int asciiChar_read =
asciiChar_stream.read(asciiChar_array,0,10);

3-22 Copyright © Oracle Corporation, 2002. All rights reserved.

Reading CLOBs
To read from a CLOB, use the getAsciiStream() or getCharacterStream() method of
an oracle.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 oracle.sql.CLOB object to retrieve a
subset of the CLOB as a character string of type java.lang.String.

Oracle9i: Access the Database with Java and JDBC 3-22


Writing CLOBs

CLOBs are writeable using two different methods:


• Using getCharacterOutputStream() method
char[] data = {’0’,’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’};
writer = ((CLOB)myClob).getCharacterOutputStream();
writer.write(data);
writer.flush();
writer.close();

• Using getAsciiOutputStream() method


byte[] data = {’0’,’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’};
out = ((CLOB)myClob).getAsciiOutputStream();
out.write(data);
out.flush();
out.close();

3-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Writing CLOBs
To write to a CLOB, use the getAsciiOutputStream() or
getCharacterOutputStream() method of an oracle.sql.CLOB object to retrieve the
CLOB as an output stream to be written back to the CLOB. The getAsciiOutputStream()
method returns an ASCII output stream in a java.io.OutputStream object. The
getCharacterOutputStream() method returns a Unicode output stream in a
java.io.Writer object.
As with any OutputStream 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.
Note: 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, the JDBC drivers perform all character set conversions
for you.

Oracle9i: Access the Database with Java and JDBC 3-23


Populating LOBs in a New Table
from Files

1. Use empty_blob() method to create the BLOB


locator entry in the table
2. Get the BLOB locator from the table
3. Declare the file and determine its length
4. Create a FileInputStream object to read the file
5. Create an OutputStream object to load the stream
6. Use getBufferSize() to retrieve best buffer size
7. Create a buffer byte array with the best buffer size
length
8. Use read() and write() methods
9. Close input and output streams

3-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Code Example
This example demonstrates how to populate a BLOB or CLOB column by reading data from a
stream. These steps assume that you have already created your Connection object conn and
Statement object stmt. The following example writes the GIF file john.gif to a BLOB.
1. Begin by using SQL statements to create the BLOB entry in the table. Use the empty_blob
syntax to create the BLOB locator.
stmt.execute ("INSERT INTO my_blob_table VALUES (’row1’,
empty_blob())");
2. Get the BLOB locator from the table.
BLOB blob;
cmd = "SELECT * FROM my_blob_table WHERE X=’row1’";
ResultSet rest = stmt.executeQuery(cmd);
BLOB blob = ((OracleResultSet)rset).getBLOB(2);
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 GIF 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.getBinaryOutputStream();

Oracle9i: Access the Database with Java and JDBC 3-24


Code Example (continued)
4. Call getBufferSize() to retrieve the ideal buffer size (according to calculations by the
JDBC driver) 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 GIF 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.
while ((length = instream.read(buffer)) != -1)
outstream.write(buffer, 0, length);
instream.close();
outstream.close();

Oracle9i: Access the Database with Java and JDBC 3-25


Working with BFILEs

• Oracle provides corresponding Getter and Setter


methods to manipulate BFILEs locator
• Getting the LOB locator:
// Select the BFILE locator into a result set
ResultSet rs = stmt.executeQuery
("SELECT bfile_col FROM bfile_table");
while (rs.next())
{
oracle.sql.BFILE myBfile =
((OracleResultSet)rs).getBFILE(1);
}

3-26 Copyright © Oracle Corporation, 2002. All rights reserved.

Working with BFILEs


Similarly to BLOBs and CLOBs, access to BFILEs is performed through a locator.
Following is the syntax used to specify the physical of the bfile file to be used when inserting or
updating a bfile column in a table.
Make sure you have the rights to create and drop directory
stmt.execute ("drop directory TEST_DIR");
stmt.execute ("create directory TEST_DIR as 'c:/labs'");
Use the directory object in the DML statement.
stmt.execute ("UPDATE bfile_table SET bfilecol = (bfilename
('TEST_DIR', 'Oracle.gif'))");

Oracle9i: Access the Database with Java and JDBC 3-26


Reading BFILEs

To read files use:


• openFile()method to open the file
• getBinaryStream()to retrieve the file as an
input stream
• read()method to read file data
• close()method for the stream and the file when
finished

3-27 Copyright © Oracle Corporation, 2002. All rights reserved.

Reading BFILES Code Example


BFILE bfile = ((OracleResultSet)rset).getBFILE(1);
bfile.openFile();
Inputstream in = bfile.getBinaryStream();
Int length;
byte[] buf = new byte[6];
while ((length = in.read(buf)) != -1)
{

// append and display the bfile data in 6-byte chunks


StringBuffer sb = new StringBuffer(length);
for (int i=0; i<length; i++)
sb.append( (char)buf[i] );
}

in.close();
bfile.closeFile();

Oracle9i: Access the Database with Java and JDBC 3-27


Working with Oracle Objects

You need a Java class to map the Oracle Object:


• You can use standard JDBC mapping
– The STRUCT class
• Customize Java classes to map the Oracle Object
– Using java.sql.SQLData interface
– Using oracle.java.ORAData interface

3-28 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle Objects
JDBC materializes Oracle objects as instances of particular Java classes. Two main steps in using
JDBC to access Oracle objects are:
• Creating Java classes for the Oracle objects
• Populating these Java classes.
In order to perform these steps, you have two options:
• Let JDBC materialize the object as a STRUCT.
• Explicitly specify the mappings between Oracle objects and Java classes. This includes
customizing your Java classes for object data. The driver then must be able to populate
instances of the custom object classes that you specify. This imposes a set of constraints on the
Java classes. To satisfy these constraints, you can define your classes to implement either the
JDBC standard java.sql.SQLData interface or the Oracle extension
oracle.sql.ORAData interface.

Oracle9i: Access the Database with Java and JDBC 3-28


Oracle Objects (continued)
If you choose not to supply a custom Java class for your SQL-Java mapping for an Oracle object,
then Oracle JDBC will materialize the object as an instance of the oracle.sql.STRUCT class.
You would typically want to use STRUCT objects, instead of custom Java objects, in situations
where you are manipulating SQL data. For example, your Java application might be a tool to
manipulate arbitrary object data within the database, as opposed to being an end-user application.
You can select data from the database into STRUCT objects and create STRUCT objects for
inserting data into the database.
STRUCT objects completely preserve data, because they maintain the data in SQL format. Using
STRUCT objects is more efficient and more precise in these situations where you don’t need the
information in a convenient form.
Note: While using STRUCT is more flexible for handling Object types in a very generic way,
using JPublisher to generate a Java class for database objects is quite easier and practical.

Oracle9i: Access the Database with Java and JDBC 3-29


STRUCT Object and Descriptor

• Create a STRUCT descriptor per Oracle Object type


StructDescriptor structdesc =
StructDescriptor.createDescriptor
(sql_type_name, connection);
• Construct the STRUCT object
STRUCT struct = new STRUCT(structdesc,
connection, attributes);
StructDescriptor addressDesc=
StructDescriptor.createDescriptor
("ADDRESS", conn);
STRUCT address = new STRUCT
(addressDesc, conn, address_attributes);

3-30 Copyright © Oracle Corporation, 2002. All rights reserved.

STRUCT Object and Descriptor


Before you can construct a STRUCT object, a StructDescriptor must first exist for the given
Oracle object type. You can create one by calling the static
StructDescriptor.createDescriptor() method. This method requires you to pass in
the SQL type name of the Oracle object type and a connection object:
StructDescriptor structdesc =
StructDescriptor.createDescriptor
( sql_type_name, connection);
Where sql_type_name is a Java string containing the name of the Oracle object type (such as
EMPLOYEE) and connection is your connection object.
Once you have your StructDescriptor object for the Oracle object type, you can construct
the STRUCT object. To do this, pass in the StructDescriptor, your connection object, and an array
of Java objects containing the attributes you want the STRUCT to contain.
STRUCT struct = new STRUCT(structdesc, connection, attributes);
Where structdesc is the StructDescriptor created previously, connection is your connection
object, and attributes is an array of type java.lang.Object[].

Oracle9i: Access the Database with Java and JDBC 3-30


STRUCT Object and Descriptor (continued)
Using StructDescriptor methods
A StructDescriptor can be thought of as a “type object”. This means that it contains information
about the object type, including the typecode, the type name, and how to convert to and from the
given type. Remember, there should be only one StructDescriptor object for any one Oracle object
type. You can then use that descriptor to create as many STRUCT objects as you need for that type.
The StructDescriptor class includes the following methods:
• getName(): Returns the fully qualified SQL type name of the Oracle object (that is, in
schema.sql_type_name format, such as CORPORATE.EMPLOYEE)
• getLength(): Returns the number of fields in the object type
• getMetaData(): Returns the meta data regarding this type (like the getMetaData()
method of a result set object)
The returned ResultSetMetaData object contains the attribute name, attribute typecode, and
attribute type precision information. The “column” index in the ResultSetMetaData object maps to
the position of the attribute in the STRUCT, with the first attribute being at index 1.
Retrieving an Oracle Object as an oracle.sql.STRUCT object
You can retrieve an Oracle object directly into an oracle.sql.STRUCT instance. In
the following example, getObject() is used to get a NUMBER object from column 1 (col1) of
the table struct_table. Because getObject() returns an Object type, the return is cast to
an oracle.sql.STRUCT. This example assumes that the Statement object stmt has already
been created.
// Creating an Oracle Object
String cmd;
cmd = "CREATE TYPE type_struct AS object (field1 NUMBER,field2
DATE)";
stmt.execute(cmd);
cmd = "CREATE TABLE struct_table (col1 type_struct)";
stmt.execute(cmd);
cmd = "INSERT INTO struct_table VALUES (type_struct(10,’01-apr-
01’))";
stmt.execute(cmd);
cmd = "INSERT INTO struct_table VALUES (type_struct(20,’02-may-
02’))";
stmt.execute(cmd);
// Querying the Oracle Object
ResultSet rs= stmt.executeQuery("SELECT * FROM struct_table");
oracle.sql.STRUCT oracleSTRUCT=(oracle.sql.STRUCT)rs.getObject(1);
oracle.sql.Datum[] attrs = oracleSTRUCT.getOracleAttributes();

Oracle9i: Access the Database with Java and JDBC 3-31


Working with Oracle Object References

To retrieve an Object Reference from a Result Set:


• Create a SELECT statement
• Use getRef() to get the pointer reference
• Map the referenced type to Java types
• Use getValue() to retrieve the content
ResultSet rs = stmt.executeQuery
("SELECT col3 FROM person");
while (rs.next())
{
REF ref = ((OracleResultSet)rs).getREF(1);
Address a = (Address)ref.getValue();
}

3-32 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle Object References


You can use the REF object setValue() method to update the value of an object in
the database through an object reference. To do this, you must first retrieve the reference to the
database object and create a Java object (if one does not already exist) that corresponds to the
database object.
For example, you can retrieve the reference to a database ADDRESS object:
ResultSet rs = stmt.executeQuery
("SELECT col3 FROM PEOPLE");
if (rs.next())
{

REF ref = rs.getREF(1);


Address a = (Address)ref.getValue();
}

Then, you can create a Java Address object (this example omits the content for the constructor of
the Address class) that corresponds to the database ADDRESS object.
Use the setValue() method of the REF class to set the value of the database object:
Address addr = new Address(...);
ref.setValue(addr);
Here, the setValue() method updates the database ADDRESS object immediately.

Oracle9i: Access the Database with Java and JDBC 3-32


Working with Oracle Collections

• Oracle collections are:


– VARRAY for an ordered set of a defined type with a
defined number of elements
– Nested table for an unordered set of data elements of
the same data type
• The Oracle.sql.ARRAY interface provides
methods to manipulate Oracle collections:
– setARRAY()
– getARRAY()

3-33 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle Collections
You can obtain collection data in an array instance through a result set or callable statement and
pass it back as a bind variable in a prepared statement or callable statement.
The oracle.sql.ARRAY class, which implements the standard java.sql.Array interface
(oracle.jdbc2.Array interface under JDK 1.1.x), provides the necessary functionality to
access and update the data of an Oracle collection (either a VARRAY or nested table).
This section discusses the following:
• Statement and result set getter and setter methods for passing collections to and from the
database as Java arrays
• ARRAY descriptors and ARRAY class methods
Remember that you can use custom collection classes instead of the ARRAY class.

Oracle9i: Access the Database with Java and JDBC 3-33


Working with ARRAYS

Working with arrays is done with:


• Array descriptors
– Create one per SQL type
• Array Class Methods
– getDescriptor()
– getOracleArray() for VARRAYS
– getSQLTypeName()
– getResultSet() for nested tables
– length()

3-34 Copyright © Oracle Corporation, 2002. All rights reserved.

ARRAY Descriptors
Creating and using an ARRAY object requires the existence of a descriptor—an instance of the
oracle.sql.ArrayDescriptor class—to exist for the SQL type of the collection being
materialized in the array.
You need only one ArrayDescriptor object for any number of ARRAY objects that correspond
to the same SQL type.
ARRAY class methods
The oracle.sql.ARRAY class includes the following methods:
• getDescriptor(): Returns the ArrayDescriptor object that describes the array type
• getArray(): Retrieves the contents of the array in “default” JDBC types. If it retrieves an
array of objects, then getArray() uses the default type map of the database connection
object to determine the types
• getOracleArray(): Identical to getArray(), but retrieves the elements in oracle.sql.*
format
• getBaseType(): Returns the SQL typecode for the array elements
• getBaseTypeName(): Returns the SQL type name of the elements of this array.
• getSQLTypeName() (Oracle extension): Returns the fully qualified SQL type name of the
array as a whole
• getResultSet(): Materializes the array elements as a result set
• getJavaSQLConnection(): Returns the connection instance (java.sql.Connection)
associated with this array
• length(): Returns the number of elements in the array.

Oracle9i: Access the Database with Java and JDBC 3-34


Manipulating ARRAYS
ArrayDescriptor desc = ArrayDescriptor.createDescriptor
("NUM_VARRAY", conn);
ResultSet rs = stmt.executeQuery
("SELECT * FROM varray_table");
ARRAY array = ((OracleResultSet)rs).getARRAY (1);
System.out.println ("Array is of type “
+array.getSQLTypeName());
System.out.println ("Array element is of type code “
+array.getBaseType());
System.out.println
("Array is of length "+array.length());
// get Array elements
BigDecimal[] values = (BigDecimal[]) array.getArray();
for (int i=0; i<values.length; i++)
{
BigDecimal value = (BigDecimal) values[i];
System.out.println(">> index "+i+" = “
+value.intValue());

3-35 Copyright © Oracle Corporation, 2002. All rights reserved.

Code Example
Following is the code that is used to create an array object type in the database. The slide shows
how to access and use the corresponding database object.
stmt.execute ("CREATE TYPE num_varray AS VARRAY(10) OF
NUMBER(12, 2)");
stmt.execute ("CREATE TABLE varray_table (col1 num_varray)");
stmt.execute ("INSERT INTO varray_table VALUES (num_varray(100,
200))");
// create a new ARRAY object
int elements[] = { 300, 400, 500, 600 };
ArrayDescriptor desc =
ArrayDescriptor.createDescriptor("NUM_VARRAY", conn); ARRAY
newArray = new ARRAY(desc, conn, elements);
PreparedStatement ps = conn.prepareStatement ("insert into
varray_table values (?)");
((OraclePreparedStatement)ps).setARRAY (1, newArray);
ps.execute ();

Oracle9i: Access the Database with Java and JDBC 3-35


The DatabaseMetaData Object

• The Connection object can be used to get a


DatabaseMetaData object.
• This object provides more than 100 methods for
obtaining information about the database.
• This object is useful for dynamic SQL.

3-36 Copyright © Oracle Corporation, 2002. All rights reserved.

Metadata
Metadata is data about data. In JDBC, you use the Connection.getMetaData() method to
return a DatabaseMetaData object. The DatabaseMetaData class contains more than 100
methods for obtaining information about a database.
The following are some examples of DatabaseMetaData methods:
• getColumnPrivileges(): Gets a description of the access rights for a table’s columns
• getColumns(): Gets a description of table columns
• getDatabaseProductName(): Gets the name of this database product
• getDriverName(): Gets the name of this JDBC driver
• storesLowerCaseIdentifiers(): Reports whether the database stores mixed-case
SQL identifiers in lowercase
• supportsAlterTableWithAddColumn(): Reports whether ALTER TABLE with an add
column is supported
• supportsFullOuterJoins(): Reports whether full nested outer joins are supported
Instructor Note
If the students are interested, you could show the javadoc for java.sql.DatabaseMetaData
to give them some sense of the available methods.

Oracle9i: Access the Database with Java and JDBC 3-36


How to Obtain Database Metadata

1. Get the DatabaseMetaData object.

DatabaseMetaData dbmd = conn.getMetaData();

2. Use the object’s methods to get the metadata.


DatabaseMetaData dbmd = conn.getMetaData();
String s1 = dbmd.getURL();
String s2 = dbmd.getSQLKeywords();
boolean b1 = dbmd.supportsTransactions();
boolean b2 = dbmd.supportsSelectForUpdate();
...

3-37 Copyright © Oracle Corporation, 2002. All rights reserved.

Database Metadata
You may need to know what features are supported for the database you are connected to. The
DatabaseMetaData class provides all kinds of methods allowing you to get information about
the database environment.
The example in the slide shows the general steps involved in obtaining information about the
database. Assuming that the connection has already been opened earlier in the program, this
example gets a DatabaseMetaData object from the Connection object and then calls some
of the methods on the DatabaseMetaData object.
For example, getSQLKeywords() returns a comma-separated list of all of the database’s SQL
keywords that are not SQL92 keywords. The supportsTransactions() method reports
whether transactions can be issued against the database.

Oracle9i: Access the Database with Java and JDBC 3-37


The ResultSetMetaData Object For
Dynamic SQL

• Processing the result of a dynamic SELECT


statement requires to know info about what is
retrieved by the query, like:
– The number of columns
– The data type of each column
– The name of the column
• The ResultSet object can be used to get a
ResultSetMetaData object
• The ResultSetMetaData object provides
metadata
• Metadata gives the information to process a
dynamic SELECT

3-38 Copyright © Oracle Corporation, 2002. All rights reserved.

Result Set Metadata


In JDBC, you use the ResultSet.getMetaData() method to return a
ResultSetMetaData object, which describes the data retrieved from a database query. This
object can be used to find out about the types and properties of the columns in your result set.

Oracle9i: Access the Database with Java and JDBC 3-38


How to Obtain Result Set Metadata

1. Get the ResultSetMetaData object.


2. Use the object’s methods to get the metadata.

ResultSetMetaData rsmd = rset.getMetaData();

ResultSetMetaData rsmd = rset.getMetaData();


int nbrColumns = rsmd.getColumnCount();
for (int i = 1; i <= nbrColumns; i++) {
String colname = rsmd.getColumnName(i);
int coltype = rsmd.getColumnType(i);

}

3-39 Copyright © Oracle Corporation, 2002. All rights reserved.

Example
The example in the slide shows how to use a ResultSetMetaData object to determine the
following information about the result set:
• The number of columns in the result set
• The name of each column
• The American National Standards Institute (ANSI) SQL type for each column
Following is a subset of the available methods with the ResultSetMetadata object:
• java.lang.String getCatalogName(int column) What's a column's table's
catalog name?
• java.lang.String getColumnType(int column) What's a column's SQL type?
java.lang.String getTableName(int column) What's a column's table name?
• Int isNullable(int column) Can you put a NULL in this column?
java.sql.Types
The java.sql.Types class defines constants that are used to identify ANSI SQL types.
ResultSetMetaData.getColumnType() returns an integer value that corresponds to one
of these constants.
The DBType structure holds the ORACLE type number (VARCHAR is 1) and we need to convert
it to the Java type number (VARCHAR is 12).
The Oracle SQL Reference Manual contains tables that show how ANSI SQL data types map to
Oracle SQL data types.

Oracle9i: Access the Database with Java and JDBC 3-39


Summary of JDBC Classes and Interfaces

DriverManager

URL

Connection Driver+Database+Id

Statement
Oracle9i

ResultSet

3-40 Copyright © Oracle Corporation, 2002. All rights reserved.

Summary of JDBC Classes and Interfaces


DriverManager
DriverManager provides access to registered JDBC drivers. DriverManager hands out
connections to a specified data source through its getConnection() method.
Connection
The Connection class is provided by the JDBC driver, as are all subsequent classes mentioned.
A Connection object represents a session with a database and is used to create a Statement
object, using Connection.createStatement().
Statement
The Statement class executes SQL statements. For example, queries can be executed using the
executeQuery() method, and the results are wrapped up in a ResultSet object.
ResultSet
JDBC returns the results of a query in a ResultSet object. A ResultSet object maintains a
cursor pointing to its current row of data. The next() method moves the cursor to the next row.
The ResultSet class has getXXX() methods to retrieve the columns in the current row.
Oracle9i: Access the Database with Java and JDBC 3-40
Summary

• Different drivers are available to connect to the


database, each one requires a specific URL syntax
• When performing a query, Java classes exist to map the
database data type with a corresponding Java type
• Handle null with non primitive Java types
• Use input/output Stream methods to read/write CLOB
and BLOB columns
• The STRUCT class maintain an object in its SQL format
• Define and describe the use of the Oracle JDBC drivers
• The database metadata provides information about the
database environment
• The result set metadata provides information about
schema objects

3-41 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 3-41


Practice 3: Part I Overview

This practice covers:


• Experimenting other drivers and alternative ways
to register drivers

3-42 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 3-42


Practice 3-1
Goal
The goal of this practice is to test alternative ways to register the driver and also to experiment
other drivers.
Your assignment
You use the Practice2 class that you used in the previous lesson. In this class, you specify
the code to register the driver using the Class.forName method. You also register the
driver at launch time, and finally you change the thin driver for the OCI one.
Getting started
1. Open an MS-DOS window
– Run the myjdbc.bat file previously created
– Move to the E:\labs directory
Create the java class
2. Open Notepad
3. Open the Practice2.java file using File|open menu option
4. Update the java code
– Change the name of the class to Practice3thin
public class Practice3thin
– Change the following code so that you register the driver using the
Class.forName syntax:
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
// Register the Oracle JDBC driver
try{ Class.forName
("oracle.jdbc.driver.OracleDriver");
}

catch (ClassNotFoundException e){}


Edit and run your Java application
5. Save the file in the E:\labs directory with the name Practice3thin.java, using
File|Save menu option, but keep Notepad running, you will need it again.
6. Compile the Practice3thin.java file (filename capitalization is important)
a. In the MS-DOS window, ensure the current directory is E:\labs
b. Check that the Java source file is saved to disk.
c. Compile the file using command: javac Practice3thin.java
d. What file is created if you successfully compiled the code?
7. Run the Practice3thin application.
a. Run the file using command: java Practice3thin
b. What is displayed in the MS-DOS window?

Oracle9i: Access the Database with Java and JDBC 3-43


Practice 3-1 (continued)
Register the driver at launch time
8. Go back to the Practice3thin file using Notepad
9. Comment out the statements registering the driver
10. Save your file
Edit and run your Java application
11. Save the file in the E:\labs directory with the name Practice3thin.java,
using File|Save menu option, but keep notepad running, you will need it again.
12. Compile the Practice3thin.java file
13. Run the Practice3thin application.
a. Run the file using command: java –Djdbc.drivers option java –
Djdbc.drivers=oracle.jdbc.OracleDriver Practice3thin
b. Did the class execute?
Using the OCI driver
14. Go back to the Practice3thin file using notepad
– Change its name to Practice3oci
– Remove the comments in front of the registering driver statements
– Update the URL so that if uses the OCI driver
String url = "jdbc:oracle:oci:@SID";
Edit and run your Java application
15. Save the file in the E:\labs directory with the name Practice3oci.java, using
File|Save menu option, but keep Notepad running, you may need it again
16. Compile the Practice3oci.java file
17. Run the Practice3oci application

Oracle9i: Access the Database with Java and JDBC 3-44


Practice 3: Part II Overview

This practice covers the following topics:


• Writing a class that uses JDBC to:
– Connect to the database
– Create a table that contains a BLOB
– Populate the table
– Execute a select statement
– Copy the results to an array
– Test the results by displaying the size of the array
• Writing an application to test your class
– Display the size of the BLOB
– Display the size of the array

3-45 Copyright © Oracle Corporation, 2002. All rights reserved.

Practice 3 Part II Overview


In this practice, you will write a class that uses JDBC to connect to the database, execute a
SELECT statement, copy the results to an array, display the size of the array and disconnect from
the database. You will also write an application to test your class.
The SELECT statement finds information about pictures; you will find the name of the picture.
The method in your class that executes the query returns the results in an array, not in a JDBC
result set. This means that the calling class, which might be a form, does not need to know
anything about JDBC.
Note: The instructions for the practice are followed by a page of hints. Use these hints if you need
to review the JDBC statements that you learned in this lesson, or if you need help with any of the
code in the practice.
Instructor Note
For practice 3-4 concerning the BFILE, the oracle.gif file that is used for this practice is only
accessible if it is stored on the server where the database is running. You have to log on to UNIX,
locate for the full path name of the home directory where the oracle.gif file resides, then go
into SQL*Plus and create the directory object for all the students ( since this is a system wide
object, not a schema object). The location of the file follows the following organization:
/homeX/teachYY.
Once the file is located, issue the following statements using SQL*Plus:
SQL> create directory TEST_DIR as '/home1/teach21';
Directory created.
SQL> grant read on directory TEST_DIR to public;
Grant succeeded.

Oracle9i: Access the Database with Java and JDBC 3-45


Practice 3-2 Overview

Oracle.gif

3-46 Copyright © Oracle Corporation, 2002. All rights reserved.

Practice 3 Part II
Goal
The goal of this practice is to manipulate BLOB and BFILE type columns.
Your assignment
Oracle.gif is the file which is to be loaded into a BLOB column. Before loading it into the
BLOB column, you have a look at the file content and about its size.
Once loaded in the BLOB column, you read its content and get the size of it to verify that you were
able to retrieve the information
Finally you read the .gif file and load it into a BFILE column.
Locate the file and determine its size
Viewing the file size
• Open Windows NT navigator
• Locate the E:\labs directory
• What is the exact size of the oracle.gif file?
In the Navigator the rounded size appears to be 138k
If you Right Mouse click on the file name and select the properties menu option, the exact size
of this file is 140.309 bytes.

Oracle9i: Access the Database with Java and JDBC 3-46


Practice 3-2
Use the following applet and HTML file to view the picture.
Setting up the environment
1. Open the MS-DOS window
– Click Start on the taskbar
– Select the Start MS/DOS option
– Run the myjdbc.bat file
– Move to the E:\labs directory

Edit a Java applet to display the image


• Open Notepad to display the code of the file LoadPicture.java
import java.applet.Applet;
import java.awt.*;
import javax.swing.*;
public class LoadPicture extends JApplet
{

private Image picture;


// load image when applet is loaded
public void init()
{

picture = getImage( getDocumentBase(),


"oracle.gif" );
}

public void paint( Graphics g )


{
// display image
g.drawImage( picture, 50, 50, this );
// draw original image
}

// end class LoadPicture


• Close the file.

Oracle9i: Access the Database with Java and JDBC 3-47


Practice 3-2 (continued)
Edit an HTML file that starts the applet to display the image
• Open the Notepad to display the code of the file LoadPicture.html
<HTML>
<HEAD>
<TITLE>
ORACLE
</TITLE>
</HEAD>
<BODY>
<APPLET CODE="LoadPicture.class" width = "750"
height = "500">
</APPLET>
</BODY>
</HTML>
• Close the file.
Compile the Java class and run the applet
1. Compile the Java program
Type the following syntax in the MS-DOS window:
E:\Labs> Javac LoadPicture.java
2. Run the HTML file with appletviewer
Type the following syntax in the MS-DOS window:
E:\labs> appletviewer LoadPicture.html

Oracle9i: Access the Database with Java and JDBC 3-48


Practice 3-2 (continued)
Start JDeveloper.
• Double-click the JDeveloper icon on the desktop
Open a workspace in JDeveloper.
• Close previously opened workspace, if any.
• Open the workspace Lesson03.jws and open the project Blob.jpr.
Create class LobToTable and add statement and connection instance variables.
• Create a new class, LobToTable and accept the default package name
• Add an import statement to import the JDBC classes.
Select Projects | Project Properties in the menu options
Select Libraries option
Scroll down and choose the Oracle JDBC line, then click OK
Create the database connection.
1. Add a method, getConnection()to connect to the database using the URL, username and
password your instructor provided you with.
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:ORCL",
"username", "password");
2. Add a System.out.println statement just after loading the driver; print a message that
will let you know that you have loaded the driver when you test your class.
System.out.println("I am connected");
//Diagnostic print
3. Set autocommit off for the connection object
conn.setAutoCommit (false);
4. Create a statement object
Statement stmt = conn.createStatement ();
5. Delete all the rows that exist in table temp_large and commit the changes
stmt.execute ("DELETE FROM pictures)";
conn.commit();
6. Populate the columns name and pictureblob of table pictures with the value ‘Oracle’ and a
BLOB locator using the empty_blob() method
stmt.execute ("INSERT INTO pictures (name,
pictureblob) values ('Oracle', EMPTY_BLOB())");
7. Select the BLOB locator from the table
ResultSet rset = stmt.executeQuery ("SELECT
pictureblob FROM pictures WHERE name = 'Oracle'");
if (rset.next ())
BLOB blob = ((OracleResultSet)rset).getBLOB (1);
8. Declare a file handler for the oracle.gif file
File binaryFile = new File("E:/labs/oracle.gif");

Oracle9i: Access the Database with Java and JDBC 3-49


Practice 3-2 (continued)
9. Create a FileInputStream object to read the contents of the GIF file and an
OutputStream object to write the BLOB as a stream
FileInputStream istream = new FileInputStream
(binaryFile);
OutputStream ostream =
blob.getBinaryOutputStream ();
10. Call getBufferSize() to retrieve the ideal buffer size (according to calculation by the
JDBC driver) to use in writing to the BLOB, then create the buffer byte array.
int size =blob.getBufferSize();
System.out.println(size);
byte[] buffer = new byte[size];
11. You use the read() method to read the GIF file to the byte array buffer, then you use the
write() method to write it to the BLOB.
while ((length = istream.read(buffer)) != -1)
ostream.write(buffer, 0, length);
12. Close the inputstream and outputstream
istream.close();
ostream.close();
13. Test your application by checking the BLOB’s size
System.out.println ("Number of bytes written = "
+blob.length());
14. Close all resources
rset.close();
stmt.close();
conn.close();

Oracle9i: Access the Database with Java and JDBC 3-50


Practice 3-3
Your assignment
The content of the Oracle.gif file is now loaded in the BLOB column of the PICTURES table.
You query the table to retrieve the content of the BLOB column and display the size of the stored
information.
1. Create a second application named LobToSQL and include the necessary Java code to do the
following:
a. Register the Oracle JDBC
b. Connect to the database
c. Create a Statement
2. Create a BLOB variable, query the BLOB column, to get the BLOB locator into a result set
BLOB blob = null;
ResultSet rset = stmt.executeQuery ("SELECT pictureblob FROM
pictures");
if (rset.next())
{

//Get the blob data ­ cast to OracleResult set to
// retrieve the data in Oracle.sql format
blob = ((OracleResultSet)rset).getBLOB (1);
}

3. Get the length of the BLOB, then print its length


long length = blob.length();
System.out.println("The blob length is " + length);

4. Read the BLOB into a byte array, then print its length


int size =blob.getBufferSize();
byte[] buffer = new byte[size];
buffer = blob.getBytes(1, size);
System.out.println("The array length is " + 
buffer.length);
5. Close all resources
rset.close();
stmt.close();
conn.close();

Oracle9i: Access the Database with Java and JDBC 3-51


Practice 3-4
Your assignment
You want to load the content of the oracle.gif file in a BFILE column and check that the
information is correctly stored in the table by displaying it. For this practice you will use a directory
object that points to the directory holding the oracle.gif file on the server.
1. Create a third application named GifToBfile.
a. Register the Oracle JDBC
b. Connect to the database
c. Disable the autocommit mode

import java.sql.*;
import java.io.*;
import java.util.*;
import oracle.jdbc.*;
import oracle.sql.*;
public class GifToBfile
{
public static void main (String args [])
throws Exception
{
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
String url = "jdbc:oracle:thin:@myhost:1521:SID";
// Connect to the database
Connection conn = DriverManager.getConnection
(url,"username", "password");
// It's faster when auto commit is off conn.setAutoCommit
(false);
System.out.println ("I am connected");

• Compile your application

Oracle9i: Access the Database with Java and JDBC 3-52


Practice 3-4 (continued)
2. Update the PICTURES table and set the picturebfile column with the following value:
(bfilename ('TEST_DIR', 'oracle.gif')).
stmt.execute ("UPDATE pictures SET picturebfile= (bfilename
('TEST_DIR', 'oracle.gif'))");
3. Query the name and picturebfile columns using a result set and print the content of
each column
ResultSet rset = stmt.executeQuery
("SELECT name, picturebfile FROM pictures");
while (rset.next ())
{

String x = rset.getString (1);


BFILE bfile = ((OracleResultSet)rset).getBFILE(2);
System.out.println ("name = "+x + " " + bfile);
4. Use the getName(),fileExists(), isFileOpen(), and length() methods for the
bfile object to display the corresponding information before and after opening the bfile.
Display the name of the .gig file Get the length of the BLOB, then print its length.
System.out.println("bfile name "+ bfile.getName());
System.out.println("bfile exists "+ bfile.fileExists());
System.out.println("bfile open "+ bfile.isFileOpen());
System.out.println("open file ");
bfile.openFile();
System.out.println("bfile open "+ bfile.isFileOpen());
long len = bfile.length();
System.out.println("bfile length "+ len);
5. The following code displays the content of the .gif file:
byte [] buffer = new byte[(int)len];
System.out.println
("Wait for the image to be loaded...");
instream.read(buffer);
instream.close();
bfile.close();

javax.swing.JOptionPane.showInputDialog(new JLabel(new
ImageIcon(buffer)));
}

6. Close all resources


// Close input stream and file handler 
System.out.println("bye");
rset.close();    
stmt.close();    
conn.close();
} catch ( SQLException e) { System.out.println("caught SQLerror:
" + e ); }
catch ( IOException e) { System.out.println("caught IOerror: 
" + e ); }
}

Oracle9i: Access the Database with Java and JDBC 3-53


JDBC Advanced Topics
and Performance Extensions

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

60 minutes Lecture
50 minutes Practice
110 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Navigate in a Result Set
• Use PreparedStatement
• Create CallableStatement
• Prefetch rows in a query
• Perform Batch updates

4-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
In this lesson, you learn about JDBC 2.0 features. These enhancements provide a flexible way
to use the database and have an impact on performance improvement.
Oracle9i: Access the Database with Java and JDBC 4-2
Navigating in the Result Set

• JDBC 2.0 specifies three types of result set:


– Forward only
– Scroll insensitive
– Scroll sensitive
• Each result set can also be defined with a
concurrency type:
– Updatable
– ReadOnly
• Support of the JDBC 2.0 scrollable result set
capability is available since Oracle 8i, release 2.

4-3 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC 2.0 Result Set Capabilities


JDBC 2.0 defines three types of result set: forward only, scroll insensitive, and scroll
sensitive. The forward-only result set can only move the cursor forward and was defined in
the JDBC 1 API .
A scroll-insensitive result set can move both backward and forward but is insensitive to
changes that are committed by other transactions or other statements within the same
transaction. A scroll-sensitive result set can move both backward and forward and is sensitive
to changes that are committed by other transactions or other statements within the same
transaction.
Oracle9i: Access the Database with Java and JDBC 4-3
Result Set Navigation

SELECT col1, col2 FROM t1;


Database
JDBC calls commands
Driver Database

Read only or updateable

4-4 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC 2.0 Result Set Capabilities (continued)


For each result set type, an application may choose either of two concurrency types: read only
or updatable. A read-only result set does not support updating of its contents; an updatable
result set supports updating of its contents through the result set. The combination of three
result set types and two concurrency types, produces six different kinds of result sets:
• Forward only/Read only
• Forward only/Updatable
• Scroll insensitive/Read only
• Scroll insensitive/Updatable
• Scroll sensitive/Read only
• Scroll sensitive/Updatable
The first type of result set is the one defined in JDBC 1.0 API and supported in all releases
since Oracle 8i, release 2, JDBC drivers. The remaining five types are additions in JDBC 2.0.
All types of result sets are supported in both the JDK 1.1 and SDK 1.2 Oracle 9i, release 2,
JDBC drivers. Support for these additional types in the JDK 1.1 drivers is an Oracle
extension.
Oracle9i: Access the Database with Java and JDBC 4-4
Result Set Implementation

• SELECT col1, col2 FROM t1;


• Rows are stored in client memory cache.
col1 col2

... JVM

4-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Scrollable Cursors Support Processing


Because the Oracle database does not support scrollable cursors, the Oracle9i, JDBC drivers
implement scrolling as part of the driver itself. The driver maintains a client-side in-memory
cache to store all query results. When the user application moves the cursor, the logical
cursor is moved to point to the requested row in the cache. Since every row of the result is
cached, if the result set contains many rows, many columns, or very large columns, the cache
may consume all available memory and crash the VM. It is very important not to use a
scrollable result set for a large result set.
The Oracle9i, JDBC drivers allow you to provide your own implementation of the result set
cache. You do this by implementing the OracleResultSetCache interface and passing
an instance of your implementing class to
OracleStatement:setResultSetCache() before statement execution.
OracleResultSetCache is an interface defined by Oracle that defines the accessors to
put or get the data into or from the cache. You may want to provide your own cache
implementation to use a client-side resource that the default implementation does not, such as
a disk.
Oracle9i: Access the Database with Java and JDBC 4-5
Setting Navigation for Result Set

• Define a statement with the scrollable and


concurrency properties
Statement stmt = conn.createStatement
(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);

• Define a Result Set using the statement properties


ResultSet rset = stmt.executeQuery
("SELECT ename, sal FROM emp");

4-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Navigating in the ResultSet


ResultSet rset = stmt.executeQuery
("SELECT ename FROM emp ");
// iterate through the result using next()
show_resultset_by_next(rset);
// iterate through the result using previous()
show_resultset_by_previous(rset);
// iterate through the result using absolute()
show_resultset_by_absolute(rset);
// iterate through the result using relative()
show_resultset_by_relative(rset);
rset.first (); rset.last (); rset.previous();
rset.absolute(5);
Oracle9i: Access the Database with Java and JDBC 4-6
Positioning in the Result Set

Choosing a position

col1 col2
void beforeFirst()

boolean first()
boolean next()
boolean absolute(int row)

boolean relative (int row)


boolean previous()
boolean last()

void afterLast()

4-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Available Navigable Methods


beforeFirst() method: Positions to before the first row of the result set, or has no effect
if there are no rows in the result set. This is where you would typically start iterating through
a result set to process it going forward, and is the default initial position for any kind of result
set. You are outside the result set bounds after a beforeFirst() call. There is no valid
current row, and you cannot position relatively from this point.
afterLast() method: Positions to after the last row of the result set, or has no effect if
there are no rows in the result set. This is where you would typically start iterating through a
result set to process it going backward. You are outside the result set bounds after an
afterLast() call. There is no valid current row, and you cannot position relatively from
this point.
first() method: Positions to the first row of the result set, or returns false if there are no
rows in the result set.
last() method: Positions to the last row of the result set, or returns false if there are
no rows in the result set.
Oracle9i: Access the Database with Java and JDBC 4-7
Available Navigable Methods (continued)
absolute() method: Positions to an absolute row from either the beginning or end of
the result set. If you input a positive number, it positions from the beginning; if you input a
negative number, it positions from the end. This method returns false if there are no rows in
the result set. Attempting to move forward beyond the last row, such as an absolute(11)
call if there are 10 rows, will position to after the last row, having the same effect as an
afterLast() call. Attempting to move backward beyond the first row, such as an
absolute(-11) call if there are 10 rows, will position to before the first row, having the
same effect as a beforeFirst() call.
relative()method: Moves to a position relative to the current row, either forward if you
input a positive number or backward if you input a negative number, or returns false if there
are no rows in the result set.
The result set must be at a valid current row for use of the relative() method.
Attempting to move forward beyond the last row will position to after the last row,
having the same effect as an afterLast() call.
Attempting to move backward beyond the first row will position to before the first
row, having the same effect as a beforeFirst() call.
A relative(0) call is valid but has no effect.
Note
• Calling absolute(1) is equivalent to calling first(); calling absolute(­1) is
equivalent to calling last().
• The boolean methods—isFirst(), isLast(), isAfterFirst(), and
isAfterLast()—all return false (and do not throw an exception) if there are no rows
in the result set.
Presetting the Fetch direction
The JDBC 2.0 standard allows the ability to pre-specify the direction, known as the fetch
direction, for use in processing a result set. This allows the JDBC driver to optimize its
processing. The following result set methods are specified:
• void setFetchDirection(int direction) throws SQLException
• int getFetchDirection() throws SQLException
The Oracle JDBC drivers support only the forward preset value, which you can
specify by inputting the ResultSet.FETCH_FORWARD static constant value.
The values ResultSet.FETCH_REVERSE and ResultSet.FETCH_UNKNOWN are
not supported—attempting to specify them causes a SQL warning, and the settings
are ignored.

Oracle9i: Access the Database with Java and JDBC 4-8


Updating the Result Set

• Navigate to locate the row to be updated


• Update the values using updatexxx() methods
rs.updateString(1, "DUPONT");
rs.updateFloat("sal", 100000.0f);

• Update the current row


rs.updateRow();

• Delete the current row using DeleteRow()


rs.deleteRow();
• updateRow() and deleteRow() methods use
Rowids

4-9 Copyright © Oracle Corporation, 2002. All rights reserved.

Performing an UPDATE Operation in a Result Set


Performing a result set UPDATE operation requires two separate steps to first update the data
in the result set and then copy the changes to the database.
Presuming the result set is also scrollable, you can position to a row using any of the
available positioning methods (except beforeFirst() and afterLast(), which do not
go to a valid current row), and then update that row as desired.
Following are the steps for updating a row in the result set and database:
1. Call the appropriate updateXXX() methods to update the data in the columns you
want to change. Each of these methods takes an int for the column number or a string
for the column name and then an item of the appropriate datatype to set the new value.
Following are a couple of examples for a result set rs:
rs.updateString(1, "mystring");
rs.updateFloat(2, 10000.0f);
2. Call the updateRow() method to copy the changes to the database (or the
cancelRowUpdates() method to cancel the changes).
Once you call updateRow(), the changes are executed and will be made permanent
with the next transaction COMMIT operation. If you choose to cancel the changes
before copying them to the database, 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 (auto-commit must be
disabled to allow a ROLLBACK operation).
Positioning to a different row before calling updateRow() also cancels the
changes and reverts to the original values in the result set.
Oracle9i: Access the Database with Java and JDBC 4-9
Inserting in the Result Set

• Navigate to the insert row location


rs.moveToInsertRow();
• Update the values by using updatexxx() methods
rs.updateString(1, "DUPONT");
rs.updateFloat("sal", 100000.0f);

• Execute the insert in the database


rs.insertRow();

• Return to the previous location


rs.moveToCurrentRow();

4-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Performing an INSERT Operation in a Result Set


Result set INSERT operations use what is called the result set insert-row, which is a staging
area that holds the data for the inserted row until it is copied to the database. You must
explicitly move to this row to write the data that will be inserted.
As with UPDATE operations, result set INSERT operations require separate steps to first
write the data to the insert-row and then copy it to the database.
Following are the steps in executing a result set INSERT operation.
1. Move to the insert-row by calling the result set moveToInsertRow() method.
2. As with UPDATE operations, use the appropriate updateXXX() methods to write data
to the columns. For example:
rs.updateString(1, "mystring");
rs.updateFloat(2, 10000.0f);
(Note that you can specify a string for column name, instead of an integer for column
number.)
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.
3. Copy the changes to the database by calling the result set insertRow() method.
Once you call insertRow(), the insert is executed 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);
Oracle9i: Access the Database with Java and JDBC 4-10
Scrollable and Updateable Restrictions
with Result Sets
Statement Restriction Scrollable Updateable

Cannot be SELECT *

Must be single table

Must include all


non-nullable columns for INSERT

No ORDER BY
No aggregate or
derived columns
Cannot be returned from
a Stored Procedure or
from a PL/SQL block

4-11 Copyright © Oracle Corporation, 2002. All rights reserved.

Update Restrictions

To support updatability and change sensitivity, Oracle JDBC drivers cache the ROWID along
with each row. The drivers generate SQL to update or read changes using this ROWID. You
do not have to include the ROWID in your query; the drivers automatically add it when
necessary.
Since scrollable result sets are implemented by the driver rather than by the underlying
database, there are a number of restrictions:
• Not all SQL queries can return all result set types. If you request an unsupported result set
type, the execute method will still return a result set, but it will be of the supported
type that best approximates your request. Many queries cannot return any type other than
forward only or case insensitive. One quick way to check a questionable statement is to
execute it using SQL*Plus (or some other tool) and add ROWID to the list of selected
columns. If this fails, then the query must be forward only or case insensitive.
• The driver does not check for conflicts with ResultSet.deleteRow() and
ResultSet.updateRow().
• The driver does not enforce write lock for updateable result sets.
Oracle9i: Access the Database with Java and JDBC 4-11
Update Restrictions (continued)
An update conflict occurs when the value in a row is changed by another committed
transaction and you try to update the same row. For both ResultSet.deleteRow() and
ResultSet.updateRow(), an Oracle8i, release 2, JDBC driver uses the ROWID value to
uniquely identify a row in a database table. As long as the ROWID remains valid, the driver
performs the delete or update operation on the row with the matched ROWID. If the row’s
column values in the database are changed by another committed transaction, the driver
ignores these changes and writes the new values or deletes the row without warning. This
procedure can affect data integrity. If detection of update conflicts is important in your
application, you may impose a write lock on the selected rows by modifying your SQL query
to included the FOR UPDATE keywords. Since only a single write lock may be held at a
time on a data item, this can reduce concurrency and substantially reduce performance, but it
guarantees that no update conflict will occur.
Any rows inserted or deleted by others are not visible. Once the result set is open, the row’s
order and membership are fixed. The only exception is that calling deleteRow() on a result set
removes the row from that result set.
The driver does not detect that changes have been made by itself or others. Therefore, you
cannot call rowUpdated, rowDeleted, or rowInserted in ResultSet to determine whether the
current row has been changed.
Workaround
As a workaround for the SELECT * limitation, you can use table aliases as follows:
SELECT t.* FROM table t;

Oracle9i: Access the Database with Java and JDBC 4-12


The PreparedStatement Object

• A PreparedStatement prevents reparsing of SQL


statements.
• Use this object for statements that you want to
execute more than once.
• A PreparedStatement can contain variables that
you supply each time you execute the statement.

4-13 Copyright © Oracle Corporation, 2002. All rights reserved.

PreparedStatement
PreparedStatement is inherited from Statement; the difference is that
PreparedStatement holds precompiled SQL statements.
If you execute a Statement object many times, its SQL statement is compiled each time.
PreparedStatement is more efficient because its SQL statement is compiled only once,
when you first prepare PreparedStatement. After that, each time you execute the SQL
statement in PreparedStatement, the SQL statement does not have to be recompiled.
Therefore, if you need to execute the same SQL statement several times in an application, it
is more efficient to use PreparedStatement than Statement.
PreparedStatement parameters
PreparedStatement does not have to execute exactly the same query each time. You
can specify parameters in the PreparedStatement SQL string and supply the actual
values for these parameters when the statement is executed.
The following slide shows how to supply parameters and execute a prepared statement.
Oracle9i: Access the Database with Java and JDBC 4-13
How to Create a PreparedStatement

1. Register the driver and create the database


connection.
2. Create the PreparedStatement, identifying
variables with a question mark (?).

PreparedStatement pstmt =
conn.prepareStatement
("UPDATE emp SET ename = ? WHERE empno = ?");

PreparedStatement pstmt =
conn.prepareStatement
("SELECT ename FROM emp WHERE empno = ? ");

4-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Creating a PreparedStatement
To write changes to the database, such as for INSERT or UPDATE operations, you will
typically create a PreparedStatement object. You can use the PreparedStatement
object to execute a statement with varying sets of input parameters. The
prepareStatement() method of your JDBC Connection object allows you to define a
statement that takes variable bind parameters, and returns a JDBC PreparedStatement
object with your statement definition.
Oracle9i: Access the Database with Java and JDBC 4-14
How to Execute a PreparedStatement

1. Supply values for the variables.


pstmt.setXXX(index, value);
2. Execute the statement.
pstmt.executeQuery();
pstmt.executeUpdate();
int empNo = 3521;
PreparedStatement pstmt =
conn.prepareStatement("UPDATE emp
SET ename = ? WHERE empno = ? ");
pstmt.setString(1, "DURAND");
pstmt.setInt(2, empNo);
pstmt.executeUpdate();

4-15 Copyright © Oracle Corporation, 2002. All rights reserved.

Specifying Values for the Bind Variables


You use the PreparedStatement.setXXX() methods to supply values for the
variables in a prepared statement. There is one setXXX() method for each Java type:
setString(), setInt(), and so on.
You must use the setXXX() method that is compatible with the SQL type of the variable. In
the example in the slide, the first variable is updating a VARCHAR column, so you need to use
setString() to supply a value for the variable. You can use setObject() with any
variable type.
Each variable has an index. The index of the first variable in the prepared statement is 1, the
index of the second variable is 2, and so on. If there is only one variable, its index
is 1. The index of a variable is passed to the setXXX() method.
Closing a PreparedStatement
If you close a PreparedStatement, you will have to prepare it again.
Oracle9i: Access the Database with Java and JDBC 4-15
The CallableStatement Object

• The CallableStatement object holds parameters


for calling stored procedures.
• A CallableStatement can contain variables that
you supply each time you execute the call.
• When the stored procedure returns, computed
values (if any) are retrieved through the
CallabableStatement object.

4-16 Copyright © Oracle Corporation, 2002. All rights reserved.

The CallableStatement Object


The way to access stored procedures using JDBC is through the CallableStatement
class, which is inherited from the PreparedStatement class. CallableStatement is
like PreparedStatement in that you can specify parameters using the question mark (?)
notation, but it contains no SQL statements.
Both functions and procedures take parameters represented by identifiers. A function
executes some procedural logic, and it returns a value that can be any data type supported by
the language used to write the function (Java or PL/SQL). The parameters supplied to the
function do not change after the function is executed.
A procedure executes some procedural logic but does not necessary return a value. However,
some of the parameters supplied to the procedure may have their values changed after the
procedure is executed.
Note: Calling a stored procedure is the same whether the stored procedure was written
originally in Java or in any other language supported by the database, such as PL/SQL.
Indeed, a stored procedure written in Java appears to the programmer as a PL/SQL stored
procedure.
Oracle9i: Access the Database with Java and JDBC 4-16
The CallableStatement Object (continued)
Oracle JDBC drivers support execution of PL/SQL stored procedures and anonymous blocks.
They support both SQL92 escape syntax and Oracle PL/SQL block syntax. The following
PL/SQL calls would work with any Oracle JDBC driver:
// SQL92 syntax
CallableStatement cs1 = conn.prepareCall
( "{call proc (?,?)}" ) ; // stored proc
CallableStatement cs2 = conn.prepareCall
( "{? = call func (?,?)}" ) ; // stored func
// Oracle PL/SQL block syntax
CallableStatement cs3 = conn.prepareCall
( "begin proc (?,?); end;" ) ; // stored proc
CallableStatement cs4 = conn.prepareCall
( "begin ? := func(?,?); end;" ) ; // stored func
As an example of using 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;
Your invocation call in your JDBC program should look like:
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci8:@<hoststring>", "scott", "tiger");
CallableStatement cs = conn.prepareCall ("begin ? := foo(?);
end;");
cs.registerOutParameter(1,Types.CHAR);
cs.setString(2, "aa");
cs.executeUpdate();
String result = cs.getString(1);
Java stored procedures
You can use JDBC to invoke Java stored procedures through the SQL and PL/SQL engines.
The syntax for calling Java stored procedures is the same as the syntax for calling PL/SQL
stored procedures, presuming they have been properly "published“ (that is, have had call
specifications written to publish them to the Oracle data dictionary). See the Oracle9i Java
Stored Procedures Developer’s Guide for more information on writing, publishing, and using
Java stored procedures.

Oracle9i: Access the Database with Java and JDBC 4-17


CallableStatement for a
Procedure Call(1)

1. Register the driver and create the database


connection.
2. Create the CallableStatement, identifying
variables with a question mark (?).
CallableStatement cstmt =
conn.prepareCall("{call PROC(param1,param2)}");

3. Register the output parameters.


cstmt.registerOutParameter(index,param_Type);

4-18 Copyright © Oracle Corporation, 2002. All rights reserved.

Creating a CallableStatement
First, you need an active connection to the database to obtain a CallableStatement
object.
Next, you create a CallableStatement object using the prepareCall() method of
the Connection class. This method typically takes a string as an argument. The syntax for
the string has two forms. The first form includes a result parameter, and the second form does
not:
{? = call proc (…) } // A result is returned to a variable
{call proc (…) } // Does not return a result
Note that the parameters of the stored procedures are specified using the question mark
notation used earlier in PreparedStatement. You must register the data type of the
parameters using the registerOutParameter() method of CallableStatement if
you expect a return value or if the procedure is going to modify a variable (also known as an
OUT variable). In the example in the slide, the second and third parameters will be computed
by the stored procedure, whereas the first parameter is input (the input is specified in the next
slide). Parameters are referred to sequentially, by number. The first parameter is 1.
To specify the data type of each OUT variable, you use parameter types from the Types
class. When the stored procedure successfully returns, the values can be retrieved from the
CallableStatement object.
Instructor Note
The stored procedures lesson includes an example showing execution of a callable statement.
Oracle9i: Access the Database with Java and JDBC 4-18
CallableStatement for a
Procedure Call(2)

4. Set the input parameters.


cstmt.setXXX(index, value);

5. Execute the statement.


cstmt.execute();

6. Get the output parameters.


var = cstmt.getXXX(index);

4-19 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Execute a CallableStatement


There are three additional steps in executing the stored procedure after you have registered
the types of the OUT variables:
4. Set the IN parameters.
Use the setXXX() methods to supply values for the IN parameters. There is one
setXXX() method for each Java type: setString(), setInt(), and so on. You
must use the setXXX() method that is compatible with the SQL type of the variable.
You can use setObject() with any variable type. Each variable has an index. The
index of the first variable in the prepared statement is 1, the index of the second variable
is 2, and so on. If there is only one variable, its index is 1.
5. Execute the call to the stored procedure.
Execute the procedure using the execute() method.
6. Get the OUT parameters.
Once the procedure is completed, you retrieve OUT variables, if any, using the
getXXX() methods. Note that these methods must match the types that you registered
in the previous slide.
Example:
CallableStatement cstmt =
conn.prepareCall  ( {"call ADDITEM (?,?,?)} ");
cstmt.setInt (1, itemNbr);
cstmt.registerOutParameter(2,Types.INTEGER);
cstmt.registerOutParameter(3,Type.DOUBLE);
Oracle9i: Access the Database with Java and JDBC 4-19
REF CURSOR

• A REF CURSOR:

– Is a pointer to a Query work area


– Identifies a reference to a cursor variable
– Encapsulates the results of a query
• Use REF CURSOR with CallableStatement
• The CallableStatement implements a PL/SQL
procedure that returns a REF CURSOR
• The getCursor() method is an Oracle extension
to CallableStatement returning the REF CURSOR
into a ResultSet object
• Use a cursor like a ResultSet

4-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle REF CURSOR Type Category


A cursor variable holds the memory location (address) of a query work area, rather than the
contents of the area. Declaring a cursor variable creates a pointer. In SQL, a pointer has the
data type REF x, where REF is short for REFERENCE and x represents the entity being
referenced. A REF CURSOR, then, identifies a reference to a cursor variable. Because many
cursor variables might exist to point to many work areas, REF CURSOR can be thought of as
a category or “datatype specifier” that identifies many different types of cursor variables.
To create a cursor variable, you should identify a type that belongs to the REF
CURSOR category. For example:
DECLARE TYPE DeptCursorTyp IS REF CURSOR
Then create the cursor variable by declaring it to be of the type DeptCursorTyp:
dept_cv DeptCursorTyp - - declare cursor variable
...
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.
Oracle9i: Access the Database with Java and JDBC 4-20
Oracle REF CURSOR Type Category (continued)
In JDBC, REF CURSORs are materialized as ResultSet objects 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: Accessing REF CURSOR Data
import oracle.jdbc.*;
...
CallableStatement cstmt;
ResultSet cursor;
// Use a PL/SQL block to open the cursor
Important: The cursor associated with a REF CURSOR is closed whenever the statement
object that produced the REF CURSOR is closed.
Unlike in earlier releases, the cursor associated with a REF CURSOR is not closed when the
result set object in which the REF CURSOR was materialized is closed.
cstmt = conn.prepareCall
("begin open ? for select ename from emp; end;");
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
cstmt.execute();
cursor = ((OracleCallableStatement)cstmt).getCursor(1);
// Use the cursor like a normal ResultSet
while (cursor.next ())
{System.out.println (cursor.getString(1));}
In the preceding example:
• A CallableStatement object is created by using the prepareCall() method
of the connection class.
• The callable statement implements a PL/SQL procedure that returns a REF CURSOR.
• As always, the output parameter of the callable statement must be registered to define
its type. Use the typecode OracleTypes.CURSOR for a REF CURSOR.
• The callable statement is executed, returning the REF CURSOR.
• The CallableStatement object is cast to an OracleCallableStatement
object to use the getCursor() method, which is an Oracle extension to the standard
JDBC API, and returns the REF CURSOR into a ResultSet object.

Oracle9i: Access the Database with Java and JDBC 4-21


Prefetching Rows in a Query

• Oracle JDBC drivers enable you to set the number


of rows to prefetch to the client:
– Can be defined for the connection
– Alternatively, can be defined for individual
statements
• Prefetching reduces the number of round trips to
the server.

4-22 Copyright © Oracle Corporation, 2002. All rights reserved.

Prefetching Rows
Standard JDBC receives the result sets of a query one row at a time. Each row costs a round
trip to the database. Oracle JDBC drivers support the concept of prefetching. This feature
associates an integer with each Statement object. This integer is called the row prefetch
setting, and it dictates how many rows JDBC will fetch at a time from result sets associated
with the statement.
Specifying a row prefetch value for a single statement
If you want to specify a row prefetch value for a single statement, you can call the
setRowPrefetch() method on the Statement object. This method is actually defined
in OracleStatement, so you will need to cast your Statement object to an
OracleStatement object before calling this method.
Specifying a row prefetch value for all statements in a Connection
If you want to establish the same prefetch value for all Statement objects created for a
particular Connection object, you can call the setDefaultRowPrefetch() method
on the Connection object. This method is defined in OracleConnection, so you will
need to cast your Connection object to an OracleConnection object.
Instructor Note
This technique is also known as array fetching. You can specify an array fetch when writing
PL/SQL code or other third-generation languages supported by the Oracle precompilers.
Oracle9i: Access the Database with Java and JDBC 4-22
Prefetching Rows: Example

Connection conn = DriverManager.getConnection(…);


((OracleConnection)conn).setDefaultRowPrefetch(7);
Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery(
"SELECT * FROM customers");
… // process results

((OracleStatement)stmt).setRowPrefetch(2);
rs = stmt.executeQuery(" SELECT * FROM customers ");
… // process results

4-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Setting the Row Prefetch Property


The code in the slide shows how to set the row prefetch property in two ways:
• Setting the default row prefetch value for a Connection object, so that all
Statement objects attached to it inherit the same row prefetch value
• Setting a row prefetch value for a single Statement object, so that it applies to that
Statement object but no others
Following is a step-by-step explanation of the code:
• A Connection object is created in the usual way. If you do not set a default row
prefetch value for a connection, its default row prefetch value is 10.
• The default row prefetch value for the Connection object is then set to 7 by calling
setDefaultRowPrefetch(). This method is defined in OracleConnection, so
you have to cast the Connection object if you want to call this method.
• A Statement object is created for this Connection. This statement, and any others
attached to the same connection, will inherit the row prefetch value of 7.
• The Statement object is then used exactly as before, regardless of the row prefetch
value. Only the execution time changes.
• Farther on in the code, the row prefetch value for just this statement is set to 2 by calling
setRowPrefetch(). This method is defined in OracleStatement, so you have to
cast the Statement object to call this method.
Oracle9i: Access the Database with Java and JDBC 4-23
Prespecifying Column Types

• When a query is performed, JDBC uses a network


round trip to identify result types.
• Oracle JDBC enables column types to be
predefined.
• Prespecifying column types eliminates one
network round trip.
• Prespecification converts data into the Java
expected type.
((OracleStatement)st).clearDefines();
((OracleStatement)st).defineColumnType(col, type);

4-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Retrieving Values from a Result Set in Standard JDBC


When you perform a query using standard JDBC, JDBC first performs a round trip to the
database to determine the types of the columns of the result set. JDBC then executes the
query to populate the result set. The programmer then calls the ResultSet getXXX()
methods to retrieve column values from the result set.
When a getXXX() method is called, JDBC may have to convert the data in the result set to
the data type requested by the programmer. For example, if the first column in a result set is a
number, but the programmer calls the getString() method, JDBC has to convert the
number into a Java string. This conversion takes place locally, on the client machine.
Prespecifying column types in Oracle JDBC
Oracle JDBC enables you to prespecify column types in a query. Follow these steps to
prespecify column types in a query:
• Create a statement as before, using createStatement() in Connection.
• For each column in the result set, call defineColumn() to define the data type that
you expect to get back in that column.
• Execute the query as usual, by calling executeQuery() for the statement. The query
will be executed on the server, and the server will perform any necessary type
conversions according to the column types that you specified.
• Retrieve column values from the result set as usual, using the getXXX() methods. The
values will already be the correct type, so local type conversions will not be needed.
Oracle9i: Access the Database with Java and JDBC 4-24
Prespecifying Types: Example

Statement stmt = conn.createStatement();

// Ask for the CUSTOMER_ID column as an Integer.


((OracleStatement)stmt).defineColumnType
(1, Types.INTEGER);

ResultSet rs = stmt.executeQuery
(" SELECT customer_id FROM customers ");
… // process results

4-25 Copyright © Oracle Corporation, 2002. All rights reserved.

Prespecifying Types: Example


This example shows how to prespecify the data types for columns in a query.
The Statement object is created at the beginning of the example, in the usual way. The
defineColumnType() method is then called, to specify the expected column type for
each column in the result set.
The result set in this example contains only a single column, so defineColumnType()
needs to be called only once. If you have a query with more than one column in the result set,
you must call defineColumnType() for every column; otherwise, the process fails.
Server-Side Type Conversion
When a query is executed, the server assembles the result set and ensures that the columns
have the data types that you have specified. If a column does not match with the declared
data type, the server will perform type conversions if necessary. When the column values are
retrieved using the getXXX() methods, the data is already in the correct data type, so no
local type conversions are necessary.
For example:
((OracleStatement)stmt).defineColumnType(1,
Types.VARCHAR);
((OracleStatement)stmt).defineColumnType(2,
Types.VARCHAR);
stmt.executeQuery(
"SELECT customer_id, cust_first_name FROM customers");
Oracle9i: Access the Database with Java and JDBC 4-25
Objectives of Update Batching

• Reduce the number of round trips to the database


• Group multiple DML statements into a single
“batch” and having the whole batch sent to the
database and processed in one trip.
• Useful with prepared statements, when you are
repeating the same statement with different bind
variables.
• Oracle uses a batch value conditioning the number
of statements that are sent to the database.
• Sun model has no definable batch value.

4-26 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle Model Versus Standard Model


Oracle update batching uses a batch value that typically results in implicit processing of a
batch. The batch value is the number of operations you want to batch (accumulate) for each
trip to the database. As soon as that many operations have been added to the batch, the batch
is executed. Note the following:
• You can set a default batch for the connection object, which applies to any prepared
statement executed in that connection.
• For any individual prepared statement object, you can set a statement batch value that
overrides the connection batch value.
• You can choose to explicitly execute a batch at any time, overriding both the connection
batch value and the statement batch value
Instructor Note
Page 27-28 show the Oracle Batching implementation. It is also known as array fetching.
Oracle9i: Access the Database with Java and JDBC 4-26
Batched Updates of Prepared Statements

• By default, prepared statements are executed as


soon as executeUpdate() is called.
• Oracle batch updates enables prepared statements
to be batched by group of n
((OracleConnection)conn).setDefaultExecuteBatch (2);
PreparedStatement ps = conn.prepareStatement
("UPDATE departments SET manager_id = (?)
WHERE department_id = (?) ");
ps.setInt (1, 41);
ps.setInt (2, 40);
ps.executeUpdate ();
ps.setInt (1, 31);
ps.setInt (2, 30);
ps.executeUpdate ();
// The number of batch calls to executeUpdate is now equal to the
// batch value of 2. The data is now sent to the database and
// both rows are updated in a single roundtrip.

4-27 Copyright © Oracle Corporation, 2002. All rights reserved.

Batched Updates of Prepared Statements


When you execute a prepared statement using standard JDBC, JDBC makes a separate round
trip to the database each time the executeUpdate() method is called.
Oracle JDBC drivers enable you to accumulate inserts and updates at the client and send
them to the server in batches, thereby reducing round trips to the server. If you set the batch
size for a prepared statement, JDBC accumulates that many execution requests for the
statement before passing the requests to the database for execution.
Setting the batch size for a prepared statement
The default batch size for a prepared statement is 1. To change the batch size, use
setExecuteBatch() in the OraclePreparedStatement class. Now, when the
executeUpdate() method is called on that PreparedStatement object, JDBC
queues an execution request. When the number of queued requests reaches the batch size,
JDBC sends the requests to the database for execution. You can determine the current batch
size by calling getExecuteBatch().
Flushing batched statements
If you want a set of batched prepared statements to be executed now, regardless of whether
the batch size has been reached, you can call the sendBatch() method defined in the
OraclePreparedStatement class. This causes JDBC to send queued execution
requests for the given prepared statement to the database for execution.
JDBC automatically executes the sendBatch() method whenever the connection receives
a commit request, or whenever either the statement or the connection receives a close request.
Batch errors
If an error occurs during batch execution, a rollback of the set of statements is performed.
Oracle9i: Access the Database with Java and JDBC 4-27
Batched Updates of Prepared Statements

• Use addBatch() method to prepare SQL


statements to be submitted
...
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();
int[] updateCounts = pstmt.executeBatch();
...

4-28 Copyright © Oracle Corporation, 2002. All rights reserved.

Batched Updates of Prepared Statements (continued)


Adding operations to the batch
When any statement object is first created, its statement batch is empty. Use the
standard addBatch() method to add an operation to the statement batch. This
method is specified in the standard java.sql.Statement,
PreparedStatement, and CallableStatement interfaces, which are
implemented by interfaces oracle.jdbc.OracleStatement,
OraclePreparedStatement, and OracleCallableStatement, respectively.
Oracle9i: Access the Database with Java and JDBC 4-28
Batched Updates of Prepared Statements (continued)
Batch Errors
If an error occurs during batch execution, a rollback of the set of statements is performed.
Note that with standard update batching, you can use either standard PreparedStatement,
CallableStatement, and Statement objects, or Oracle-specific OraclePreparedStatement,
OracleCallableStatement, and OracleStatement objects.
Note: The Oracle implementation of standard update batching does not implement true
batching for generic statements and callable statements. Although Oracle JDBC supports the
use of standard batching syntax for Statement and CallableStatement objects, you will see
performance improvement for only PreparedStatement objects.

Oracle9i: Access the Database with Java and JDBC 4-29


Managing Batch Execution

• Use:(OracleConnection)conn).setDefault
ExecuteBatch() method to specify the batch value
• Override the batch value for a statement:
((OraclePreparedStatement)
ps).setExecuteBatch();
• Force execution at any time using:
rows=((OraclePreparedStatement)
ps).sendBatch ();
• Call Commit() for statements that have been
executed

4-30 Copyright © Oracle Corporation, 2002. All rights reserved.

Setting the Statement Batch Value


Use the following steps to set the statement batch value for a particular Oracle prepared
statement. This will override any connection batch value set using the
setDefaultExecuteBatch() method of the OracleConnection instance for the
connection in which the statement executes.
// Write your prepared statement and specify input values for the first row:
PreparedStatement ps = conn.prepareStatement
("INSERT INTO departments VALUES (?,?,?)");
ps.setInt (1,12);
ps.setString (2,"Oracle");
ps.setString (3,"USA");
// Set, the batch size of the statement is set to 2.
((OraclePreparedStatement)ps).setExecuteBatch(2);
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");
int rows = ps.executeUpdate ();
System.out.println ("Number of rows updated now: " + rows);
ps.close ();
Oracle9i: Access the Database with Java and JDBC 4-30
The ROWID Pseudocolumn

• Oracle JDBC drivers do not support


getCursorName() for cursor use.
• Oracle provides a ROWID type instead:
– ROWID is a pseudocolumn in a query
– Retrieve its value from a result set, using
getString()
• ROWID can also be bound to a parameter in a
PreparedStatement object.

4-31 Copyright © Oracle Corporation, 2002. All rights reserved.

Cursors
In SQL, a result table is retrieved through a named cursor. SQL programmers will be familiar
with the idea of using cursors to traverse the rows in the result table.
Cursors can also be used to update or delete the current row using an UPDATE or DELETE
statement. The statement specifies the FOR UPDATE clause and uses the cursor to identify
which row is to be affected.
Cursors in standard JDBC
The standard JDBC specification defines a getCursor() method in the ResultSet
class. You can call this method to identify the current row in the result table and then update
or delete the row as you see it.
Cursors in Oracle JDBC
Oracle JDBC drivers do not support the getCursorName() method in the ResultSet
class, because there is no convenient way to map it to Oracle constructs. It is recommended
that you use ROWID instead; it provides similar functionality.
The following slide shows how to use ROWID to identify the current row in a table.
Oracle9i: Access the Database with Java and JDBC 4-31
Example: Using ROWID
for In-Place Updates
ResultSet rset = stmt.executeQuery
("SELECT product_name, ROWID
FROM product_information FOR UPDATE");
PreparedStatement pstmt = conn.prepareStatement
("UPDATE product_information SET product_name = ?
WHERE ROWID = ?");
while (rset.next()) {
String productInformation = rset.getString(1);
String rowid = rset.getString(2);
… // Assign the new rating
pstmt.setString(1, newProductInformation);
pstmt.setString(2, rowid);
pstmt.executeUpdate();
}

4-32 Copyright © Oracle Corporation, 2002. All rights reserved.

Using ROWID for In-Place Updates


The code in the slide gives new ratings to the titles in PRODUCT_INFORMATIONS.
• The first SQL statement is a SELECT statement, wrapped in a Statement object. The
statement retrieves the product_name column and ROWID pseudocolumn for each
product. Notice the FOR UPDATE clause. This places exclusive locks on the active data
set so that it can be modified without loss of consistency.
• The second SQL statement is an UPDATE statement and is wrapped in a Java
PreparedStatement object. Each time this SQL statement is executed, it updates the
product_name to a new value. The prepared statement has two parameters: one is the
revised product_name, and the other is the ROWID value that identifies which record of
product_information to update.
• Following is a step-by-step explanation of the code:
– The SQL SELECT string in the Statement object is executed.
– The SQL UPDATE string in the PreparedStatement object is then precompiled.
– A loop is set up to traverse the rows from the SQL query.
– Inside the loop, the product_information column is retrieved using
rset.getString(1). The ROWID pseudocolumn is retrieved in the same way.
Note that ROWID is a string.
– Still in the loop, the first parameter in the prepared statement is filled in with the new
rating. The second parameter is filled in with the ROWID value to identify the record
to update when the prepared statement is executed.
Oracle9i: Access the Database with Java and JDBC 4-32
Summary

• You can navigate forward/backward or locate a


specific row in a Result Set
• A scrollable result set is still updateable
• Use PreparedStatement to prevent reparsing of
recurrent SQL statements
• A CallableStatement allows you to call a stored
procedure/function written in Java or PL/SQL
• Use a REF CURSOR when a CallableStatement
returns a result set
• Prefetching rows as prespecifying column types in
a query improve performances
• Perform Batch updates to group DML statements
into a single batch

4-33 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 4-33


Practice 4-1 Overview

This practice covers the following topics:


• Creating a scrollable ResultSet for users to
navigate
• Use a PreparedStatement to generate a dynamic
WHERE clause

4-34 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 4-34


Practice 4-1
Goal
The goal of this practice is create a scrollable result set and navigate through the rows in an
HTML user interface.
Your assignment
You will create a Class that queries the database and you will display the result using a UI (in
the form of a servlet) that has been created for you, allowing you to navigate in the result set.
Open lesson04.jws and select Navigate.jpr.
1. First, create a class to contain the JDBC code.
a. Create a new class file. Name it OrdersQuery.java and accept all other
defaults.
b. Open OrdersQuery.java in the editor.
2. You will create four methods in this class: setConnection, getOrders,
getOrderItems, and close.
a. Create four private instance variables to contain the Connection,
PreparedStatement, Statement, and ResultSet objects. Initialize all variables to null.
b. Create the first method, setConnection(). This void method will be passed a
URL, username, and password from the servlet and create a connection for the
user.
i. Set the Statement variable created in Step 2a to be
TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
ii. Set the PreparedStatement variable created in Step 2a to select all the
columns in the ORDER_ITEMS table, where the ORDER_ID is dynamic.
iii.Set the ResultSet variable created in Step 2a to select all the columns in
the ORDERS table, ordered by the ORDER_ID column.
c. Create the method close(). This method should return void and close the
Connection object, Statement object, and ResultSet object if they are not null.
d. Compile and save the class. You will need to import java.sql.* in order to
compile.
e. Next, create the getOrders method. This method will return rows from the
ORDERS table, formatted in an HTML table row for use in the servlet. The method
will take two arguments, String rsaction and int actionnum. These
arguments will be passed to the method depending on what the user selects in the
servlet.
i. Create a String method variable to store the value of the returned rows, and
initialize it to an empty string.
ii. If the actionnum argument is null, the user must have pressed a ‘previous’,
‘next’, ‘first’, or ‘last’ button in the servlet. Therefore, check if the
rsaction is one of these strings and navigate the Resultset as
necessary. Also, make sure that the resultset is not currently on the last
row when trying to navigate to the next row, the first row when trying to
navigate to the previous row, etc.
iii.Otherwise, if the actionnum argument is not null, the user must have
selected a row to ‘jump’ to. If so, create an int variable to store the value of
the current row in the ResultSet. Check to ensure that the actionnum
variable is not already the current row in the ResultSet and if it is not,
navigate the ResultSet to the value of the actionnum variable.

Oracle9i: Access the Database with Java and JDBC 4-35


Practice 4-1 (continued)
iv. Next, return the row in the ResultSet. Create String variables for the
ORDER_ID, ORDER_MODE, ORDER_STATUS, and ORDER_TOTAL
columns and set the variables equal to the value of their corresponding
column in the ResultSet.
v. Generate the row to be returned to the servlet. Set the variable created in step
“i” equal to the values of the variables in the previous step and the row
number for the row, formatting in an html table. The line of code should look
like this, replacing your variable names where appropriate:
"<tr><td>" + orderid + "</td><td>" + ordermode + 
"</td><td>" + orderstatus + "</td><td>" +
ordertotal + "</td><td>" + rs1.getRow() +
"</td></tr>";
f. Finally, create the getOrderItems method. This method will use a prepared
statement to display in a table the order items for whichever orderid is selected
in the servlet.
i. Create the getOrderItems method in the class. This method will return
the order item rows in an HTML table (in a String) for display in the servlet,
and accepts the String value of the selected orderid from the servlet.
ii. Use the setInt() method of PreparedStatement to parse the integer
value of order_id.
iii. Create a new method variable of type ResultSet and set it equal to the
value of the executed query of the PreparedStatement.
iv. Create a StringBuffer object and initialize it as follows:
StringBuffer itemrow = new StringBuffer(1000);
v. Using a while loop, loop through all records in the ResultSet object. As
you iterate through each row, fetch the ORDERID, LINEITEMID,
PRODUCTID, UNITPRICE, QUANTITY and DISCOUNT values and save
them in String variables by the same name. The values can be retrieved using
the number of their column, such as: rs.getString(1);
vi. Next in the while loop, add the following code:
itemrow.append += "<tr><td>" + orderid + 
"</td><td>" + lineitemid + "</td><td>" + productid
+ "</td><td>" + unitprice + "</td><td>" + quantity
+ "</td><td>" + discount + "</td></tr>“
Notice that you are creating a new HTML table row for each row returned
from the result set.
vii. Now outside of the while loop, close the ResultSet object.
viii.Return itemrow.toString() from the method.
ix. Compile to test the application.
g. Run ResultDisplay.java and use the HTML controls in the servlet to
navigate through the result set.

Oracle9i: Access the Database with Java and JDBC 4-36


JDBC Optional Package and JDBC
in Web Applications

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

70 minutes Lecture
40 minutes Practice
110 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Connect to a database using Java Naming and
Directory Interface (JNDI)
• Use connection pooling and connection cache
• Perform distributed transactions
• Control Statement caching
• Manage client security with JDBC
• Connect to a database with applets

5-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
This lesson discusses some J2EE features and how they are implemented using JDBC 2.0.

Oracle9i: Access the Database with Java and JDBC 5-2


J2EE/JDBC 2.0 Features

JDBC API is divided into two parts:


• JDBC 2.0 core API

JNDI

Connection pooling

Distributed
transaction
• JDBC 2.0 standard extensions API
• Oracle9i, Release 2 will provide partial support for
JDBC 3.0

5-3 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC 2.0 Extensions


JDBC 2.0 provides a new set of features for developing Java applications that access a
database. Since Oracle8i, release 2, the Oracle drivers fully comply with Java 2 and JDBC
2.0.
JDBC 2.0 API is divided into two parts:
• JDBC core API, which is part of Java 1.2. It has been kept small and simple for ease of
use.
• JDBC standard extensions API, which is contained in the javax.sql package. It
provides more advanced functionalities.
Using these specifications, each database vendor adds its own driver. The following pages
describe these specifications and the Oracle driver functionalities that support them.
The features that are discussed on the following pages include:
• Java Naming and Directory Interface (JNDI)
• Connection pooling and connection cache
• Distributed transactions
• Advanced data types
Instructor Note
Oracle9i, Release 2 will provide partial support for JDBC 3.0 including: transaction
savepoints, toggling between local/global.

Oracle9i: Access the Database with Java and JDBC 5-3


Database Connection Flexibility

Part of the J2EE specifications and included in JDBC


2.0, JNDI provides a flexible service to connect to a
database with the following advantages:
• No hardcoded database reference
• Use of logical names
• Physical databases can change:
– New instance names
– New physical location
– New database provider

5-4 Copyright © Oracle Corporation, 2002. All rights reserved.

JDBC 2.0 Extensions


J2EE.2.6.8 Java Naming and Directory Interface™ (JNDI). The JNDI API is the standard
API for naming and directory access.
The JNDI API has two parts:
• An application-level interface used by the application components to access naming and
directory services
• A service provider interface to attach a provider of a naming and directory service.
JNDI
To use the JNDI functionality you need the jndi.jar file to be in the CLASSPATH . This
file is included with the Java products on the Oracle9i CD, but is not included in the
classes12.zip and classes111.zip files.

Oracle9i: Access the Database with Java and JDBC 5-4


Java Naming Directory Interface

• Allows connection to a directory service that


manages data sources
• Uses lookup facilities to identify a database
service from a logical name
• Facilitates deployment and maintenance
• All Oracle data sources can be referenced by JNDI

5-5 Copyright © Oracle Corporation, 2002. All rights reserved.

What is JNDI?
Java Naming and Directory Interface (JNDI) provides a uniform way for applications to find
and access remote services over the network. The remote service is most likely to be a
database service, but it could be a messaging service or an application-specific service. JNDI
simply makes JDBC applications easier to manage.
To establish a connection to a database, you first need to register the JDBC driver and then
to specify a JDBC-type URL to connect to the database using the driver manager. In doing
so, you depend not only on a JDBC vendor driver but also on a machine name and a port
number, which are part of the URL components. This dependency can make the application
difficult to maintain.
JNDI solves this problem, allowing an application to refer to a logical name that JNDI
associates with a particular data source.
A JDBC data source object implements the javax.sql.DataSource interface. A data
source object is a factory for JDBC connections.
Prior to JDBC 2.0, an application received a connection from java.sql.driver. The
application had to create an instance of the driver object in a vendor-specific way, register
the driver, and then ask the driver manager to return an appropriate driver, given a vendor-
specific URL.
The data source is created using a JDBC driver vendor class, and it implements
javax.sql.DataSource. Oracle provides the
oracle.jdbs.pool.OracleDataSource class to create your data source.
The JNDI class library need to be added to the CLASSPATH.
Oracle9i: Access the Database with Java and JDBC 5-5
Using JNDI

DataSource
Middle Tier
D3
JNDI
Lookup
operation
Oracle

D1/ D2/ D3/


ORCL7 ORCL8 ORCL9
Database
connection

ORCL7 ORCL8 ORCL9

Logical DataSource name is mapped to a


corresponding physical Database

5-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Imports Required to Use JNDI


import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.OracleDataSource;
import javax.naming.*;
import javax.naming.spi.*;
import java.util.Hashtable;

Oracle9i: Access the Database with Java and JDBC 5-6


Creating a Data Source

A data source describes the database properties:


• Specify the data source parameters
• A named data source can be saved in a directory
service
OracleDataSource ods = new OracleDataSource();
ods.setDatabaseName ("ORCL");
ods.setDriverType ("oracle");
ods.setNetworkProtocol("thin");
(This is the administrator role to create the data
sources)

5-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Creating JNDI with Oracle


The oracle.jdbc.pool.OracleDataSource class has set and get methods,
allowing you to specify the parameters that are needed to complete the data source
definition. Following is a list of all the set methods available. The same get methods exist.
setDatabaseName(java.lang.String dsname): Set the name of a particular
database on a server.
setDataSourceName(java.lang.String dsname): Set the data source name
setDescription(java.lang.String des): Set the description for this data
source instance
setDriverType(java.lang.String dt): Set the JDBC driver type
setLoginTimeout(int timeout): Set the maximum time, in seconds, that this data
source will wait while attempting to connect to a database
setLogWriter(java.io.PrintWriter pw): Set the log writer for this data source
setNetworkProtocol(java.lang.String np): Set the network protocol for
connections
setPassword(java.lang.String pd): Set the password that is required to obtain
connections
setPortNumber(int pn): Set the number of the port where a server is listening for
requests
setServerName(java.lang.String sn): Set the name of the server on which the
database is running
setTNSEntryName(java.lang.String dbname): Set the TNS entry name
setURL(java.lang.String url): Set the URL from which connections have to be
obtained
setUser(java.lang.String user): Set the user name that must be used to obtain
connections
Oracle9i: Access the Database with Java and JDBC 5-7
Registering the Data Source

• Register the Data Source in the JNDI service


...
Context ctx = new InitialContext();
ctx.bind("jdbc/sampledb", ods);
...

• The logical name for the Data Source is created

5-8 Copyright © Oracle Corporation, 2002. All rights reserved.

Registering the Data Source


Once you have initialized the connection properties of the OracleDataSource instance
ods, as shown in the preceding example, you can register this data source instance with
JNDI, as in the following example:
...
Context ctx = new InitialContext();
ctx.bind("jdbc/sampledb", ods);
...
Calling the JNDI InitialContext() constructor creates a Java object that references
the initial JNDI naming context. System properties that 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 name space 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.

Oracle9i: Access the Database with Java and JDBC 5-8


Using the Data Source

• Specify the logical name and the JNDI directory


...
OracleDataSource ods =
(OracleDataSource)ctx.lookup("jdbc/sampledb");
Connection conn = ods.getConnection();
...

• Alternatively a username and password override


the Data Source one
Connection conn = ods.getConnection
("bill", "lion");

5-9 Copyright © Oracle Corporation, 2002. All rights reserved.

Open a Connection
To perform a lookup and open a connection to the database that is logically bound to the
JNDI name, use the logical JNDI name. Doing this requires casting the lookup result (which
is otherwise simply a Java Object) to a new OracleDataSource instance and then using its
getConnection() method to open the connection.

Oracle9i: Access the Database with Java and JDBC 5-9


Connection Pooling

• Use it to minimize the operation costs of creating


and closing sessions
• Use explicit Data Source declaration or JNDI entry
for physical reference to the database
• Use the getConnection() method to obtain a
logical connection instance

5-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Connection Pooling Presentation


A connection pool is a cache of database connections. It is maintained in memory, which
enables the connections to be reused. This technique is important for increasing
performance, especially when the JDBC API is used in a middle-tier environment.
Connection pooling does not affect application code. The application simply accesses a
JDBC data source and uses it in the standard way. The data source implements connection
pooling transparently to the application using the PooledConnection and
ConnectionPoolDataSource facilities provided by the JDBC 2.0 driver.

Oracle9i: Access the Database with Java and JDBC 5-10


Connection Pooling
Middle tier

Java servlet

Data source

Middle-tier server code

ConnectionPoolDataSource
JDBC
driver Database

Database
commands

5-11 Copyright © Oracle Corporation, 2002. All rights reserved.

Connection Pooling Presentation (continued)


When using pooled connections, you must perform the following two steps:
• Use a DataSource object rather than the DriverManager class to get a connection. The
DataSource object is implemented and deployed so that it will create pooled
connections.
• Use a finally statement to close a pooled connection. The following finally statement
would appear after the try and catch blocks that apply to the code in which the pooled
connection is used:
try { Connection con =
ds.getConnection("Login","Password");
// ... code to use the pooled connection con
}

catch (Exception ex {
// . . . code to handle exceptions
}

finally {
if(con != null) con.close();
}

Note: Connection pooling is supported in both JDK1.1 and JDK 1.2 OCI and in thin drivers.
Connection pooling is not supported for the server driver since the server driver can have
only one connection, which is to the logged-in session in which it is running.

Oracle9i: Access the Database with Java and JDBC 5-11


Connection Cache

• Use cache implementation to specify cache


properties
• Use the OracleConnectionCacheImpl() method
to specify:
– Maximum number of pooled connections
– Minimum number of pooled connections
– The scheme for new pooled connections:
Dynamic
Fixed with No Wait
Fixed with Wait

5-12 Copyright © Oracle Corporation, 2002. All rights reserved.

Connection Cache
Connection pooling, a JDBC 2.0 feature described earlier, is an infrastructure for supporting
connection caching. It provides no real additional functionality alone, without a connection
caching mechanism. The Oracle connection cache provides three commonly used caching
schemes in addition to making it easy for middle-tier developers to implement their own
schemes:
• Dynamic: This is the default scheme. New connections can be created beyond the
maximum limit upon request but are closed and freed when the logical connections are
closed. When all the connections are active and busy, requests for new connections will
create new physical connections, but these physical connections are closed when the
corresponding logical connections are closed. This is a typical grow and shrink scheme.
• Fixed with No Wait: At no time will there be more active connections than the
maximum limit. Requests for new connections beyond the maximum limit will return
null.
• Fixed with Wait: This is the same as the Fixed with No Wait scheme except that
requests for new connections beyond the maximum will wait until a connection becomes
available.
Connection caching is supported in both the JDK 1.1 and JDK 1.2 JDBC drivers.

Oracle9i: Access the Database with Java and JDBC 5-12


Using a Connection Cache

OracleConnectionPoolDataSource ocpds =
new OracleConnectionPoolDataSource();

ocpds.setDriverType("oci");
ocpds.setDatabaseName("orcl");
ocpds.setPortNumber(1521);
ocpds.setUser("scott");
ocpds.setPassword("tiger");

PooledConnection pc =
ocpds.getPooledConnection();

Connection conn = pc.getConnection();

5-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Preliminary Steps in Connection Caching


Presume the following has already been accomplished:
1. The middle tier has created a connection cache instance
2. The middle tier has provided connection information to the connection cache instance
for the database and schema that will be used. This can be accomplished when
constructing the connection cache instance.
3. The application has retrieved the connection cache instance
General steps in opening a connection
Once the JDBC application has access to the connection cache instance, the application and
middle tier perform the following steps to produce a logical connection instance for use by
the application:
1. The application requests a connection through the getConnection() method of the
connection cache instance. No input is necessary, because a connection cache instance
is already associated with a particular database and schema.
2. The connection cache instance examines its cache as follows:
a. To see if there are any pooled connection instances in the cache yet; and
b. If so, if any are free—that is, to see if there is at least one pooled connection
instance that currently has no logical connection instance associated with it.
3. The connection cache instance chooses an available pooled connection instance or, if
none is available, might create a new one (this is implementation-specific). In creating
a pooled connection instance, the connection cache instance can specify connection
properties according to its own connection properties.
Oracle9i: Access the Database with Java and JDBC 5-13
Connection Cache Properties

• Setting cache properties


OracleConnectionCacheImpl ocacheimpl = new
OracleConnectionCacheImpl(ocpds);

ocacheimpl.setMaxLimit(5);
ocacheimpl.setMinLimit(2);
Ocacheimpl.setCacheScheme
(OracleConnectionCacheImpl.
FIXED_RETURN_NULL_SCHEME);
• Testing cache properties
getActiveSize()
getCacheSize()

5-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Preliminary Steps in Connection Caching (continued)


Oracle offers a sample implementation of connection caching and connection event
listeners, providing the OracleConnectionCacheImpl class. This class
implements the OracleConnectionCache interface (which you can optionally
implement yourself in some other connection cache class) and uses instances of the
OracleConnectionEventListener class for listener functionality.
These Oracle classes and interfaces are all in the oracle.jdbc.pool package.
The use of the OracleConnectionCacheImpl class allows you to specify caching
properties such as:
• Setting a maximum number of pooled connections
• Setting a minimum number of pooled connections
• Schemes for creating new pooled connections in the Oracle Implementation

Oracle9i: Access the Database with Java and JDBC 5-14


Distributed Transactions Overview
Middle tier

Application code

Data source

Middle-tier server code Database

XADataSource
JDBC Database
driver

Database Database
commands

5-15 Copyright © Oracle Corporation, 2002. All rights reserved.

Distributed Transactions Overview


The slide shows a Web client running in a browser that invokes some bit of application code
executing in a middle-tier server environment. The middle-tier server could be a Java-
enabled Web server, an Enterprise JavaBeans server, or some other type of application server
that supports the Java programming language. The middle-tier application code uses the
JDBC API to access a pair of databases in the context of a global (distributed) transaction.
The fact that distributed transactions are used does not greatly affect the code that the
application developer must write. You need to initiate a global (distributed) transaction with
a transaction manager and not to a specific data source. Then the application code uses
XADataSource instead of a normal data source in the standard way to obtain a
Connection object.
The data source implementation, which is provided by the middle-tier server, interacts with
the transaction manager to set up the transactional environment for the connection returned
to the application and typically maintains a pool of database connections to achieve
maximum performance.
Follow this URL to get more information about distributed transactions:
http://developer.java.sun.com/developer/Books/JDBCTutorial/
Note: Using JTA functionality requires file jta.jar to be in the CLASSPATH. (This file is
located at $ORACLE_HOME/jlib.) Oracle includes this file with the JDBC product. (You
can also obtain it from the Sun Microsystems Web site, but it is advisable to use the version
from Oracle, because that has been tested with the Oracle drivers.)

Oracle9i: Access the Database with Java and JDBC 5-15


 T
 ran sa ct
 ion m an ager

 branch
 branchB

 A
Using Distributed Connections

• Determine the package to use:


– oracle.jdbc.xa
– oracle.jdbc.xa.client
– oracle.jdbc.xa.server
• Use the available classes of the specified package:
– OracleXAConnection
– OracleXADataSource
– OracleXAResource

5-16 Copyright © Oracle Corporation, 2002. All rights reserved.

Distributed Transactions
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 the code that runs 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.
You must import the following for Oracle XA functionality:
• import oracle.jdbc.xa.OracleXid;
• import oracle.jdbc.xa.OracleXAException;
• import oracle.jdbc.pool.*;
• import oracle.jdbc.xa.client.*;
• import javax.transaction.xa.*;

Oracle9i: Access the Database with Java and JDBC 5-16


Distributed Transactions (continued)
If your application is running in the Oracle JVM and is using both the server-side driver and
the thin driver, then you must take care to use the right class in the right place. Generally,
you will want to use fully qualified class names,
oracle.jdbc.xa.client.OracleDataSource and
oracle.jdbc.xa.server.OracleDataSource, rather than IMPORT statements. If
you import both packages into the same class, you will have problems because the class
names are the same. Similarly, you will have problems if you import one package but intend
to use classes from both. In this case, an unqualified name would refer to the imported
package, and a fully qualified name would be required to refer to the other. Mistakenly
omitting the qualification would lead to run-time errors. If you do not import either and use
only fully qualified names, omission of the qualification will cause a compile error rather
than a run-time error.
Distributed transactions are supported in the JDK 1.1 and SDK 1.2 drivers. Distributed
transaction support is not backward compatible with older versions of the Oracle database
server. Distributed transactions are supported only on Oracle8i, release 2, and later Oracle
database servers with the Oracle Java VM installed on the server.

Oracle9i: Access the Database with Java and JDBC 5-17


Performing a Distributed Transaction

When performing a distributed transaction the


following steps apply:
• Create XA data sources
• Establish the XA connections
• Get the physical connections
• Get the XA resources
• Create Xids for each branch with the same global
ID
• Start the resources on each branch
• Perform SQL operations on each branch
• End the resources on each branch
• Prepare changes on each branch
• Commit changes on each branch

5-18 Copyright © Oracle Corporation, 2002. All rights reserved.

XA Resource Method Functionality and Input Parameters


The OracleXAResource class has several methods to coordinate a transaction branch
with the distributed transaction with which it is associated. This functionality usually
involves two-phase COMMIT operations.
A transaction manager, receiving OracleXAResource instances from a middle-tier
component such as an application server, typically invokes this functionality.
Each of these methods takes a transaction ID as input, in the form of an Xid instance, which
includes a transaction branch ID component and a distributed transaction ID component.
Every transaction branch has a unique transaction ID, but transaction branches belonging to
the same global transaction have the same global transaction component as part of their
transaction IDs.
XA ID Interface and Oracle Implementation
The transaction manager creates transaction ID instances and uses them in
coordinating the branches of a distributed transaction. Each transaction branch is
assigned a unique transaction ID.

Oracle9i: Access the Database with Java and JDBC 5-18


Distributed Transaction Branch Testing
Before commiting changes, test operation success
on each branch (two phases commit)
oxar1.end(xid1, XAResource.TMSUCCESS);
End the branchesoxar2.end(xid2, XAResource.TMSUCCESS);
int prp1 = oxar1.prepare (xid1);
Prepare the branchesint prp2 = oxar2.prepare (xid2);
boolean do_commit = true;
if (!((prp1 ==
XAResource.XA_OK)||(prp1==XAResource.XA_RDONLY)))
do_commit = false;
if (!((prp2 == XAResource.XA_OK)||(prp2==
AResource.XA_RDONLY)))
do_commit = false;
if (prp1 == XAResource.XA_OK)
if (do_commit) xar1.commit (xid1, false);
else oxar1.rollback (xid1);
if (prp2 == XAResource.XA_OK)
if (do_commit) oxar2.commit (xid2, false);
else oxar2.rollback (xid2);

5-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Complete Code Example of Distributed Transactions


OracleXADataSource oxds1 = new OracleXADataSource();
oxds1.setURL("jdbc:oracle:oci8:@");
oxds1.setUser("scott");
oxds1.setPassword("tiger");
OracleXADataSource oxds2 = new OracleXADataSource();
oxds2.setURL("jdbc:oracle:thin:@(description=(address=(host=dl
sun991)
(protocol=tcp)(port=5521))(connect_data=(sid=rdbms2)))");
oxds2.setUser("scott");
oxds2.setPassword("tiger");
// Get XA connections to the underlying data sources
XAConnection pc1 = oxds1.getXAConnection();
XAConnection pc2 = oxds2.getXAConnection();
// Get the physical connections
Connection conn1 = pc1.getConnection();
Connection conn2 = pc2.getConnection();
// Get the XA resources
XAResource oxar1 = pc1.getXAResource();
XAResource oxar2 = pc2.getXAResource();

Oracle9i: Access the Database with Java and JDBC 5-19


Complete Code Example of Distributed Transactions (continued)
// Create the Xids With the Same Global Ids
Xid xid1 = createXid(1);
Xid xid2 = createXid(2);
// Start the Resources
oxar1.start (xid1, XAResource.TMNOFLAGS);
oxar2.start (xid2, XAResource.TMNOFLAGS);
// Execute SQL operations with conn1 and conn2
doSomeWork1 (conn1);
doSomeWork2 (conn2);
// END both the branches -- IMPORTANT
oxar1.end(xid1, XAResource.TMSUCCESS);
oxar2.end(xid2, XAResource.TMSUCCESS);
// Prepare the RMs
int prp1 = oxar1.prepare (xid1);
int prp2 = oxar2.prepare (xid2);
System.out.println("Return value of prepare 1 is " + prp1);
System.out.println("Return value of prepare 2 is " + prp2);
boolean do_commit = true;
if (!((prp1 == XAResource.XA_OK) || (prp1 ==
XAResource.XA_RDONLY)))
do_commit = false;
if (!((prp2 == XAResource.XA_OK) || (prp2 ==
XAResource.XA_RDONLY)))
do_commit = false;
System.out.println("do_commit is " + do_commit);
System.out.println("Is oxar1 same as oxar2 ? " +
oxar1.isSameRM(oxar2));
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;

Oracle9i: Access the Database with Java and JDBC 5-20


Statement Caching

• Statement caching prevents:


– Overhead of repeated cursor creation
– Repeated statement parsing and creation
• Statement caching forms are:
– Implicit
– Explicit
• Enabling Statement caching:
((OracleConnection)conn).setStmtCacheSize(10);

5-21 Copyright © Oracle Corporation, 2002. All rights reserved.

About 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.
Statement caching can:
• Prevent the overhead of repeated cursor creation
• Prevent repeated statement parsing and creation
Basics of statement caching
Use a statement cache to cache statements that are associated with a particular physical
connection. Enabling statement caching automatically enables implicit and explicit statement
caching. Both these types of statement caching share the same cache.
For a simple connection, the cache is associated with an OracleConnection object. For
a pooled connection, the cache is associated with an OraclePooledConnection object.
The OracleConnection and OraclePooledConnection objects include methods
to enable statement caching.
When you enable statement caching, a statement object is cached when you call the “close”
methods.
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 pooled connection, all the logical connections will use the same cache. If you try to enable
statement caching on a logical connection of a pooled connection, this will throw an
exception. There are two forms of statement caching:
• Implicit
• Explicit
Oracle9i: Access the Database with Java and JDBC 5-21
Implicit Statement Caching

Statement Cache
Automatic cache • Case sensitive check
check for implicit • Statement type
• Scrollable type

N
New statement Found ?

Y
Statement Cache

• Case sensitive check State & Data


• Statement type Re-initialized
• Scrollable type

5-22 Copyright © Oracle Corporation, 2002. All rights reserved.

Implicit Statement Caching


When you enable statement caching, implicit statement caching automatically caches the
prepared or callable statement when you call the close() method of this statement object.
The prepared and callable statements are cached and retrieved using standard connection
object and statement object methods.
Plain statements are not implicitly cached because implicit statement caching uses a SQL
string as a key, and plain statements are created without a SQL string.
Therefore, implicit statement caching applies only to the OraclePreparedStatement
and OracleCallableStatement objects, that are created with a SQL string. When one
of these statements is created, the JDBC driver automatically searches the cache for a
matching statement. The match criteria are the following:
• The SQL string in the statement must be identical (case-sensitive) to one in the cache.
• The statement type must be the same (prepared or callable).
• The scrollable type of result sets produced by the statement must be the same (forward-
only or scrollable).
During implicit statement caching, if the JDBC driver cannot find a statement in cache, it
will automatically create one.
Note: You can determine the scrollability when you create the statement.
Oracle9i: Access the Database with Java and JDBC 5-22
Explicit Statement Caching

WithKey()
Statement Cache

N
null
Found ?

Reuse of cached information

5-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Explicit Statement Caching


When you enable statement caching, explicit statement caching, which is based on a user-
defined key, enables you to cache and retrieve selected prepared, callable, and plain
statements. The key is an arbitrary Java string that you provide.
To explicitly cache a statement and to retrieve an explicitly cached statement, use the Oracle
“WithKey” methods. Employing these methods, specify the key as an input parameter. As
the name implies, explicit statement caching is performed on each statement object you want
to cache.
If the JDBC driver finds the matching statement with the specified key, then the statement is
returned. If the JDBC driver cannot find a matching statement in the cache, it will return a
null value.
Comparing implicit and explicit statement caching
Because explicit statement caching retains the statement data and state, in addition to the
metadata, it has a performance edge over implicit statement caching, which retains only the
metadata. However, because explicit statement caching saves all three types of information
for reuse, you must be cautious when using this type of caching—you may not be aware of
what was retained for data and state in the previous statement.
Implicit statement caching uses standard methods to allocate and retrieve statement objects.
Explicit statement caching uses standard methods to allocate statements and specialized
Oracle “WithKey” methods to cache and retrieve statement objects.
Implicit statement caching uses the SQL string of a prepared or callable statement as the key,
requiring no action on your part.
Explicit statement caching requires you to provide a Java string, which it uses as the key.

Oracle9i: Access the Database with Java and JDBC 5-23


Implicit Statement Caching Use

• Allocate a statement
PreparedStatement pstmt = conn.prepareStatement
("UPDATE emp SET ename = ? WHERE rowid = ?");

• Cache the statement


((OracleConnection)conn)psmt).close();

• Test for statement caching status


Int state=((OracleStatement)stmt).creationState();

5-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Statement Caching Use


You can dynamically enable and disable statement caching. Enable statement caching by
calling the setStmtCacheSize() method of your connection object, setting the cache to
a value greater than zero. The cache size you specify is the maximum number of statements
in the cache. Enable statement caching to be able to use implicit or explicit statement
caching.
Retrieving an implicitly cached statement
To recall an implicitly cached statement, call either the prepareStatement() or
prepareCall()method, depending on the statement type.
The following code recalls pstmt from cache using the prepareStatement()
method:
pstmt = conn.prepareStatement ("UPDATE emp SET ename = ? WHERE
rowid = ?");
If you call the creationState() method on the pstmt statement object, the
method returns IMPLICIT. If the pstmt statement object was not in cache, then the
creationState() method returns NEW to indicate that a new statement was recently
created by the JDBC driver.

Oracle9i: Access the Database with Java and JDBC 5-24


Explicit Caching Code Example
Connection conn=DriverManager.getConnection (url,
"scott", "tiger");
((OracleConnection)conn).setStmtCacheSize(1);
String sql = "SELECT ename FROM emp";
PreparedStatement stmt = conn.prepareStatement (sql);
System.out.println("1. Stmt is " + stmt);
ResultSet rset = stmt.executeQuery ();
while (rset.next ())
...
rset.close();
stmt.close();
((OracleStatement)stmt).closeWithKey ("mysql");
System.out.println("End of 1st execution");
System.out.println("Reexecuting the same SQL");
stmt =
((OracleConnection)conn).prepareStatementWithKey
("mysql");
rset = stmt.executeQuery ();
while (rset.next ())
...

5-25 Copyright © Oracle Corporation, 2002. All rights reserved.

Code and Steps for Explicit Caching


// Create a Statement
// Select the ENAME column from the EMP table
// Iterate through the result and print the employee names
// Close the ResultSet
// Close the Statement
((OracleStatement)stmt).closeWithKey ("mysql");
System.out.println("End of 1st execution");
getOpenCursors (sysconn);
System.out.println("Reexecuting the same SQL");
stmt = ((OracleConnection)conn).prepareStatementWithKey
("mysql");
System.out.println("2. Stmt is " + stmt);
// Select the ENAME column from the EMP table
rset = stmt.executeQuery ();
// Iterate through the result and print the employee names
while (rset.next ())
System.out.println (rset.getString (1));
// Close the RseultSet
rset.close();
// Close the Statement
stmt.close();
System.out.println("End of 2nd execution");
Oracle9i: Access the Database with Java and JDBC 5-25
Client Security with JDBC

• JDBC OCI & Thin drivers support features of


Oracle Advanced Security, such as:
– Data encryption
– Data integrity
– Third-party authentication
– Authorizations
• Classes111.zip and classes12.zip include
required JAR files

5-26 Copyright © Oracle Corporation, 2002. All rights reserved.

Client Security with JDBC


Oracle Advanced Security, previously known as the “Advanced Networking Option” (ANO)
or “Advanced Security Option” (ASO), includes features to support data encryption, data
integrity, third-party authentication, and authorizations.
Oracle JDBC supports most of these features; however, the JDBC Thin driver must be
considered separately from the JDBC OCI driver.
Both the JDBC OCI drivers and the JDBC Thin driver support at least some of the features
of Oracle Advanced Security. If you are using one of the OCI drivers, you can set relevant
parameters in the same way that you would in any thick-client setting. The Thin driver
supports Advanced Security features through a set of Java classes included with the JDBC
classes ZIP file, and supports security parameter settings through Java properties objects.

Oracle9i: Access the Database with Java and JDBC 5-26


Authentication Encryption and Integrity

• Authentication:
– Thin driver implements Oracle O3LOGON to
authenticate the user
– OCI driver supports any thick client situation
• Encryption and Integrity are based on combination
of client side and server side security parameters
• Encryption and Integrity parameters are set:
– Through SQLNET.ORA file on the client for OCI
– Through a Java properties object

5-27 Copyright © Oracle Corporation, 2002. All rights reserved.

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
Client integrity level SQLNET.CRYPTO_CHECKSUM_CLIENT REJECTED
ACCEPTED
REQUESTED
REQUIRED
Client integrity selected list SQLNET.CRYPTO_CHECKSUM_TYPES_CLIENT MD5

For more information about these settings, refer to Appendix A of the Oracle Advanced
Security Administrator’s Guide.

Oracle9i: Access the Database with Java and JDBC 5-27


Setting Encryption and Integrity
Parameters for Thin

Thin driver uses Java


...
Properties prop = new Properties();
prop.put("oracle.net.encryption_client", "REQUIRED");
prop.put("oracle.net.encryption_types_client",
"( DES40 )");
prop.put("oracle.net.crypto_checksum_client",
"REQUESTED");
prop.put("oracle.net.crypto_checksum_types_client",
"( MD5 )");
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@localhost:1521:main", prop);
...

5-28 Copyright © Oracle Corporation, 2002. All rights reserved.

Thin Driver Client Parameters for Encryption and Integrity

Parameter Name Parameter Parameter Possible

Type Class Settings

Oracle.net.encryption_client string static REJECTED


ACCEPTED
REQUESTED
REQUIRED
oracle.net.encryption_types_client string static RC4_40
RC4_56
DES40C
DES56C
oracle.net.crypto_checksum_client string static REJECTED
ACCEPTED
REQUESTED
REQUIRED
oracle.net.crypto_checksum_types_client string static MDS

For more information about these settings, refer to Appendix A of the Oracle Advanced
Security Administrator’s Guide.
Oracle9i: Access the Database with Java and JDBC 5-28
JDBC in Applets

• 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 a HTML file

5-29 Copyright © Oracle Corporation, 2002. All rights reserved.

Applet Basics
This section describes the issues you should take into consideration if you are writing an
applet that uses the JDBC Thin driver.
Applets and security
Without special preparations, an applet can open network connections only to the host
machine from which it was downloaded. Therefore, an applet can connect to databases only
on the originating machine. If you want to connect to a database running on a different
machine, you have two options:
• Use Oracle Connection Manager on the host machine. The applet can connect to Oracle
Connection Manager, which in turn connects to a database on another machine.
• Use signed applets, which can request socket connection privileges to other machines.
The Thin driver offers support for data encryption and integrity checksum features of the
Oracle Advanced Security option.
Applets and firewalls
An applet that uses the JDBC Thin driver can connect to a database through a firewall.
Packaging and deploying applets
To package and deploy an applet, you must place the JDBC Thin driver classes and
the applet classes in the same zip file.

Oracle9i: Access the Database with Java and JDBC 5-29


Connecting to the Database
Through an Applet

• Applet connecting to a database running on the


same host as the Web Server:
String connString="jdbc:oracle:thin:@myHost:
1521:ORCL";
conn = DriverManager.getConnection(connString,
"scott", "tiger");

• To connect an Applet to a database running on a


different host than the Web Server there are two
possible ways:
– Use the Connection Manager
– Use a signed applet

5-30 Copyright © Oracle Corporation, 2002. All rights reserved.

Connecting to the Database Through the Applet


The most common task of an applet using the JDBC driver is to connect to and query a
database. Because of applet security restrictions, unless particular steps are taken an applet
can open TCP/IP sockets only to the host from which it was downloaded (this is the host on
which the Web server is running). This means that without these steps, your applet can
connect only to a database that is running on the same host as the Web server.
If your database and Web server are running on the same host, then there is no issue and no
special steps are required.
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 a TNS keyword-value syntax.
• Using host:port:sid syntax:
String connString="jdbc:oracle:thin:@myHost:1521:ORCL";
conn = DriverManager.getConnection(connString, "scott",
"tiger");
• Using TNS keyword-value syntax:
String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1521)(host=myHost)))
(connect_data=(sid=ORCL)))";
conn = DriverManager.getConnection(connString, "scott",
"tiger");
Oracle9i: Access the Database with Java and JDBC 5-30
Connection Manager

• Is installed on the Web host


• Runs on the Web host
• Is seen like a database server for the Applet
• Acts as a bridge to a database connection

Applet TCP/IP CMAN Oracle


(only) Web Net Database
Server

WebHost

5-31 Copyright © Oracle Corporation, 2002. All rights reserved.

Connecting to a Database on a Host Other than the Web Server


If you are connecting to a database on a host other than the one on which the Web server is
running, then you must overcome applet security restrictions. You can do this by using either
the Oracle Connection Manager or signed applets.
Using the Connection Manager
The Connection Manager is a lightweight, highly-scalable program that can receive Oracle
Net packets and re-transmit them to a different server. To a client running Oracle Net, the
Connection Manager looks exactly like a database server. An applet that uses the JDBC Thin
driver can connect to a Connection Manager running on the Web server host and have the
Connection Manager redirect the Oracle Net packets to an Oracle server running on a
different host.

Oracle9i: Access the Database with Java and JDBC 5-31


Applet Connection String

Example of the connect string syntax:


String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1610)(host=webHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(sid=orcl))
(source_route=yes))";
Connection conn =
DriverManager.getConnection(connString, "scott",
"tiger");

Web Host port must be 1610

5-32 Copyright © Oracle Corporation, 2002. All rights reserved.

Connecting Through Multiple Connection Managers


Your applet can reach its target database even if it first has to go through multiple
Connection Managers (for example, if the Connection Managers form a "proxy chain"). To
do this, add the addresses of the Connection Managers to the address list, in the order that
you plan to access them. The database listener should be the last address on this list.
See the Oracle Net Services Administrator’s Guide for more information about source_ route
addressing.

Oracle9i: Access the Database with Java and JDBC 5-32


Applets and Firewalls

Need an Oracle Net-Compliant Firewall and the


following operations:
• Configure a Firewall for applets using thin
driver
• Write a Connect string to connect through the
firewall Firewall for
unsigned Applets
Firewall for signed
Applets

Applet TCP/IP CMAN Oracle


(only) Web Net
Database
Server

WebHost

5-33 Copyright © Oracle Corporation, 2002. All rights reserved.

Using Applets with Firewalls


Under normal circumstances, an applet that uses the JDBC Thin driver cannot access the
database through a firewall. In general, the purpose of a firewall is to prevent unauthorized
clients from reaching the server. In the case of applets trying to connect to the database, the
firewall prevents the opening of a TCP/IP socket to the database.
Firewalls are rule-based. They have a list of rules that define which clients can connect, and
which cannot. Firewalls compare the client's hostname with the rules, and based on this
comparison, either grant the client access, or not. If the hostname lookup fails, the firewall
tries again. This time, the firewall extracts the IP address of the client and compares it to the
rules. The firewall is designed to do this so that users can specify rules that include
hostnames as well as IP addresses.
You can solve the firewall issue by using an Oracle Net-compliant firewall and connection
strings that comply with the firewall configuration. Oracle Net-compliant firewalls are
available from many leading vendors; a more detailed discussion of these firewalls is beyond
the scope of this manual.
An unsigned applet can access only the same host from which it was downloaded. In this
case, the Oracle Net-compliant firewall must be installed on that host. In contrast, a signed
applet can connect to any host. In this case, the firewall on the target host controls the access.
Oracle9i: Access the Database with Java and JDBC 5-33
Applet Using Thin Driver and Firewall

• Configuring the Firewall:


– Add the IP address of the host of the JDBC applet
– Suppress _jdbc_ hostnames from the firewall’s rules
• Writing the connect String example:
String connString =
"jdbc:oracle:thin:@(description=(address_list=
(address=(protocol=tcp)(port=1610)(host=fireWallHost))
(address=(protocol=tcp)(port=1521)(host=oraHost)))
(connect_data=(sid=orcl))
(source_route=yes))";
Connection conn =
DriverManager.getConnection(connString, "scott",
"tiger");

5-34 Copyright © Oracle Corporation, 2002. All rights reserved.

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—that is, they cannot get the hostname or
environment variables locally—because of security limitations. As a result, the JDBC Thin
driver cannot access the hostname on which it is running. The firewall cannot be provided
with the hostname. To allow requests from JDBC Thin clients to go through the firewall, you
must do the following two things to the firewall’s list of rules:
• Add the IP address (not the hostname) of the host on which the JDBC applet is running.
• Ensure that the hostname “__jdbc__” never appears in the firewall’s rules.
This hostname has been hard-coded as a false hostname inside the driver to force an IP
address lookup. If you do enter this hostname in the list of rules, then every applet using
Oracle’s JDBC Thin driver will be able to go through your firewall.
By not including the Thin driver’s hostname, the firewall is forced to do an IP address
lookup and base its access decision on the IP address, instead of the hostname.

Oracle9i: Access the Database with Java and JDBC 5-34


Packaging Applets

To deploy your applets, you have to do the followings


operations:
• Unzip the JDBC driver in an empty directory
• Unzip the nls_charset (optional)
• Add your applet classes files
• Zip all the files in a single ZIP or JAR file

5-35 Copyright © Oracle Corporation, 2002. All rights reserved.

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 (these
will be contained in either classes12.zip, if you are targeting a browser that
incorporates a JDK 1.2.x version, or classes111.zip, for a browser incorporating a
JDK 1.1.x version).
To package an applet, perform the following steps:
1. Move the JDBC driver classes file classes12.zip (or classes111.zip) to an
empty directory.
2. Unzip the JDBC driver classes ZIP file (and national language character set ZIP file, if
applicable).
3. Add your applet classes files to the directory, and any other files the applet might
require.
4. Zip the applet classes and driver classes together into a single ZIP or JAR file.
Additionally, if you are using DatabaseMetaData entry points in your applet, include
the oracle/jdbc/driver/OracleDatabaseMetaData.class file.
Note that this file is very large and might have a negative impact on performance. If
you do not use DatabaseMetaData methods, omit this file.
5. 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>
Oracle9i: Access the Database with Java and JDBC 5-35
Summary

• JNDI is a J2EE service used to connect to


databases using logical names
• Connection pooling and connection caching
minimize resources used to connect to the
database
• A transaction manager on the middle tier allows
you to perform distributed transactions
• Statement Caching prevents repeated cursor
creation and statement reparsing
• Encryption and Integrity are based on combination
of client side and server side security parameters
• Use Connection Manager or signed applets if your
applet needs to access a database running on a
different host than the web server

5-36 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 5-36


Practice 5 Overview

This practice covers:


• Using DataSource and JNDI to connect to a
database
• Using the PooledConnection

5-37 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 5-37


Practice 5-1
Goal
The goal of this practice is to use the JNDI service to connect to a database.
Your assignment
You use already created java files, and complete the existing code with additional
statements in order to use the JNDI service. The RegisterDataSource.java file
creates a temp/jndi directory with a file that contains the physical data sources
information needed to connect to a database.
The JndiConnection.java file establishes the connection based on a logical name
specified in the file by performing a lookup action in the file created in the previous
action, where the physical database information is stored.
To be able to run this practice, you need to had some specific .jar files to your project.
Setting up the environment
• Close any previously opened workspace in JDeveloper
• Open the workspace named Lesson05
• This workspace contains a Jndi project
• Add the following .jar files to your project
• Select Project | Project Settings from the menu
• Select the Libraries node
• Click New to add a library
• In the Library name type “JNDI Provider”
• Click Edit on the Class Path item
• Click Add Entry
• Locate the e:\labs\jndi\ directory
• Select fscontext.jar and providerutil.jar files
• Click Select
• Verify that both .jar files appear in the Edit Class Path dialog and click OK
• Verify that both jar files appear in the Class Path and click OK
• The JNDI Provider should now appear in the Selected Libraries
• Then click OK to exit Project Settings
• Make sure that only the RegisterDataSource entry is in the system navigator,
otherwise remove other files (from IDE only)
Completing the RegisterDataSource class
This java file when executed creates a temp/jndi directory on your system (if
needed) and create a datasource specification in the .bindings file
• Edit the RegisterDataSource.java file
1. Complete the following statements in the Main method
- String dsName = Type any name.
- String dbName = ""; //indicate the name of the SID
- String host = ""; // indicate the name of the host
- int port = ;// indicate the port number
String dsName = "ora9i";
String dbName = "iasdb";//indicate the name of the
SID
String host="localhost";//indicate the name of the
host
int port = 1521; //indicate the port number
Oracle9i: Access the Database with Java and JDBC 5-38
Practice 5-1 (continued)
• Edit the RegisterDataSource.java file(continued)
2. Locate the following comment in the Main method:
// Display the content of the database variables
- Use the println() method to display the content of the previous
variables
System.out.println("Host: " + host);
System.out.println("Port: " + port);
System.out.println("Database: " + dbName);
System.out.println("Pooled: " + pooled);
- Display the content of the jndiURL variable too
System.out.println("Jndi URL Path: " +
jndiURL);
• Compile and run the RegisterDataSource class
– Did it compile and run successfully?
– What is displayed in the log window?
Here is an example of what could be displayed
Host: ed-pdsun3.us.oracle.com
Port: 1521
Database: iasdb

Pooled: false
Jndi URL Path: file:/temp/jndi
Register DataSource: jdbc/ora9i
Done!
Process exited with exit code 0.
• Using Windows NT explorer, look for a /temp/jndi library.
• Does the library exist?
• Is there a file in the jndi directory, and what is its name?
The file is called .bindings
• Open the file to display its content.
Completing the JndiConnection class
This java file when executed uses the dsName variable and performs a lookup in the
.bindings file previously created to get the necessary information to establish a
database connection. Then it performs a query on the REGIONS table.
• Open the file named JndiConnection.java
Use the File | Open option in the menu
• Edit JndiConnection.java file
• Complete the following statements in the Main method
1. Create 5 null variables for
- InitialContext
- Connection
- PreparedStatement
- ResultSet
- DataSource

Oracle9i: Access the Database with Java and JDBC 5-39


Practice 5-1 (continued)
2. Complete the following statements in the Main method
String dsName = Type a name that maps the one used in the
RegisterDataSource class.
3. Create a data source using the following syntax
Ds = (DataSource) context.lookup(dsName);
4. Create a connection using your username/password
conn = ds.getConnection("username", "password");
5. Create a prepare statement that queries all columns of Countries table using the
regionId parameter
pstmt = conn.prepareStatement("SELECT * FROM
countries WHERE region_id = ?");
6. Use the setXXX method to supply a value to SELECT statement parameter, based
on the following syntax: pstmt.setXXX(index, value);
pstmt.setInt(1, regionId);
rset = pstmt.executeQuery();
7. Display a title for your query
System.out.println("List of Countries in Region " +
regionId);
8. Create a while loop to display each of the rows retrieved by the query
while (rset.next()) {
System.out.println(rset.getString("country_id")+" "+
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

Oracle9i: Access the Database with Java and JDBC 5-40


Practice 5-2
Goal
The goal of this practice is to illustrate the pool connection mechanism.
Your assignment
You use an already created java files, and complete the existing code with additional
statements. You need to rerun the RegisterDataSource class in order to create a new
entry in the JNDI service.
Then you complete the code of a new class named JndiPooledConnection.java.
This class opens a physical connection, and then a logical one. Once the connection is
established, you execute a query statement to retrieve rows of the COUNTRIES table. After,
you close the logical and then the physical connection.
In the second step, after closing your logical connection, you reopen a new logical one and
resubmit your SELECT statement. And finally after having closed your logical and physical
connection, you try to reopen a logical one.
Setting up the environment
• Open the workspace named Lesson05 if closed
• Run the RegisterDataSource class with a program argument set to –pool
– Select Project Settings from the menu
– Select the Runner node
– Type –pool in the Program Arguments and click OK
– Run RegisterDataSource to create a new entry in the Jndi service
• Open the file named JndiPooledConnection.java
Use the File | Open option in the menu
• Edit JndiPooledConnection.java file and view its content
• Complete the following statements in the Main method
1. Create 6 null variables for
- InitialContext
- Connection
- PreparedStatement
- ResultSet
- ConnectionPoolDataSource
- PooledConnection

Oracle9i: Access the Database with Java and JDBC 5-41


Practice 5-2 (continued)
2. Complete the following statement in the Main method
String dsName = “”Type a name that maps the one used in the
RegisterDataSource class.
3. Create a data source using the following syntax
ds = (ConnectionPoolDataSource)
context.lookup(dsName);
4. Create a pooled connection using your username/password
pooledConn = ds.getPooledConnection
("Username", "password");
5. Establish the connection for the pooledConnection
conn = pooledConn.getConnection();
6. Create a prepare statement that queries all columns of Countries table using the
regionId parameter.
pstmt = conn.prepareStatement("SELECT * FROM
countries WHERE region_id = ?");
7. Use the setXXX method to supply a value to SELECT statement parameter, based
on the following syntax: pstmt.setXXX(index, value);
pstmt.setInt(1, regionId);
8. Submit the prepared statement, and display a title for your query
rset = pstmt.executeQuery();
System.out.println("List of Countries in Region " +
regionId);
9. Create a while loop to display each of the rows retrieved by the query
while (rset.next()) {
System.out.println(rset.getString("country_id")+" "+
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

10. In the finally block, based on the following syntax close the Result set, the
prepared statement, the logical connection and the physical connection objects.
try { if (rset != null) rset.close(); } catch
(SQLException e) {}
finally
{

try { if (rset != null) rset.close(); } catch


(SQLException e) {}
try { if (pstmt != null) pstmt.close(); } catch
(SQLException e) {}
try { if (conn != null) conn.close(); } catch
(SQLException e) {}
try { if (pooledConn != null)
pooledConn.close(); } catch (SQLException e) {}
}

• Compile and run the JndiPooledConnection class


– Did it compile and run successfully?
– What is displayed in the Log window?
Oracle9i: Access the Database with Java and JDBC 5-42
Practice 5-2 (continued)
Testing the pooled connection
• After the ResultSet loop, close the logical connection
conn.close();
• Reopen the logical connection
conn = pooledConn.getConnection();
• Cut and paste the code that performs the Query and displays the result
rset = pstmt.executeQuery();
System.out.println("List of Countries in Region "
+ regionId);
while (rset.next()) {
System.out.println(rset.getString("country_id")
+ " " +
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

• Compile and run the RegisterDataSource class


– Did it compile and run successfully?
– What is displayed in the Log window?
• After the first ResultSet loop, after the close of the logical connection, close the
pooled connection
PooledConn.close();
• Compile and run the RegisterDataSource class
– Did it compile and run successfully?
– What is displayed in the Log window?
– Explain the error

Oracle9i: Access the Database with Java and JDBC 5-43


Developing and Deploying
Stored Procedures

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

60 minutes Lecture
45 minutes Practice
105 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Identify the benefits of stored procedures in Java
• Know the steps to deploy Java stored procedures
• Write Java stored procedures
• Use JDeveloper to load and publish a stored
procedure
• Call stored procedures from various entry points
• Describe the security attributes of stored
procedures

6-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
The ability to deploy Java stored procedures is an important feature of Oracle9i. Because Java
stored procedures run in the DBMS memory space, they generally execute faster than a routine
run by the client. This lesson teaches you how to write, load, and publish Java stored
procedures and how to call all stored procedures from Java.

Oracle9i: Access the Database with Java and JDBC 6-2


Overview

Server Benefits

Java stored procedure:


• Develop
• Deploy
• Call

6-3 Copyright © Oracle Corporation, 2002. All rights reserved.

Overview

A Java stored procedure resides on the database server at run time. This programming model
gives you several benefits that are described later.
You develop the procedure using JDeveloper and deploy it to the server using a custom
profile.

Oracle9i: Access the Database with Java and JDBC 6-3


What Is a Java Stored Procedure?

• An algorithm stored on the database


• A way to extend SQL with procedural logic
• A way to reach the Oracle9i Java Virtual Machine
• An alternative to PL/SQL

Java stored procedure

6-4 Copyright © Oracle Corporation, 2002. All rights reserved.

About Java Stored Procedures


The database industry has embraced SQL, which is an accepted standard language designed
for querying.
However, developing business logic, as opposed to querying, is better done using a higher-
level programming language, such as PL/SQL or Java. For instance, there are no for loop
constructs in SQL. In such situations, in addition to storing data on the database, you store an
algorithm also in the form of a stored procedure.
Although the term procedure is used, generally speaking, it is interchangeable with function (a
programming construct that returns a value).
Java stored procedures are stored procedures written in Java that you use to reach the Java
Virtual Machine on the server. The JVM on the server is an enterprise-class, scalable
implementation of the Java standards.

Oracle9i: Access the Database with Java and JDBC 6-4


Why Use Java Stored Procedures?

• Faster than a JDBC application running outside the


database
• A Java alternative to PL/SQL
• No network overhead
• No extra processes created
• Code compiled into an executable
• Code cached, potentially shared
• Server CPU speed

6-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Benefits of Stored Procedures


There are several benefits of using stored procedures in Java. The most important benefit is
increased performance:
• A Java stored procedure runs closest to where the data physically resides—namely, the
database. Almost by definition, then, this model is better than other programming
models, such as the one using the thin JDBC driver and working across the network.
• There are no extra processes created because the Java Virtual Machine is always running
when the database is up.
• Because the code has been verified and compiled into an executable, the running time is
vastly reduced. The code is also cached and shared.
• Generally, by grouping a series of SQL statements into an iterative procedure, you get
the benefits of working with the big picture; several things happen with one call.
• Finally, because the code runs on the server, which typically is a high-performance
machine, you get reduced running time.

Oracle9i: Access the Database with Java and JDBC 6-5


Why Use Java Stored Procedures?

• Centralized business rules:


– Avoid redundant coding
– Use existing RDBMS code Database
– Reduce maintenance

• Access control Relational Object-


• Scalable Data Relational Data

Java Stored
Procedure

PL/SQL Stored
Procedure

6-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Benefits of Stored Procedures (continued)


Other benefits of Java stored procedures result from centralized logic:
• When you put your stored procedure on the database, you are guaranteed that every
client that accesses the data has access to the logic. This implies that you avoid repeated
coding for every client.
• You benefit from existing code that is on the server, written by you or your partners or
from the database itself.
• Once validated, a stored procedure can be reused. The implementation can change to
provide enhanced functionality without affecting the end application.
• With stored procedures, you can decide who gets to use the code. This is because the
procedures are stored as an object like a table, much the way data is stored. For example,
you can allow access to a procedure that updates a database table but deny access to the
table itself.
• Using the Oracle multithreaded server facilities enables your stored procedure-based
applications to be scalable.
Instructor Note
It is difficult to decide whether stored procedures run faster or slower in Java than in PL/SQL.
There is no type mismatch between the data types used in PL/SQL and the SQL engine.
However, Java code can be compiled very efficiently, especially when the data access activity
includes compute-intensive subtasks (for example, changing the Gregorian calendar dates in
thousands of records to those used in the Japanese calendar system or vice versa). The
Oracle9i Java Virtual Machine includes a native Java compiler. Thus, it depends on the
application.
Oracle9i: Access the Database with Java and JDBC 6-6
How Do You Use
Java Stored Procedures?

You can call a Java stored procedure from:


• An applet or an application:
– JDBC
– SQLJ
• Another stored procedure
• SQL DML, PL/SQL, Forms, EJB
• Database triggers, object-relational methods

6-7 Copyright © Oracle Corporation, 2002. All rights reserved.

Using Java Stored Procedures


You can make use of the stored procedures that you have written in several ways:
• A Java applet or Java application can use the JDBC or SQLJ API to access the
procedures much the same way that you use them to access data.
• Another stored procedure (written in either Java or PL/SQL) can call the stored
procedures that you have written.
• You can access the stored procedures from SQL DML, PL/SQL, or Forms or from code
that meets the Enterprise JavaBeans (EJB) specifications.
• Triggers are yet another mechanism to access your stored procedures, as are object-
relational methods.

Oracle9i: Access the Database with Java and JDBC 6-7


The Oracle9i Database

Oracle9i

SQL
Oracle Net
PL/SQL

HTTP JVM JDBC

6-8 Copyright © Oracle Corporation, 2002. All rights reserved.

The Oracle9i Database and the Java Virtual Machine


The Oracle9i Java Virtual Machine (JVM) is:
• A complete Java execution environment
• Tightly integrated with the database
• Designed for optimal performance and scalability within the database environment
• Runs in the same process space and address space as the database kernel
• Shares a number of the databases kernel’s memory heaps
• Directly accesses the database’s buffer cache.
This architecture avoids duplicating memory to provide optimal performance.
The JVM is a general-purpose Java execution environment that is compliant with the Java
JDK specification but has been optimised to leverage the Oracle architecture.
The embedded JDBC Driver enables the JVM to communicate with SQL and PL/SQL. It
accesses SQL and PL/SQL locally within the server rather than using Oracle Net.
SQL and PL/SQL call Java using a set of mechanisms called Inter-Language Method Services.
This is the standard mechanism that is used for SQL to call PL/SQL, and for both SQL and
PL/SQL to “call out” to C external procedures. The calling mechanism was extended with
Oracle8i to enable SQL and PL/SQL to call Java.

Oracle9i: Access the Database with Java and JDBC 6-8


The Oracle9i JVM
JVM

Interpreter &
SQL Calls Run-time System
Memory
Natively
Compiled Code

Class Loader Garbage Collector

Loadjava Utility
RDBMS RDBMS
Library Manager Memory Manager
CREATE JAVA Statement

6-9 Copyright © Oracle Corporation, 2002. All rights reserved.

Main Components of the Oracle9i JVM


Library Manager
When invoked by the CREATE JAVA {SOURCE | CLASS | RESOURCE} statement,
the library manager loads Java source, class, or resource files into the database.
Garbage collection of memory
Garbage collection is a major feature of Java’s automated storage management, eliminating
the need for Java developers to allocate and free memory explicitly.
Compiler
The Oracle JVM includes a standard Java 2 (also known as JDK 1.2) Java compiler. When
invoked by the CREATE JAVA SOURCE statement, it translates Java source files into
architecture-neutral, one-byte instructions known as bytecodes.
Interpreter
To execute Java programs, the Oracle JVM includes a standard Java 2 bytecode interpreter.
For high throughput, the interpreter runs on the Shared Server, which manages sessions.
Class Loader
The class loader reads the class, then generates the data structures needed to execute it.
Immutable data and metadata are loaded into initialize-once shared memory. As a result, less
memory is required per session. Also, it invokes the Java compiler automatically when Java
class files must be recompiled (and the source files are available).
Oracle9i: Access the Database with Java and JDBC 6-9
The Oracle9i Java Virtual Machine (continued)
Verifier
Oracle security and Java security work with the verifier to protect your applications and data.
Note: Although your own code is interpreted, the Oracle JVM uses natively compiled versions
of the core Java class libraries, SQLJ translator, and JDBC drivers.
Server-side JDBC Internal Driver
Using low-level entry points, a specially tuned JDBC driver runs directly inside the RDBMS,
thereby providing the fastest access to Oracle data from Java stored procedures. The server-side
internal JDBC driver complies fully with the Sun Microsystems JDBC specification. Tightly
integrated with the RDBMS, it supports Oracle-specific data types, globalization character sets,
and stored procedures. Additionally, the client-side and server-side JDBC APIs are the same,
which makes it easy to partition applications.
Server-side SQLJ translator
The SQLJ preprocessor, itself a Java program, takes as input a Java source file in which SQLJ
clauses are embedded. Then, it translates the SQLJ clauses into Java class definitions that
implement the specified SQL statements. A highly optimized SQLJ translator runs directly
inside the RDBMS, where it provides run-time access to Oracle data using the server-side
internal JDBC driver. SQLJ forms can include queries, DML, DDL, transaction control
statements, and calls to stored procedures. The client-side and server-side SQLJ APIs are
identical, which makes it easy to partition applications.
Native compiler (Accelerator)
Java executes platform-independent bytecodes on top of a JVM, which in turn interacts with the
specific hardware platform. Any time you add levels within software, your performance is
degraded. Because Java requires going through an intermediary to interpret platform-
independent bytecodes, a degree of inefficiency exists for Java applications that does not exists
within a platform-dependent language, such as C. To address this issue, several JVM suppliers
create native compilers. Native compilers translate Java bytecodes into platform-dependent
native code, which eliminates the interpreter step and improves performance.

Oracle9i: Access the Database with Java and JDBC 6-10


Overview of Creating and Running
a Stored Procedure

Develop

Load

Deploy
Publish

Call

6-11 Copyright © Oracle Corporation, 2002. All rights reserved.

Creating and Running a Stored Procedure


The slide shows the three steps for creating and running a Java stored procedure.
Develop
First, you need to develop the stored procedure; this means writing the Java code. Your stored
procedure may query and update data; you use JDBC or SQLJ to do this. The rules that you
must follow when writing a Java class that will be deployed as a Java stored procedure are
discussed in this lesson.
Deploy
Second, you need to deploy the stored procedure to an Oracle9i database. There are two main
steps to deployment:
1. Load the stored procedure into the database.
2. Create a SQL wrapper for the stored procedure.
The SQL wrapper is also called a call spec. Other applications call the Java stored procedure
through its call spec. In this lesson, you will learn how to use the JDeveloper Deployment
Wizard to automate the deployment process.
Call
Third, you need to call the stored procedure. In this lesson, you will learn how to write JDBC
or SQLJ code that calls a stored procedure.

Oracle9i: Access the Database with Java and JDBC 6-11


Step 1: Develop the Stored Procedure

Develop

Load

Deploy
Publish

Call

6-12 Copyright © Oracle Corporation, 2002. All rights reserved.

Step 1: Develop the Stored Procedure


The following slides show how to write a Java class so that you can deploy the methods as
Java stored procedures.

Oracle9i: Access the Database with Java and JDBC 6-12


Writing a Java Class for Deployment
as Stored Procedures

• There is no constructor because the class is never


instantiated as an object.
• The server cannot materialize a GUI.
• Variables and methods are static.
• Each method checks the database connection and
sets it if necessary.
• Method declarations contain input and output
parameters.
• Output parameters are declared as arrays.
• You use the default database connection.

6-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Writing a Java Class for Deployment as Stored Procedures


When you load a Java class into the database from JDeveloper, you specify which methods
you want to deploy as Java stored procedures. Each of these methods can be called as a
separate stored procedure; the class itself is not instantiated as an object. This means the
following:
• There is no constructor.
• A server cannot provide GUIs, but it can supply the logic that drives them.
• All variables and methods are class variables and methods; that is, they are declared as
static.
• Each method that needs a database connection must check the connection and set it if
necessary. One way to do this is to declare the connection as a static class variable
initialized to null and check its value at the beginning of each method.
• Stored procedures can have input and output parameters. You specify the input and
output parameters in your method declaration. The output parameters are declared as
arrays, so the output parameters can be passed as object references, not as primitive
variables.
• Finally, stored procedures are connecting to the SQL engine from inside the database, so
they use the default connection. The syntax for connecting in this way is as follows:
connection = (new
oracle.jdbc.driver.OracleDriver()).defaultConnection();
The following slide shows an example of a Java class written for deployment as stored
procedures, using the beginOrders() method of the Orders class.

Oracle9i: Access the Database with Java and JDBC 6-13


The Database Server Default Connection

• Use the default connection for connecting within


the server.
• The resulting connection is to your existing
database session.
• If you use default connections, you do not need to:
– register the driver
– connect to the database
• You should not close the default connection.
DriverManager.getConnection
("jdbc:default:connection:");

6-14 Copyright © Oracle Corporation, 2002. All rights reserved.

The Default Connection


If you are connecting within the server, you can use the default connection. A Java stored
procedure accesses the database by using the default connection. The slide shows how to use
the default connection. To connect within the server, you must first connect to the server from
outside, so you already have a database session. The default connection takes the same user
and privileges as your existing database session. Therefore, you do not need to specify a URL,
user ID, or password for the default connection. You can also use the URL
jdbc:oracle:kprb as an alternative way to get the default connection.
The server-side thin driver that exists in Oracle9i, enables a Java stored procedure to make a
JDBC connection to another external database.
You should never close the default connection. Closing the default connection will probably
throw an exception in future releases of Oracle9i.

Oracle9i: Access the Database with Java and JDBC 6-14


The Default Connection (continued)
Connecting with the DriverManager.getConnection() method
To connect to the internal server connection from code that is running within the target server,
you can use the static DriverManager.getConnection() method with either of the
following connect strings:
DriverManager.getConnection("jdbc:oracle:kprb:");
or:
DriverManager.getConnection("jdbc:default:connection:");
Any username or password that you include in the URL string is ignored while connecting
to the server default connection.
Instructor Note
The OCI 8 driver works with Oracle 8.0.4 and later versions of Oracle8; the OCI 7 driver
works with Oracle 7.3 and later versions of Oracle7, the OCI driver works will all previous
versions of the database.

Oracle9i: Access the Database with Java and JDBC 6-15


Internal Connection to the Database

• Connecting with the getConnection() method:


DriverManager.getConnection("jdbc:oracle:kprb:");
Or
DriverManager.getConnection("jdbc:default:connection:");
• Connecting with the defaultConnection()
method:
Connection conn = null;
try {
// connect with the server-side internal driver
OracleDriver ora = new OracleDriver();
conn = ora.defaultConnection();
}
} catch (SQLException e) {...}
return conn;
….

6-16 Copyright © Oracle Corporation, 2002. All rights reserved.

Connecting with the OracleDriver Class defaultConnection() Method


The oracle.jdbc.OracleDriver class defaultConnection() method is an
Oracle extension and always returns the same connection object. Even if you invoke this
method multiple times, assigning the resulting connection object to different variable names,
just a single connection object is reused. You do not need to include a connect string in the
defaultConnection() call.
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 typically not be closed.
Session and transaction context for the server-side internal driver
The server-side driver operates within a default session and default transaction context. The
default session is the session in which the JVM was invoked. In effect, you are already
connected to the database on the server. This is different from the client side where there is no
default session: you must explicitly connect to the database.
Auto-commit mode is disabled in the server. You must manage transaction COMMIT and
ROLLBACK operations explicitly by using the appropriate methods on the connection object:
conn.commit();
or:
conn.rollback();

Oracle9i: Access the Database with Java and JDBC 6-16


Example: Orders.beginOrder()

• Written as a client-side SQLJ application:


public OrderInfo beginOrder(int customer_id,
int employee_id) throws SQLException {…}

• Written for deployment as a Java stored


procedure:
public static void beginOrder(int customer_id,
int employee_id, int[] orderIdOut,
String[] firstNameOut, String[] lastNameOut)
throws SQLException {…}

6-17 Copyright © Oracle Corporation, 2002. All rights reserved.

Example: Orders.beginOrder()
The first code fragment in the slide shows the declaration of the beginOrder() method.
beginOrder() takes a customer ID and an employee ID and creates a new record in the
ORDERS table for the transaction. The method returns an OrderInfo object containing the ID
of the new order and the first name and last name of the customer.
Rewriting beginOrder() for deployment as a stored procedure
The second code fragment shows how you would rewrite beginOrder() for deployment as
a stored procedure. The differences are as follows:
• The method is declared as static.
• The return type is void, because there is no OrderInfo data type in the database.
• The order ID, first name, and last name have become output parameters and are declared
as arrays.
This is how beginOrder() would set its output parameters:
orderidOut[0] = order_id;
firstNameOut[0] = first_name;
lastNameOut[0] = last_name;
(order_id, first_name, and last_name are the Java variables containing the values
selected from the database.)

Oracle9i: Access the Database with Java and JDBC 6-17


Step 2: Load the Stored Procedure

Develop

Load

Deploy
Publish

Call

6-18 Copyright © Oracle Corporation, 2002. All rights reserved.

Step 2: Load the Stored Procedure


The following slides show how to deploy stored procedures to an Oracle9i database. To deploy
stored procedures to an Oracle9i database, perform the following steps:
1. Load the stored procedure into the database using loadjava.
2. Create a SQL wrapper for the stored procedure, also referred to as publishing Java
methods by writing call specs.
In the following slides you will learn how to use the JDeveloper Deployment Wizard to
automate the deployment process.

Oracle9i: Access the Database with Java and JDBC 6-18


Loading Java in the Database

.java-.sqlj .class .jar


file file file

loadjava

Database

Java Java Java


Source Class Resource
Schema

Options
Java
Table
Compiler

6-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Java in the Database

To make Java files available to the Oracle JVM, you must load them into the Oracle database
as schema objects. Loadjava can invoke the JVM’s Java compiler, which compiles source
files into standard class files.
The slide shows that loadjava can set the values of options stored in a system database
table. Among other things, these options affect the processing of Java source files.
Each Java class is stored as a schema object. The name of the object is derived from the fully
qualified name (full name) of the class, which includes the names of containing packages. For
example, the full name of class Handle is: oracle.aurora.rdbms.Handle
In the name of a Java schema object, slashes replace dots, so the full name of the class above
becomes: oracle/aurora/rdbms/Handle
The Oracle RDBMS accepts Java names up to 4000 characters long. However, the names of
Java schema objects cannot be longer than 30 characters, so if a name is longer than that, the
system generates an alias (short name) for the schema object. Otherwise, the full name is used.
You can specify the full name in any context that requires it. When needed, name mapping is
handled by the RDBMS.
Java code, binaries, and resources
In the Oracle JVM environment, source, classes, and resources reside within the Oracle9i
database as Java schema objects, where a schema corresponds to a database user. There are
three types of Java objects: source, class, and resource. There are no .java, .class,
.sqlj, .properties, or .ser files on the server; instead, these files map to source, class,
and resource Java schema objects.
Oracle9i: Access the Database with Java and JDBC 6-19
Loading Java Code in the Server

• Loading already compiled files:


• loadjava -user scott/tiger Foo1.class Foo2.class
• loadjava -user scott/tiger Foo*.class
• loadjava -user scott/tiger Foo.jar
• loadjava -thin -user scott/tiger
@localhost:1521:ORCL Foo.jar

• Loading noncompiled files


• loadjava -user scott/tiger -resolve Foo.java
• loadjava -thin -user scott/tiger@localhost:1521:ORCL
-resolve Foo.java Bar.sqlj

• - resolve option compiles at loading time

6-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Loading Class Files into the Server


Consider a case where you have three class files in your application: Foo1.class
Foo2.class, and Foo3.class. The following three examples demonstrate:
• Specifying the individual class file names
• Specifying the class file names using a wildcard
• Specifying a JAR file that contains the class files
Each class is written into its own class schema object in the server.
These three examples use the default OCI driver in loading the files:
loadjava -user scott/tiger Foo1.class Foo2.class Foo3.class
or:
loadjava -user scott/tiger Foo*.class
or:
loadjava -user scott/tiger Foo.jar
Or use the following command to load with the Thin driver (specifying the –thin option and an
appropriate URL):
loadjava -thin -user scott/tiger@localhost:1521:ORCL Foo.jar
(Whether to use an OCI driver or the Thin driver to load classes depends on your
particular environment and which performs better for you.)

Oracle9i: Access the Database with Java and JDBC 6-20


Loading Class Files into the Server (continued)
Loading source files into the server
• When you specify the -resolve option on loadjava for a source file, the
following occurs:
a. The source file is loaded as a source schema object.
b. The source file is compiled.
c. Class schema objects are created for each class defined in the compiled .java
file.
d. The compiled code is stored in the class schema objects.
• If you do not specify -resolve, then the source is loaded into a source schema object
without any compilation. In this case, however, the source is implicitly compiled the first
time an attempt is made to use a class defined in the source.
For example, run loadjava as follows to load and compile Foo.java, using the default OCI
driver:
loadjava -user scott/tiger -resolve Foo.java
Or use the following command to load with the Thin driver (specifying the –thin option and
an appropriate URL):
loadjava -thin -user scott/tiger@myHost:1521:ORCL -resolve
Foo.java
Either of these will result in appropriate class schema objects being created in addition to the
source schema object.
Note: Because the server-side embedded JVM uses JDK 1.2.x, it is advisable to compile
classes under JDK 1.2.x if they will be loaded into the server. This will catch incompatibilities
during compilation, instead of at run time (for example, JDK 1.1.x artifacts such as leftover
use of the oracle.jdbc2 package).
Instructor Note
Oracle generally recommends compiling source on the client whenever possible, and loading
the .class files instead of the source files into the server.

Oracle9i: Access the Database with Java and JDBC 6-21


Step 3: Publish the Stored Procedure

Develop

Load

Deploy
Publish

Call

6-22 Copyright © Oracle Corporation, 2002. All rights reserved.

Step 3: Publishing the Stored Procedure


Create a SQL wrapper for the stored procedure, also referred to as publishing Java methods by
writing call specs.

Oracle9i: Access the Database with Java and JDBC 6-22


Publishing a Java Procedure

Make the Java method available by creating a call


spec as a:
• Stand-alone PL/SQL function or procedure
• Packaged PL/SQL function or procedure
• Member method of a SQL object type
Database

Call Java
Application Spec Class
Schema

Data

Dictionary

6-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Publishing a Java Procedure


Publishing enables the Java methods to be called as PL/SQL functions or procedures.
A call spec and the Java method it publishes must reside in the same schema (unless the Java
method has a PUBLIC synonym).
You can declare the call spec as a:
• Stand-alone (top-level) PL/SQL function or procedure
• Packaged PL/SQL function or procedure
• Member method of a SQL object type
A call spec exposes a Java method’s top-level entry point to Oracle. Therefore, you can
publish only public static methods—with one exception. You can publish instance methods as
member methods of a SQL object type.
Packaged call specs perform as well as top-level call specs. So, to ease maintenance, you
might want to place call specs in a package body. That way, you can modify them without
invalidating other schema objects. Also, you can overload them.

Oracle9i: Access the Database with Java and JDBC 6-23


Writing a Call Spec

• Use PL/SQL to define a procedure or function as a


wrapper
• Specify input/output parameters for the procedure
or function as SQL datatypes
CREATE FUNCTION row_count (tab_name VARCHAR2) RETURN
NUMBER
AS LANGUAGE JAVA
NAME ’RowCounter.rowCount(java.lang.String) return
int’;

• Specify input/output parameters of the Java class


as Java types

6-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Writing a Call Spec


Publishing Java method rowCount, which returns the number of rows in a given database
table.
import java.sql.*;
import java.io.*;
import oracle.jdbc.*;
public class RowCounter {
public static int rowCount (String tabName) throws SQLException
{

Connection conn =
DriverManager.getConnection("jdbc:default:connection:");
String sql = "SELECT COUNT(*) FROM " + tabName;
int rows = 0;
try {
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery(sql);
while (rset.next()) {rows = rset.getInt(1);}
rset.close();
stmt.close();
} catch (SQLException e)
{System.err.println(e.getMessage());}
return rows;
}

Oracle9i: Access the Database with Java and JDBC 6-24


Deploying a Java Stored Procedure
with JDeveloper

• JDeveloper helps you to deploy Java stored


procedures to the database.
• Deploying to the database uses the information
provided in the deployment profile and two
Oracle9i utilities:
– Loadjava loads the Java class containing the stored
procedures to Oracle9i
– Publish generates the PL/SQL call spec wrappers for
the loaded public static methods

6-25 Copyright © Oracle Corporation, 2002. All rights reserved.

Deploying Java Stored Procedures


Create a deployment profile for Java stored procedures, then deploy the classes and,
optionally, any public static methods in JDeveloper using the settings in the profile.
Deploying to the database uses the information provided in the Deployment Profile Wizard
and the following two Oracle9i utilities: :
• Loadjava: Loads the Java class containing the stored procedures to Oracle9i
• Publish: Generates the PL/SQL call spec wrappers for the loaded public static methods.
Use JDeveloper to write methods in Java for new stored procedures and deploy them to the
Oracle9i server. When you deploy a Java class to Oracle9i, you can select the methods that
you want to publish to PL/SQL for use as stored procedures.
Methods can be deployed together in a package or separately.

Oracle9i: Access the Database with Java and JDBC 6-25


Steps for Deployment
Steps for deploying with JDeveloper:
• Create a deployment profile for Java stored
procedures
• Deploy the classes and, optionally, any public
static methods in JDeveloper using the settings in
the profile
• Deploy in a connection context

6-26 Copyright © Oracle Corporation, 2002. All rights reserved.

Deploying Stored Procedures to Oracle9i


First use the Deployment Profile Wizard to create a complete deployment profile that
identifies all of the deployment information.
Deployment profiles are created and stored for later use in a Deployment folder within a
project. When multiple profiles are created for an object type, the profile names are
incremented (for example Profile1, Profile2, etc.).
In the project navigator and the file system, deployment profiles are saved in the Deployment
folder in the form Profile#.prf.
Additionally, deployment creates call specs that act as PL/SQL wrappers for the Java public
static methods in the classes deployed. PL/SQL applications call the Java method through its
call spec.
Starting a Deployment Profile
With a project selected in the JDeveloper Navigator, choose File > New... to open the New
Object dialog. Select Deployment Profiles in the Categories list and choose Stored Procedures
in the Items list. Click OK. Specify a location for the deployment profile or accept the
defaults. The deployment profile is named with a .deploy filename extension. Click Save then,
the Java Stored Procedures Deployment Profile Settings panel displays
In a typical development scenario, you may need to deploy your stored procedures several
times during development and testing. JDeveloper simplifies some of the activities using the
profile concept. After a profile has been created, only incremental changes to your project are
loaded into the database.

Oracle9i: Access the Database with Java and JDBC 6-26


Deployment Profile

6-27 Copyright © Oracle Corporation, 2002. All rights reserved.

Deployment Profile

Your project may consist of a number of entities such as images, HTML files, Java classes,
and so on. You need to specify which of these you are currently interested in deploying to the
server. This is specified by selecting the check box next to each file displayed in the list. Click
OK when you are done. The newly created stored procedures deployment profile icon appears
in the Navigator below the specified project.
On the Loadjava Options page, configure the loadjava options including the Privileges and
Resolver settings.
Click Profile Dependencies if the deployment profile depends on J2EE modules from another
deployment profile. JDeveloper supports deployment profile dependencies across projects in
the same workspace.
How should the selected source files be deployed?
This option lets you deploy the selected files into an archive and provides you the flexibility to
specify how the selected files from the project will be deployed. You can choose from the
available options:
• As compiled output only: Only the compiled output files (for example, the class files)
will be deployed. This is the default selection.
• As source files only: Only the source files (for example, .java files) that are selected in
the check box tree will be deployed.
• As both compiled output and source files: Both the compiled output files and source files
are deployed. This option creates the largest deployment package.

Oracle9i: Access the Database with Java and JDBC 6-27


Selecting the Methods to Publish

Select the methods that you want to publish.

6-28 Copyright © Oracle Corporation, 2002. All rights reserved.

Add Stored Procedure


This window displays the classes produced by the source files in your project and the methods
contained within each class. What method do you want to publish as a stored procedure?You
can only publish those methods with the icon beside it. Those methods with a dimmed
PL/SQL icon cannot be selected.
Settings
Click to display the Method Settings dialog box from which you can define a new PL/SQL
method.
Expand all
Click to display all the methods below each package in your project.
Why not?...
If a method on the list is dimmed, this indicates that the method cannot be published as a Java
stored procedure. Click Why not? for an explanation on why the current selection cannot be
deployed as a Java Stored Procedure.

Oracle9i: Access the Database with Java and JDBC 6-28


Publishing the Methods

• Published methods appear in the navigator


• “Preview” displays the PL/SQL statement used to
publish the procedure

6-29 Copyright © Oracle Corporation, 2002. All rights reserved.

Publishing the Methods


The preview SQL statement option displays the PL/SQL call spec wrappers for the loaded
public static methods that is used to publish the method.
Publishing enables the Java methods to be called as PL/SQL functions or procedures.

Oracle9i: Access the Database with Java and JDBC 6-29


Deploying in the Database
• Select the database to generate to
• View deployment log
• Deployment script in JDeveloper:
– Runs the loadjava utility
– Publishes Java to the SQL world

6-30 Copyright © Oracle Corporation, 2002. All rights reserved.

Deploying in the Database


Using the “Deploy to menu” option, you can select the connection that you need to use while
deploying the stored procedures. You can also add a new connection.
Internally, the script uses an Oracle9i utility called loadjava (which will perform the actual
task of storing the Java class in the database) and the CREATE PROCEDURE SQL statement
(which will make the methods available for invocation). loadjava accepts Java source files,
SQLJ source files, and Java JAR files as input.
Once the connection context is selected JDeveloper runs the loadjava utility using the options
specified in the deployment profile.
Deployment
Once deployment is finished, the following message is displayed:
*** Deployment completed ***
Instructor Note
It may be worth reminding students that this connection is for deployment only; it has nothing
to do with how the stored procedures are called or executed.

Oracle9i: Access the Database with Java and JDBC 6-30


Database Browsing
You can inspect:
• Deployed Java classes
• Deployed PL/SQL procedures and functions

Java Class

PL/SQL wrapper

6-31 Copyright © Oracle Corporation, 2002. All rights reserved.

Database Browsing
Once you have a valid connection in your workspace, you can inspect your deployed Java
classes, as well as any PL/SQL procedures and functions. The steps for doing this are as
follows:
1. Double-click the connection name in the navigator pane.
2. In the database browser, open the Database Schemas node and then open the node for the
database username that you used in your deployment connection.
3. Click the appropriate nodes to browse PL/SQL packages, PL/SQL functions, PL/SQL
procedures, or deployed Java classes in your database.
The example in the slide shows the procedures and classes that the Deployment Wizard
created in the database following the steps shown in the preceding slide.
Instructor Note
You can achieve rudimentary debugging by browsing the database. If a Java class has not been
deployed successfully, the methods will not work as expected. You can avoid surprises by first
browsing the database.

Oracle9i: Access the Database with Java and JDBC 6-31


How to Delete a Java Stored Procedure

1. Delete the Java classes:


– From the command line
% dropjava -u scott/tiger myPackage3.GenericDrop

– From SQL*Plus
SQL> drop java class " myPackage3.GenericDrop ";

2. Delete the SQL wrapper (from SQL*Plus only).


SQL> drop procedure DROPIT;

6-32 Copyright © Oracle Corporation, 2002. All rights reserved.

Deleting a Java Stored Procedure


You cannot delete a Java stored procedure from JDeveloper. The slide shows how to delete the
Java stored procedure that was loaded in the preceding slides, assuming that the Rentals
class is in the Java package demo07.
The syntax of the dropjava command is:
% dropjava -u username/password java_package.java_class
The equivalent command in SQL*Plus is (note the quotation marks and respect the case for the
Java class name):
SQL> drop java class "java_package.java_class";
The SQL*Plus command to delete the SQL wrapper procedures is:
SQL> drop object_type object_name;
The object type can be a package, a function, or a procedure.
Note: The JDeveloper Deployment Wizard may have loaded additional Java classes on which
your stored procedures depend. Use the JDeveloper database browser to see what classes you
need to delete.
Note that if class was loaded with loadjava, it should be dropped with dropjava, not
SQL> DROP JAVA CLASS statement because the digest table will is not synchronized
when you use the SQL command.
As a general guideline, use the same way to drop Java classes as the one you used to load it.

Oracle9i: Access the Database with Java and JDBC 6-32


Step 4: Call the Stored Procedure

Develop

Load

Deploy
Publish

Call

6-33 Copyright © Oracle Corporation, 2002. All rights reserved.

Step 4: Call the Stored Procedure


The following slides show the different ways to call a stored procedure.

Oracle9i: Access the Database with Java and JDBC 6-33


Calling a Stored Procedure
Using JDBC(1)

Creating the CallableStatement object:


1. Declare the CallableStatement object.
2. Initialize the CallableStatement object.
3. Register the object’s output parameters.

private CallableStatement beginOrderStmt;



beginOrderStmt = connection.prepareCall(
"{call OE.BEGINORDER(?,?,?,?,?)}");

beginOrderStmt.registerOutParameter(3,Types.INTEGER);
beginOrderStmt.registerOutParameter(4,Types.VARCHAR);
beginOrderStmt.registerOutParameter(5,Types.VARCHAR);

6-34 Copyright © Oracle Corporation, 2002. All rights reserved.

Creating the CallableStatement Object


The slide shows how to create the CallableStatement object that you use to call the
OE.BEGINORDER procedure. The code could be in a file called OrderClient.java. To
create the CallableStatement object:
1. Declare the CallableStatement.
The example in the slide declares a CallableStatement object named
beginOrderStmt. You would probably declare the CallableStatement as a
private instance variable.
2. Initialize the CallableStatement object.
The slide shows how to initialize beginOrderStmt using prepareCall(). It will
probably help you to understand the example if you refer to the declaration of
Oe.beginOrder(), which was created in the deployment stage.
public static void beginOrder(int customer_id, int
sales_rep_id, int[] orderId, String[] firstName, String[]
lastName)
beginOrder() has five parameters. In the example in the slide, beginOrderStmt
is initialized to call OE.BEGINORDER with five parameters (hence the five ? characters
in the statement).

Oracle9i: Access the Database with Java and JDBC 6-34


Creating the CallableStatement Object (continued)
3. Register the object’s output parameters.
Parameters 3, 4, and 5 of beginOrderStmt are registered as output parameters. This
corresponds with parameters 3, 4, and 5 of beginOrder(), which are declared as
arrays to allow them to work as output parameters. The third parameter in
beginOrderStmt is INTEGER, which maps to int[] in beginOrder().
Similarly, the fourth and fifth parameters in beginOrderStmt are VARCHAR, which
maps to String[] in beginOrder().
Invoking a Java stored procedure using JDBC
Java stored procedures invoked from JDBC must be encapsulated in CallableStatement
objects. To invoke a Java stored procedure using JDBC:
• Create a callable statement object.
• Declare a callable statement object.
For example: private CallableStatement checkIn; Initialize the callable statement object by
calling prepareCall on the connection with a SQL CALL statement for the stored procedure.
For example:
checkIn = connection.prepareCall( "{call NPL.CHECKIN(?, ?, 
?)}");
Note that the number of parameters in the stored procedure is represented by the number
placeholders in the SQL call.
Register the callable statement object’s output parameters.
Call registerOutParameter for each output parameter, identifying it by position, and declaring
its type.
For example, if the second parameter is an SQL INTEGER (which maps to a Java int), and the
third is a SQL VARCHAR ( which maps to a Java String), then:
newCustomer.registerOutParameter(2, Types.INTEGER); 
newCustomer.registerOutParameter(3, Types.VARCHAR);
Execute the callable statement object. Provide the callable statement object’s input parameters
by calling a set method, identifying the parameter by position, and assigning it a value.
For example, if the first parameter is an int input parameter: checkIn.setInt(1, 
orderID);
Execute the callable statement object. For example: checkIn.execute();  
Extract the callable statement object's output parameters.
Call a get method for each output parameter, identifying the parameter by position. The get
methods return values of corresponding Java types.
For example: int daysLate = checkIn.getInt(2); String name = 
checkIn.getString(3);

Oracle9i: Access the Database with Java and JDBC 6-35


Calling a Stored Procedure
Using JDBC(2)

To execute the CallableStatement object:


1. Set the input parameters.
2. Execute the statement.
3. Get the output parameters.

beginOrderStmt.setInt(1, customerId);
beginOrderStmt.setInt(2, salesRepId);

beginOrderStmt.execute();

int orderId = beginOrderStmt.getInt(3);


String custFirstName = beginOrderStmt.getString(4);
String custLastName = beginOrderStmt.getString(5);

6-36 Copyright © Oracle Corporation, 2002. All rights reserved.

Executing the CallableStatement Object


The slide shows how to use the CallableStatement object to call the stored procedure
and get its output parameters.
1. Set the input parameters.
The first and second parameters of beginOrderStmt are both passed as input
parameters to the stored procedure. They are both int values, so you use setInt() to
set their values.
2. Execute the statement.
Now that you have created the CALL statement for beginOrderStmt, registered its
output parameters, and set its input parameters, you can call the stored procedure with a
call to beginOrderStmt.execute().
3. Get the output parameters.
After the beginOrderStmt has been executed, its third, fourth, and fifth parameters
contain the output parameters of the stored procedure. The final step is to call the
appropriate getXXX() methods to get these values from beginOrderStmt.

Oracle9i: Access the Database with Java and JDBC 6-36


Calling a Stored Procedure
Using SQLJ

• Use the #sql{call …} syntax.


• Pass parameters as :in, :out, or :inout.
• You do not need to set up a CallableStatement
or other special object.
#sql {
call OE.BEGINORDER(:in customerId,
:in employeeId, :out orderId,
:out custFirstName, :out custLastName)
};

6-37 Copyright © Oracle Corporation, 2002. All rights reserved.

Using SQLJ for Procedure Calls


Calling a stored procedure from SQLJ is simpler than calling a stored procedure from JDBC,
because there is no CallableStatement object to deal with. The slide shows how to use
the #sql {call …} syntax to call the OE.BEGINORDER procedure.
There is no special procedure for setting the input parameters. In the example, customerId
and employeeId are Java variables. Similarly, you do not register output parameters, and
there is no special procedure for assigning them to Java variables after calling the stored
procedure. In the example, orderId, custFirstName, and custLastName are Java
variables and contain the values of the output parameters after the stored procedure has been
called.

Oracle9i: Access the Database with Java and JDBC 6-37


Calling a Stored Function
Using SQLJ

• Use the #sql result = {VALUES(func


(<param>))} syntax.
• Pass parameters as :in, :out, or :inout.
• You do not need to set up a CallableStatement
or other special object.

FUNCTION TAX (v_price NUMBER) RETURN NUMBER;

double taxAmount = ...


double price = ...
#sql taxAmount = { VALUES (tax (:price))};

6-38 Copyright © Oracle Corporation, 2002. All rights reserved.

Using SQLJ for Function Calls


Stored function calls use the keyword VALUES followed by the function call.
In standard SQLJ, the function call must be enclosed in parentheses, as shown in the example
on the slide.
In Oracle SQLJ, the parentheses are optional.
An alternative way to specify a function call is to use the syntax of a SQL SELECT statement
that references the function. Use the following syntax:
#sql { SELECT TAX(:price) INTO :taxAmount FROM DUAL};
Invoking a Java Stored Procedure using SQLJ Declare and initialize input and in-out variables.
For example, if the first parameter is an int input parameter: int bookID =
scanID();
Declare output variables. For example:
int daysLate;
String title;
Invoke the stored procedure in a SQLJ statement. In the statement identify the parameters by
name, and designate them as :in, :out, or :inout. For example:
#sql { call NPL.CHECKIN (:in bookID, :out daysLate, :out
title)}
Return values will be assigned to output and inout variables.

Oracle9i: Access the Database with Java and JDBC 6-38


Calling Java from SQL*Plus

• You can execute the CALL statement interactively


to invoke a Java stored procedure:
CALL [schema_name.][{package_name |
object_type_name}][@dblink_name]
{ procedure_name ([param[, param]...])
| function_name ([param[, param]...])
INTO :host_variable};

SQL> VARIABLE current_balance NUMBER;


SQL> CALL balance() INTO :current_balance;
SQL> Call completed
SQL> PRINT current_balance

6-39 Copyright © Oracle Corporation, 2002. All rights reserved.

Redirecting Output
On the server, the default output device is a trace file, not the user screen. As a result,
System.out and System.err print to the current trace files. To redirect output to the SQL*Plus
text buffer, call the procedure set_output() in package DBMS_JAVA, as follows:
SQL> SET SERVEROUTPUT ON
SQL> CALL dbms_java.set_output(2000);
The minimum (and default) buffer size is 2,000 bytes; the maximum size is 1,000,000
bytes. In the following example, the buffer size is increased to 5,000 bytes:
SQL> SET SERVEROUTPUT ON SIZE 5000
SQL> CALL dbms_java.set_output(5000);
Output is printed when the stored procedure exits.
For more information about SQL*Plus, see the SQL*Plus User’s Guide and Reference.

Oracle9i: Access the Database with Java and JDBC 6-39


Calling Java from a Database Trigger

• Identifies the code to be executed when the trigger


fires
• Can be a call to a Java stored procedure in an
accessible schema (using the CALL statement)
• Arguments may reference correlation names for
columns in the affected rows:
– OLD for the value before update
– NEW for the value after insert or update

CREATE [OR REPLACE] TRIGGER ...


CALL procedure_name [(arg1, arg2, ...)];

6-40 Copyright © Oracle Corporation, 2002. All rights reserved.

Trigger Body
Since Oracle8i (release 8.1.5 and later), you can define a trigger body in any of three ways:
• As a Java stored procedure: The trigger definition contains a call to the stored procedure,
along with any arguments that the trigger needs to pass. You must have already created
this procedure in your schema or in another schema for which you have execute
permission.
• As a PL/SQL stored procedure: The trigger definition contains a call to the stored
procedure, along with any arguments that the trigger needs to pass. This procedure needs
to have been precreated in your schema or in another schema for which you have execute
permission.
• As an anonymous PL/SQL block: The trigger body of legacy triggers (created in earlier
versions of the database) are defined in the trigger definition itself, not as a separate
subprogram.
For details on this type of trigger body, see the PL/SQL User’s Guide and Reference.
Using the CALL Statement
You use a CALL statement to execute a Java stored procedure (or PL/SQL stored procedure)
and optionally pass arguments to it. Use CALL within the CREATE TRIGGER statement to
use a stored procedure as the trigger body.
The arguments that you specify in parentheses can be:
• Literal values
• SQL expressions (but not including bind variables)
• Column references, qualified by correlation names

Oracle9i: Access the Database with Java and JDBC 6-40


How to Develop a Trigger in Java

1. Write and load the Java class.


public class AutoAdjust {
public static void
addRaise(Double s, Double m,
Double n, Double[] after) {...}}...

2. Publish the class.


CREATE PROCEDURE adjust_sals
(oldsal NUMBER, modif NUMBER, newsal NUMBER,
modified_new out NUMBER)...
AS LANGUAGE JAVA
NAME ’AutoAdjust.addRaise(java.lang.Double, ...)

6-41 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Develop a Trigger in Java


1. Write and load the Java class.
In this example, the AutoAdjust class is written to accept the old salary (s) and new
salary (n), calculate the difference, and then multiply it by the adjustment (m). An
adjusted new salary is then calculated for output (which will be written back to the
NEW.sal column in the trigger).
Develop and load the class through Oracle JDeveloper, as appropriate.
2. Publish the class.
Create the stored procedure with parameters that pass and return the corresponding
values.

Oracle9i: Access the Database with Java and JDBC 6-41


Developing a Trigger in Java

3. Create the trigger with the stored procedure as its


body.
CREATE OR REPLACE TRIGGER adjust_salaries
BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW
CALL adjust_sals(:old.sal,1.6,:new.sal,:new.sal);

3000 3010 3016

UPDATE EMP
SET sal=3010 ...

SCOTT 3016

6-42 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Develop a Trigger in Java (continued)


3. Create the trigger with the stored procedure as its body.
You can create the trigger at the command line in SQL*Plus. Your Oracle user needs the
CREATE TRIGGER privilege to use this command.
Correlation names
Correlation names are prefixes to column references. Use these names to qualify whether the
reference applies to the existing column value of the row being processed by the trigger or the
value being written by the triggering event:
• OLD: References the value of the column before the triggering DML operation
• NEW: References the value being assigned to the column by the triggering DML
operation (it is possible for the trigger body to redefine this value before the DML
operation occurs)
The example on the slide shows a trigger, check_sal, that checks salary changes (by
comparing the old and new values of the salary) and records the details in an audit table if a
change is outside the normal increase limit for the job type. In an argument list, OLD and NEW
are prefixed with colons.
Note: As in other CREATE commands, you use the OR REPLACE option to create the object
in your schema even if an object with that name exists already, by overwriting any previous
definition.
The adjust_salaries trigger calls the adjust_sals stored procedure, passing the old
value of sal, the adjustment factor (1.6 in this example), and the new value of sal supplied
by the triggering DML statement. The final argument is also :new.sal, allowing the
adjusted salary to write back and replace the value defined by the triggering DML command.

Oracle9i: Access the Database with Java and JDBC 6-42


Calling Java from SQL DML

Published Java methods as functions are usable in


DML statements:
CREATE OR REPLACE FUNCTION format_emp (ename VARCHAR2,
job VARCHAR2) RETURN VARCHAR2
AS LANGUAGE JAVA NAME ’Formatter.formatEmp
(java.lang.String, java.lang.String)
return java.lang.String’;

SQL> SELECT format_emp(ename, job) AS "Employees" FROM emp


2 WHERE job NOT IN ('MANAGER','PRESIDENT') ORDER BY ename;

6-43 Copyright © Oracle Corporation, 2002. All rights reserved.

Calling Java from SQL DML


If you publish Java methods as functions, you can call them from SQL SELECT, INSERT,
UPDATE, DELETE, CALL, EXPLAIN PLAN, LOCK TABLE, and MERGE statements. For
example, assume that the executable for the following Java class is stored in the Oracle
database:
public class Formatter {
public static String formatEmp (String empName, String 
jobTitle) {
empName = empName.substring(0,1).toUpperCase() +
empName.substring(1).toLowerCase();
jobTitle = jobTitle.toLowerCase();
if (jobTitle.equals("analyst"))
return (new String(empName + " is an exempt analyst"));
else
return (new String(empName + " is a non­exempt " + jobTitle));
}

The class Formatter has one method named formatEmp, which returns a formatted string
containing a staffer’s name and job status. First, you write the call spec for this method, then,
you call the function in your DML statement.
Employees
--------------------------------------------
Adams is a non-exempt clerk
Allen is a non-exempt salesman

Oracle9i: Access the Database with Java and JDBC 6-43


Calling Java from PL/SQL

• You can call Java stored procedures from any


PL/SQL block, subprogram or package
CREATE OR REPLACE PROCEDURE raise_salary (empno
NUMBER, pct NUMBER)
AS LANGUAGE JAVA
NAME ’Adjuster.raiseSalary(int, float)’;

DECLARE
emp_id NUMBER;
percent NUMBER;
BEGIN
-- get values for emp_id and percent
raise_salary(emp_id, percent);
...
END;

6-44 Copyright © Oracle Corporation, 2002. All rights reserved.

Calling Java from PL/SQL


For example, assume that the executable for the following Java class is stored in the Oracle
database:
import java.sql.*;
import oracle.jdbc.*;
public class Adjuster {
public static void raiseSalary (int empNo, float percent)
throws SQLException {
Connection conn =
DriverManager.getConnection("jdbc:default:connection:");
String sql = "UPDATE emp SET sal = sal * ? WHERE empno = ?";
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setFloat(1, (1 + percent / 100));
pstmt.setInt(2, empNo);
pstmt.executeUpdate();
pstmt.close();
} catch (SQLException e) {System.err.println(e.getMessage());}
}

The class Adjuster has one method, which raises the salary of an employee by a given
percentage. Because raiseSalary is a void method, you publish it as a procedure.

Oracle9i: Access the Database with Java and JDBC 6-44


Access Control

• Access control refers to the rights with which a


stored procedure is executed.
• By default, Java stored procedures are executed
with the privileges of the invoker.
• Invoker-rights procedures are not bound to a
particular schema.

6-45 Copyright © Oracle Corporation, 2002. All rights reserved.

Access Control
Suppose that you deploy your procedures using acmeConnection, which has the username
acme. For user SCOTT to run the Java stored procedure, he must be given execute privileges
on the published PL/SQL procedure. After SCOTT runs the Java stored procedure, unqualified
references to schema objects (such as database tables) in the Java stored procedures are
resolved in the schema of the invoker, which in this case is SCOTT. Java stored procedures are
therefore said to execute with invoker rights.
For an invoker-rights procedure, external references depend on the kind of statement they
appear in. The following names are resolved in the schema associated with the invoker:
• Names in DML statements, such as tables, views, and sequences
• Names in cursors
• Names in dynamic SQL statements and DBMS_SQL statements
The names of program units that the invoker-rights procedure calls are resolved in the schema
containing the procedure.
It is most important to know that roles are not active in definer's rights procedures, and that
they are active in invoker’s rights procedures
Instructor Note
loadjava has an option to override the default behavior mentioned here. In JDeveloper, you
cannot interact with loadjava explicitly.

Oracle9i: Access the Database with Java and JDBC 6-45


Summary

• There are several performance benefits to


implement Java Stored Procedures in the database
• The steps for Java stored procedures are develop,
load, publish and call
• Java stored procedures use an internal connection
• Use JDeveloper to load and publish a stored
procedure
• Publishing a Java Stored procedure creates a
PL/SQL wrapper
• Create a deployment profile to deploy Java Stored
procedure using JDeveloper
• Deployed Java stored procedures can be called
from various entry points

6-46 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 6-46


Practice 6 Overview

This practice covers:


• Creating a Java Stored procedure
• Publishing the Java Stored procedure
• Creating a trigger
• Calling a Java Stored Procedure from a trigger

6-47 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 6-47


Practice 6
Goal
The goal of this practice is to create a Java Stored procedure in the database and to call it
from a database trigger.
Your assignment
You create a Java stored procedure that logs into a log table the updates that are made on
the PROMOTION_ID column of the ORDERS table when the ORDER_MODE is online;
You create a log table in order to record these changes.
You create a trigger on the Orders table that fires when an update on the
PROMOTION_ID column is made for orders that are ‘online’ orders. This trigger calls
the Java stored procedure that keeps track of the changes.
Setting up the Environment
• Close any previously opened workspace in JDeveloper
• Open the workspace named Lesson6.
• Create a new project named StoredProc.
• Make sure that the required libraries are included in the project.
• Create a new Connection
– In the Database node of the system navigator, right-click and select the New
connection option
– Fill in the dialogs specifying your usual host name, username, and password.
– Test the connection to make sure it works
• From File | New menu option, select Objects and choose SQL File.
• Use this SQL file to type in the SQL statement in order to create a table name.
order_audit with five columns allowing you to store the order_id, the order_total,
the new promotion_id, the date at which the change is made and the use that made
the change.
CREATE TABLE order_audit(
order_id    number(12),
order_total number(8,2),

new_promotion_id number(6),
update_date date,
username varchar2(15));
Creating the Java stored procedure

• Create a new class and name it DbOrder.


• Make sure that only Public is selected in the Optional attributes properties.
• Import the necessary packages
import java.sql.*;
import java.io.*;
import oracle.jdbc.*;
• Create a public static method.
– Name it logPromotion.
– Define three input parameters for the orderid, the ordertotal and promotionid
values
public static void logPromotion (int orderID, 
float oldOrderTotal, int newPromotionId)
• Add a throws SQLException statement
throws SQLException {
• Create a default internal connection
Oracle9i: Access the Database with Java and JDBC 6-48
Practice 6 (continued)
• Create a string variable that contains an Insert statement in the order_audit table and
takes three parameters plus today’s date and the user name
String sql = "INSERT INTO order_audit VALUES (?, ?, ?,
sysdate,user)";
• Define a Prepared statement object with the sql statement variable
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
• Pass each input parameter to the prepared statement object using the setXXX
methods and the position of each parameter in the table
pstmt.setInt(1, orderID);
pstmt.setFloat(2, oldOrderTotal);
pstmt.setInt(3, newPromotionId);
• Execute the statement using executeUpdate() method
pstmt.executeUpdate();
• Close the statement
pstmt.close();
• End the code
} catch (SQLException e)
{System.err.println(e.getMessage());}
Deploying the Java stored procedure
• Create a new deployment profile for Stored Procedures.
• Accept defaults values and click OK.
• Add a stored procedure to your deployment profile
– Right-click the Deployment profile
– Select the logPromotion method in the DbOrder Class
– Click OK
– A new entry appears in the Deployment profile with the method name
• Display the PL/SQL generated for publishing
– Right-click the method name
– Select the Edit Method Signature
– Select the Preview SQL Statement
• Deploy the Deployment profile in the database
– Right-click the Deployment profile and deploy using the connection created
previously

Oracle9i: Access the Database with Java and JDBC 6-49


Practice 6 (continued)
Creating the database trigger
• From File | New menu option, select Objects and choose SQL File.
• Use this SQL file to type in the SQL statement in order to create a trigger that
triggers for each row after an update of the promotion_id column is done for an
Order that has the ‘online’ order_mode value
CREATE OR REPLACE TRIGGER promo_trig
AFTER UPDATE OF promotion_id ON orders
FOR EACH ROW
WHEN (old.order_mode='online')
CALL logPromotion(:old.order_id, :old.order_total,
:new.promotion_id)
/
• Right-click the file to run it using SQL*Plus.
Note: At this point you are able to test your Java stored procedure.
Testing the Java stored procedure
• Open a SQL*Plus window for your connection.
• Query the ORDERS table to find an ORDER_ID having the online property for the
ORDER_MODE column
SELECT order_id FROM orders WHERE order_mode=‘online’
• Update the order table and set a value for the promotion_id column for one of
the online orders (order_id 2390 can do it)
UPDATE orders SET promotion_id=1 WHERE order_id=2390;
• Query the Orders table for the given order_id value and verify that
PROMOTION_ID is updated
SELECT * FROM orders WHERE order_id =2390;
• Query the order_audit table to verify that you Java stored procedure executed
and populated the correct values
SELECT * FROM order_audit;

Oracle9i: Access the Database with Java and JDBC 6-50


Embedding SQL Statements
in Java Code with SQLJ

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

70 minutes Lecture and guided practice


60 minutes Practice
130 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Connect to a database using SQLJ
• Execute a database query using SQLJ
• Use iterators to extract columns by name and by
position
• Add a .sqlj file to a JDeveloper project and set its
properties
• Precompile SQLJ code in JDeveloper

7-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
For PL/SQL or PRO* programmers, SQLJ provides a simpler way to query a database in Java
than JDBC, because SQLJ uses SQL queries embedded in Java code. This lesson teaches you
how to write database queries in SQLJ.
Oracle9i: Access the Database with Java and JDBC 7-2
SQLJ

• SQLJ is a standard for embedding static SQL


statements in Java code.
• The Oracle SQLJ translator translates SQLJ files to
Java code.
• Oracle SQLJ provides extension to support
dynamic SQL.
• You can create and deploy SQLJ files in
JDeveloper projects.

SQL

7-3 Copyright © Oracle Corporation, 2002. All rights reserved.

About SQLJ
SQLJ provides a way to embed static SQL statements and constructs in Java programs.
SQLJ statements are embedded directly in a Java program. When the program is compiled,
the SQLJ translator first translates the SQLJ statements into JDBC calls.
You can include SQLJ files in a JDeveloper project. JDeveloper automatically calls the SQLJ
translator when you build a project that contains SQLJ source files. JDeveloper comes with
all of the packages required to use SQLJ.
You can write a program that contains a mixture of JDBC calls and SQLJ statements.
Naming SQLJ files
SQLJ source files have the suffix .sqlj—for example, Customers.sqlj.
The SQLJ packages
The SQLJ classes and interfaces are in three packages: sqlj.runtime,
sqlj.runtime.ref, and oracle.sqlj.runtime.
Oracle9i: Access the Database with Java and JDBC 7-3
Advantages of SQLJ Compared to JDBC

• SQLJ is less intricate than JDBC.


• The SQLJ translator can check for:
– SQL syntax errors
– Incorrect assumption of table structures
– Java-SQL type mismatch

SQL

7-4 Copyright © Oracle Corporation, 2002. All rights reserved.

Advantages of SQLJ Compared to JDBC


• SQLJ is less complicated than JDBC, because you write SQL statements to interact with
the database. SQLJ provides more concise and less error-prone static SQL constructs than
JDBC.
• SQLJ provides stronger typing than JDBC code, because the SQL code can be checked at
compile time rather than at run time. SQLJ offers syntax and semantic checking against
the server schema at compile time. A server connection is used to check your embedded
SQL code to verify that it is syntactically and semantically correct.
Oracle9i: Access the Database with Java and JDBC 7-4
The SQLJ Translator

• Checks SQL
– Online checking (against the database)
– Offline checking (against the syntax)
• Generates Java code with JDBC calls
Java code with Java code
embedded SQL with JDBC calls
SQLJ Java Java class
Translator compiler

xx.sqlj xx.java xx.class


Oracle

7-5 Copyright © Oracle Corporation, 2002. All rights reserved.

How SQLJ Statements Are Compiled


The compilation process works as follows:
1. The translator invokes the semantics-checker, which checks the syntax and semantics of
embedded SQL statements. It also can optionally check the use of database elements in
your code against an appropriate database schema.
The developer can use online or offline checking, according to SQLJ option settings. If
online checking is performed, then SQLJ will connect to a specified database schema to
verify that the database supports all the database tables, stored procedures, and SQL
syntax that the application uses, and that the host variable types in the SQLJ application
are compatible with data types of corresponding database columns.
2. The SQLJ translator translates the embedded SQL statements into Java code containing
JDBC calls.
3. The Java compiler compiles your Java code into bytecode format.
Note: In addition to the .java file, the SQLJ translator can create a file called a profile,
with the suffix .ser. This file contains resource information that is needed by the translated
SQLJ .class file at run time. The profile contains vendor-specific database code.
Oracle SQLJ, however, generates Oracle JDBC code directly, instead of generating standard
code that calls the SQLJ runtime for SQL operations (which in turn contains calls to Oracle
JDBC). Oracle-specific code generation offers many advantages over standard SQLJ code
generation like: applications run more efficiently, are smaller in size and translation is faster,
because there is no profile customization step.
Use Sqlj –codegen=iso <filename>.sqlj to create the .ser file
Oracle9i: Access the Database with Java and JDBC 7-5
Preparing SQLJ Use

1. Setting the PATH


2. Setting the CLASSPATH
3. Importing JDBC and SQLJ packages

Standard
Packages
Copyright © Oracle Corporation, 2002. All rights reserved.
Oracle
Packages
{
{

7-6

Requirements for Using Oracle SQLJ


The following are required to use Oracle SQLJ:
• A JDBC driver implementing the standard java.sql JDBC interfaces from Sun
Microsystems.
• Oracle SQLJ works with any JDBC driver that complies with standards.
• A database system that is accessible using your JDBC driver.
• Class files for the SQLJ translator and SQLJ profile customizer Translator-related
classes are available in the file: [Oracle Home]/sqlj/lib/translator.zip
(or .jar)
• Class files for the SQLJ run time - Several SQLJ runtime versions are available. You
must select a run-time version that is compatible with your Java environment and JDBC
driver (these are all in [Oracle Home]/sqlj/lib).
– runtime12.zip (or .jar)—for use with Oracle9i JDBC drivers under SDK
1.2.x or higher, providing full SQLJ ISO functionality
– runtime12ee.zip (or .jar)—for use with Oracle9i JDBC drivers in a J2EE
environment (including JDK 1.2.x or higher), providing full SQLJ ISO
functionality
– runtime11.zip (or .jar)—for use with Oracle9i JDBC drivers under JDK
1.1.x
– runtime.zip (or .jar)—for use with older Oracle JDBC drivers and any
(earlier) JDK environment (intended for Oracle JDBC release 8.1.7 and prior)
– runtime-nonoracle.zip (or .jar)—for use with non-Oracle JDBC drivers
and any JDK environment
Oracle9i: Access the Database with Java and JDBC 7-6
Requirements for Using Oracle SQLJ (continued)
Special Notes Regarding the SQLJ Libraries
Be aware of the following:
For SQLJ ISO-compliant support for JDBC 2.0 types such as java.sql.Ref, Clob, Blob, Struct,
and SQLData, use the runtime12 or runtime12ee library with SDK1.2 or J2EE and an
Oracle9i (or 8.1.7) JDBC driver.
For Oracle-specific code generation, use the runtime11, runtime12, or runtime12ee library.
Certain features, such as Oracle-specific code generation, are not supported by the generic
runtime ZIP/JAR file, which is intended mainly for backwards compatibility, or by the
runtime-nonoracle ZIP/JAR file.
The runtime-nonoracle library provides the highest portability across different Java and
JDBC environments, but does not support Oracle-specific functionality.
The Runtime library provides the highest flexibility across different Java and Oracle JDBC
environments, but does not support all SQLJ ISO functionality.
If you will be running only SQLJ applications that have already been translated, compiled,
and customized, you will not need the translator ZIP/JAR file.
PATH and CLASSPATH for Oracle JDBC
If you are using one of the Oracle JDBC drivers, you will need the Oracle JDBC classes
ZIP/JAR file that is appropriate for your environment.
JDK 1.1.x-compatible classes are in classes111.zip or .jar; JDK 1.2.x (or higher)
compatible classes are in classes12.zip or .jar. Presuming you use a Sun
Microsystems JDK, make sure the appropriate ZIP/JAR filename is in your CLASSPATH
setting.
PATH and CLASSPATH for Oracle SQLJ
To be able to run the sqlj script (which invokes the SQLJ translator) without having to
fully specify its path, verify that your PATH environment variable has been updated to
include the following:
[Oracle Home]/bin
CLASSPATH setting updates your CLASSPATH environment variable to include the current
directory as well as the following (either .zip or .jar):
[Oracle Home]/sqlj/lib/translator.zip
Oracle Home directory.
In addition, you must include one of the following run-time libraries in your classpath (either
.zip or .jar):
[Oracle Home]/sqlj/lib/runtime12.zip
[Oracle Home]/sqlj/lib/runtime12ee.zip
[Oracle Home]/sqlj/lib/runtime11.zip
[Oracle Home]/sqlj/lib/runtime.zip
[Oracle Home]/sqlj/lib/runtime-nonoracle.zip
For more information, refer to Oracle9i SQLJ Developer’s Guide and Reference
Instructor Note
If this seems confusing to students, remind them that SQLJ is translated to JDBC statements.

Oracle9i: Access the Database with Java and JDBC 7-7


Running SQLJ in Command Line

You can run SQLJ in command line


• SQLJ has various options
• Use the version option to check your environment

7-8 Copyright © Oracle Corporation, 2002. All rights reserved.

Running SQLJ in Command Line


Use the sqlj –version-long command to verify your running environment.
Following is the list of some of the options that are usable with the sqlj command:
F:\>sqlj
-d=<directory> root directory for generated binary files

-encoding=<encoding> Java encoding for source files


-user=<user>/<password> enable online checking
-url=<url> specify URL for online checking
-status print status during translation
-compile=false do not compile generated Java files
-linemap instrument compiled class files from sqlj source
-profile=false do not customize generated *.ser profile files
-ser2class convert generated *.ser files to *.class files

Note: place -<key>=<value> in sqlj.properties as sqlj.<key>=<value>


Syntax example for the compilation of a file named Test.sqlj:
sqlj -user=scott/tiger -url=jdbc:oracle:oci:@orcl Test.sqlj
Oracle9i: Access the Database with Java and JDBC 7-8
SQL Statement with SQLJ

• Starts with #sql


• Is enclosed in braces {…}
• Prefixes Java variables with a colon (:)
• Ends with a semicolon (;)
int copyId = ...

#sql {
UPDATE orders
SET order_status = 2
WHERE order_id = :orderId
};

7-9 Copyright © Oracle Corporation, 2002. All rights reserved.

Format of SQLJ Statements


A SQLJ statement starts with the #sql token. The embedded SQL statement must be
enclosed in braces ({…}), and the statement must end with a semicolon (;). You can use Java
variables in the SQL statement, as long as you prefix each variable name with a colon (:).
The example in the slide updates the ORDER_ID column with the value of the copyId Java
variable.
Oracle9i: Access the Database with Java and JDBC 7-9
Selecting a Single Row with SQLJ

• Declare a Java variable for each column.


int empNo = ...
String ename, job;
int year;

• Use SELECT … INTO ….


#sql {
SELECT empno, ename, job,
TO_NUMBER(TO_CHAR (hiredate,’yyyy’))
INTO :empNo, :ename, :job, :year
FROM emp
WHERE deptno = :deptNo
};

7-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Selecting a Single Row


You can assign values to multiple Java variables in a single SQLJ SELECT statement. The
example in the slide selects from a single row of EMP and assigns the value of each column to
a Java variable. The value of the ENAME column is assigned to the Java variable ename, the
value of the JOB column to the variable job, and so on.
Later in this lesson, you will learn how to write a SELECT statement that returns multiple
rows.
Mapping database types to Java types
The rules for mapping database types to Java types are the same for SQLJ as for JDBC:
• You can map any character or numeric column to a Java String variable; this is often
the simplest choice.
• If you want to perform some calculations on the data, use Integer or BigDecimal
for numeric columns.
• If you are mapping a SQL DATE column, you must map it to a java.sql.Date Java
variable.
• SQLJ always maps SQL NULL to Java null
• The JDBC section of the Java tutorial contains the full matrix of data type mappings. The
Java Tutorial is available online at
http://java.sun.com/docs/books/tutorial/index.html.
Oracle9i: Access the Database with Java and JDBC 7-10
Overview of Querying a Database
with SQLJ

Register the driver and connect.

Set the default connection context.

Execute the query and process the results.

Close the connection.

7-11 Copyright © Oracle Corporation, 2002. All rights reserved.

Steps to Perform a Database Query with SQLJ


The slide shows the main steps that you use to perform a database query with SQLJ. The
following slides describe each step in detail.
Oracle9i: Access the Database with Java and JDBC 7-11
Register the Driver and Connect Using
Oracle.connect

• Using oracle.sqlj.runtime.Oracle creates a


connection with auto-commit to false
• Specifying connection properties in the code
Oracle.connect(URL,userid,password);

• Getting connection properties from a file


Oracle.connect(MyProg.class,"connect.properties")

• Example of a connection properties file


sqlj.url=jdbc:oracle:thin:@myHost:1521:ORCL
sqlj.user=scott
sqlj.password=tiger

7-12 Copyright © Oracle Corporation, 2002. All rights reserved.

Register the Driver and Connect


You can use the connect() method of the oracle.sqlj.runtime.Oracle class
to accomplish this. This method has several signatures, including ones that allow you to
specify the username, the password, and the URL, either directly or using a properties file. In
the following example, the properties file connect.properties is used.
Oracle.connect( MyProg.class, "connect.properties");
Assume MyProg is the name of your class. If you use connect.properties, you must
edit it appropriately and package it with your application. In this example, you must also
import the oracle.sqlj.runtime.Oracle class.
Alternatively, you can specify the username, the password, and the URL directly:
Oracle.connect("jdbc:oracle:thin:@myHost:1521:orcl", "scott",
"tiger");
Either of these examples creates a special static instance of the DefaultContext
class and installs it as your default connection. It is not necessary to do anything
with that DefaultContext instance directly.
Once you have completed these steps, you do not need to specify the connection for
any of the SQLJ executable statements in your application if you want them all to
use the default connection.
Note: The connect.properties file is searched for relative to the specified class. In
the example, if MyProg is located in my-package, then connect.properties must
be found in the same package location, my­package, as MyProg.class.
Oracle9i: Access the Database with Java and JDBC 7-12
How to Manually Register
the Driver and Connect

1. Register the JDBC driver.


DriverManager.registerDriver(
new oracle.jdbc.driver.OracleDriver());

2. Connect to the database.


– Specify connection properties
Connection conn = DriverManager.getConnection
(URL, userid, password);

– Disable Auto-commit
Conn.setAutoCommit(false);

7-13 Copyright © Oracle Corporation, 2002. All rights reserved.

Register the Driver and Connect


The first step is done directly in JDBC. You load a JDBC driver and call the JDBC method
DriverManager.getConnection() to connect to the database.
Registering the JDBC driver and connecting to the database
These steps are exactly the same as the corresponding steps for a JDBC query.
If you are using an Oracle JDBC driver, but do not use Oracle.connect(), then you
must manually register the OracleDriver class, as follows:
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Once the driver is registered, you connect to the database providing the URL, the userid and
the password as variables or directly as strings as in the following example:
Connection conn=DriverManager.getConnection
("jdbc:oracle:thin:@myHost:1521:orcl", "scott", "tiger");
Note: By default the connection created is in an auto-commit mode. To create a connection
that is similar to the Oracle.connect() connection, you need to set the autocommit
property to false.
Oracle9i: Access the Database with Java and JDBC 7-13
Register Manually the Driver and Connect

3. Set the default connection context.


DefaultContext.setDefaultContext
(new DefaultContext(conn));

4. SQL statements are executed using the default


context by default.

7-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Set the Default Connection Context


All SQLJ queries execute in a connection context. At a minimum, you need to set the default
connection context. The default connection context is implemented by the
DefaultContext class.
The following example connects to the database and sets the default connection context:
Connection conn = null;
try {
// Register the driver
DriverManager.registerDriver(
new oracle.jdbc.driver.OracleDriver());
// Connect to the database
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@myhost:1521:orcl","scott","tiger");
// Set the default connection context
DefaultContext.setDefaultContext(new
DefaultContext(conn));
}

catch (SQLException ex) {


System.err.println("Could not connect: " + ex);
System.exit(0);
}
Oracle9i: Access the Database with Java and JDBC 7-14
What Is a Connection Context?

• All SQL statements execute in a connection


context.
• The connection context defines the database
schema, session, and transaction.
• SQLJ supports connection to multiple schemas at
the same time.
• Each SQLJ statement can specify a connection
context clause or use the default connection
context.

7-15 Copyright © Oracle Corporation, 2002. All rights reserved.

Connection Contexts
All the slides and examples in this lesson use the default connection context. The next lesson
shows how to use multiple connection contexts in one file.
SQLJ connection contexts are handled by implementations of the ConnectionContext
interface.
Oracle9i: Access the Database with Java and JDBC 7-15
Connection Code Example

Connection conn = null;


try {

DriverManager.registerDriver(
new oracle.jdbc.driver.OracleDriver());

conn = DriverManager.getConnection(
"jdbc:oracle:thin:@myHost:1521:orcl",
"scott","tiger");

DefaultContext.setDefaultContext(
new DefaultContext(conn));
}
catch (SQLException ex)
{
System.err.println("Could not connect: " + ex);
System.exit(0);
}

7-16 Copyright © Oracle Corporation, 2002. All rights reserved.

More About the DefaultContext Class


The sqlj.runtime.ref.DefaultContext class provides a complete default
implementation of a connection context class. As with classes created using a connection
context declaration, the DefaultContext class implements the
sqlj.runtime.ConnectionContext interface.
The DefaultContext class has the same class definition that would have been generated
by the SQLJ translator from the declaration:
#sql public context DefaultContext;
DefaultContext methods
The DefaultContext class has four methods:
getConnection(): This method is useful if you want to have JDBC code in your
application (which is one way to use dynamic SQL operations).
setDefaultContext(): This is a static method that sets the default connection your
application uses; SQLJ executable statements that do not specify a connection context
instance will use the default connection that you define using this method.
getDefaultContext(): This is a static method that returns the DefaultContext
instance currently defined as the default connection for your application.
close(): The DefaultContext class includes a close() method to close the connection
context instance.
Note: On a client, getDefaultContext() returns null if setDefaultContext()
was not previously called. However, if a data source object has been bound under
“jdbc/defaultDataSource” in JNDI, then the client will use this data source object as its
default connection. In the server, getDefaultContext() returns the default connection
(the connection to the server itself).
Oracle9i: Access the Database with Java and JDBC 7-16
How to Query a Database with SQLJ

• Execute the query and process the results.


int memberId;
int userId = ...

#sql {
SELECT member_id into :memberId
FROM acme_members
WHERE userid = :userId
};
return memberId;

• Close the SQLJ context.


Oracle.close();

7-17 Copyright © Oracle Corporation, 2002. All rights reserved.

Step 3: Execute the Query and Process the Results


The example in the slide executes a SELECT query that returns a single value. In this case,
processing the results is simply a case of returning the value selected. Later in this lesson, you
will learn how to process a result set containing multiple rows.
Step 4: Close the Connection
This releases all resources used in maintaining this connection.
To close the SQLJ context use either one of the following syntaxes according to the way the
context was opened:
• Oracle.close();
• DefaultContext.getDefaultContext().close();
Oracle9i: Access the Database with Java and JDBC 7-17
Exception Handling

• SQLJ statements can throw SQLException.


• Your code must catch SQLException or pass it to
the calling method.
int copyId = ...
try {
#sql {
UPDATE acme_copies
SET status = 'OUT'
WHERE copy_id = :copyId
};
}
catch (SQLException e) {
// handle the exception …
}

7-18 Copyright © Oracle Corporation, 2002. All rights reserved.

Exception Handling
Like JDBC statements, SQLJ statements can throw java.sql.SQLException. You
must deal with these exceptions in your code, either by using try…catch for every SQLJ
statement or declaring your method with throws SQLException.
Oracle9i: Access the Database with Java and JDBC 7-18
How to Handle SQL Null Values

• Java primitive types cannot have null values.


• Use Java wrapper classes instead of primitives
when your query might return a SQL null value.

int id = ...
Integer acc_man = null;
#sql {
SELECT account_manager INTO :acc_man
FROM customers
WHERE customer_id = :id
};

7-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Handling SQL Null Values


If your query could return a SQL null value, you should not assign the return value to a Java
primitive type such as int. The reason for this is that SQLJ converts SQL null values to Java
null values, and Java primitive types cannot have null values.
The solution is to use wrapper classes, such as Integer and Float, instead of primitive
types. The slide shows an example of the use of a wrapper class to select a value from a
nullable column. The same principle applies to updating a nullable column:
Integer acc_man = new Integer(149);
#sql {
UPDATE customers
SET account_mgr_id = :acc_man
WHERE customer_id = :id
};
Your program will throw sqlj.runtime.SQLNullException if you try to assign a
SQLJ null value to a Java primitive.
Oracle9i: Access the Database with Java and JDBC 7-19
Guided Practice 7-1:
Writing SQLJ Statements

Complete the code:


// updateOrders: update a record in ORDERS.
// Parameters:
// id: the copy id of the record to be updated
// mode: the new value of the order_mode
public void updateOrders (int id, String mode)…
{

UPDATE orders SET order_mode =


WHERE order_id =

7-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Guided Practice 7-1


Complete the method. updateOrders() updates the MODE of a record in ORDERS. The
ORDER_ID value of the record that is to be updated and the new value of MODE are both
passed as parameters. Assume that the code to connect to the database and set the default
context already exists outside of this method.
Instructor Note
Here is one possible solution:
public void updateOrders (int id, String status) 
{

try {
#sql { UPDATE orders SET order_mode = :mode
WHERE order_id = :id };
}
catch (SQLException e) {
System.out.println(e);
}
}

You could throw SQLException in the method declaration instead of using try…catch:
public void updateCopy (int id, String status) throws
SQLEXception
{

#sql { UPDATE orders SET order_mode = :mode


WHERE order_id = :id };
}
Oracle9i: Access the Database with Java and JDBC 7-20
Guided Practice 7-2:
Writing SQLJ Statements

Complete the code:


// countProducts: return the number of records
// in PRODUCT_INFORMATION
// Hint: use SELECT COUNT(*)
public int countProducts()…
{

SELECT COUNT(*)
FROM product_information

7-21 Copyright © Oracle Corporation, 2002. All rights reserved.

Guided Practice 7-2


Complete the method. countProducts() counts the number of records in
PRODUCT_INFORMATION.
Instructor Note
Here is one possible solution:
public int countProducts () throws SQLException{
int numberOfProducts;
#sql {
SELECT COUNT(*)
INTO :numberOfProducts
FROM product_information
};
return numberOfProducts;
}
Oracle9i: Access the Database with Java and JDBC 7-21
What Is an Iterator?

• SQLJ uses an iterator to access the result set of a


multirow query.
• An iterator defines a Java class with a variable for
each column of the result set.
• Use a named or a positional iterator.

#sql iterator CustIterator (


Integer customer_id, String cust_first_name);

SELECT customer_id, cust_first_name FROM customers

7-22 Copyright © Oracle Corporation, 2002. All rights reserved.

About Iterators
You use a SQLJ iterator to return the results of a multirow query. A SQLJ iterator is strongly
typed, which means that the number and types of its columns are defined when the iterator is
created. This allows the SQLJ translator to perform type checking on the iterator at compile
time to verify that the iterator’s columns are compatible with the data types of the underlying
database cursor. In contrast, the JDBC result set object can contain any number of columns of
any type, because there is no compile-time checking of the SQL.
An iterator is a class
An iterator is translated into a Java class by the SQLJ translator, so that it can be treated as a
Java class. It can be passed as a method parameter and can be declared as public or
private.
Named iterators and positional iterators
There are two types of iterators:
• Named iterator: You use a named iterator to access the result set columns by name.
• Positional iterator: You use a positional iterator to access the result set columns by
position.
The steps for executing a multirow query are the same for both types of iterator, but the
syntax is different.
Instructor Note
It is important to understand that you define an iterator for a particular query, not for a
database table or schema.
Oracle9i: Access the Database with Java and JDBC 7-22
How to Execute a Multirow Query
by Using a Named Iterator

1. Define the iterator class.


#sql iterator CustIterator (
Integer customer_id, String cust_first_name);

2. Declare a variable of the iterator class.


CustIterator customers;

3. Populate the variable with query results.


#sql customers = {SELECT customer_id,
cust_first_name FROM customers} ;

7-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Executing a Multirow Query by Using a Named Iterator


The slide shows the first three steps that you follow to execute a multirow query by using a
named iterator. Steps 4 and 5 are shown on the following slide.
Defining an iterator class
When you declare a named iterator, you declare an iterator column for each field in your
select statement. The name of each iterator column and its corresponding field in the
select statement must be the same; the case does not have to match. The data type of the
iterator column must be compatible with the corresponding select field; the case does not
have to match.
In the example in the slide, the iterator CustIterator has two columns: CUSTOMER_ID
and CUST_FIRST_NAME. The names of these columns match the names of the columns that
are selected in the SELECT statement.
Declaring an iterator variable
Step 1 defines an iterator class. You then need to declare a variable of that class that you will
populate in your query.
Step 2 declares a variable members, whose type is MemberIterator.
Step 3. This is how SQLJ matches iterator columns with fields in the select statement.
Instructor Note
It is important to remember that an iterator declaration is translated to a class definition. This
means that you can put a #sql iterator declaration only where you would put a class
declaration. For example, you cannot put an iterator declaration inside a method block. The
easiest approach is to put the iterator declaration outside the class declaration.
You should emphasize that the name of each iterator column must match the corresponding
field in the select statement; this is an important point.
Oracle9i: Access the Database with Java and JDBC 7-23
How to Execute a Multirow Query
by Using a Named Iterator

4. Step through the results.


int id;
String name;
while (customers.next()) {
id = customers.customer_id();
name = customers.cust_first_name ();
// Perform additional processing

}

5. Close the iterator.


customers.close();

7-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Executing a Multirow Query by Using a Named Iterator (continued)


The slide shows steps 4 and 5 for executing a multirow query using a named iterator.
Stepping through the Results
A named iterator has a next() method to retrieve data row by row and an accessor method
for each column to retrieve the data from each column. The names of the accessor methods
are identical to the names of the iterator columns.
In the example in the slide, the CUSTOMER_ID() method retrieves the value of the
CUSTOMER_ID column from the current row of the result set, and the
CUST_FIRST_NAME() method retrieves the value of the CUST_FIRST_NAME column.
Treating an iterator as a JDBC result set
A named iterator has a getResultSet() method that returns the JDBC result set
associated with the iterator.
Oracle9i: Access the Database with Java and JDBC 7-24
Selecting a Calculated Field or Function
Call into a Named Iterator

Use an alias in your SELECT statement.


#sql iterator OverdueIter (int overdue);

OverdueIter daysLate;
#sql daysLate = {SELECT TRUNC(SYSDATE-(TO_DATE
(SUBSTR(order_date,1,9)))) AS overdue
FROM orders};

Column alias

7-25 Copyright © Oracle Corporation, 2002. All rights reserved.

Selecting a Calculated Field or Function Call


The example in the previous slide shows the procedure for selecting database columns and
matches each iterator column to the corresponding column in the SELECT statement by
giving the iterator column the same name as the database column. This approach does not
work if the field of your SELECT statement involves more than a single database column
name.
The example in this slide shows what to do when the fields of your SELECT statement are
more complex. You must assign an alias to the select field, and the alias name must be the
same as the corresponding iterator column name. The example calculates the days overdue
for each rental item and selects the calculated values into the overdue column of the
iterator.
Select statements containing function calls
You also use an alias with a select statement containing a function call. For example:
#sql iterator PriceIter{double avgPrice};
...
PriceIter price;
#sql price = {SELECT AVG(min_price) as avgPrice
FROM product_information};
Oracle9i: Access the Database with Java and JDBC 7-25
How to Execute a Query
by Using a Positional Iterator

1. Define the iterator class.


#sql iterator CustomerIterator(int, String);

2. Declare a variable of the iterator class.


CustomerIterator customers;

3. Populate the variable with query results.


#sql customers =
{SELECT customer_id, cust_fisrt_name
FROM customers} ;

7-26 Copyright © Oracle Corporation, 2002. All rights reserved.

Executing a Multirow Query by Using a Positional Iterator


This slide and the next slide show the steps involved in executing a query with a positional
iterator. Steps that are different from the procedure for a named iterator are highlighted.
About positional iterators
When you declare a positional iterator class, you declare the data type of each column but not
the column name. The Java types into which the columns of the SQL query results are
selected must be compatible with the datatypes of the SQL data. The names of the database
columns or SELECT-fields are irrelevant.
Because names are not used, the order in which you declare your positional iterator Java
types must exactly match the order in which the data is selected.
Defining the iterator class
The iterator columns do not have names; only their data types are listed in the class
definition. The example defines an iterator class with unnamed columns of types int and
String.
Populating the iterator variable
The SELECT fields must be in the same order as the iterator columns. In the example, the
customer_id database column is selected into the first (int) column of the iterator, and
the cust_first_name database column is selected into the second (String) column of
the iterator.
Oracle9i: Access the Database with Java and JDBC 7-26
How to Execute a Query
by Using a Positional Iterator

4. Step through the results.


int id;
String name;
while (true) {
#sql {fetch :customers into :id, :name};
if (customers.endFetch())
break;
// Perform additional processing …
}

5. Close the iterator.


customers.close();

7-27 Copyright © Oracle Corporation, 2002. All rights reserved.

Executing a Multirow Query by Using a Positional Iterator (continued)


The slide shows steps 4 and 5 for executing a multirow query using a positional iterator.
Stepping through the results
Retrieve data from the columns of a positional iterator using SQL FETCH…INTO syntax.
Positional iterators have an endFetch() method that returns true when you reach the end
of the result set.
The FETCH CURRENT FROM syntax can be used to populate variables from the current
row.
Unlike the FETCH clause, the FETCH CURRENT FROM does not perform any movement.
Note: You must call endFetch() after the FETCH…INTO statement, not before. This is
because endFetch() initially returns true before any rows have been fetched, returns
false after you fetch the first row, and then returns true again when the last row has been
fetched.
Oracle9i: Access the Database with Java and JDBC 7-27
Named Iterator Versus Positional Iterator

• Named iterators characteristics:


– Matching is made on names
– Column order is not important
– Allow greater flexibility
– Use next() method for multirow queries
• Positional iterators characteristics:
– Similar to other embedded-SQL languages
– Use FETCH INTO syntax
– Correct order for host expressions is required

7-28 Copyright © Oracle Corporation, 2002. All rights reserved.

Comparing Named Iterators and Positional Iterators


Named iterators allow greater flexibility. Because data selection into a named iterator
matches SELECT-fields to iterator columns by name, you need not be concerned about the
order in your query. This is less prone to error, as it is not possible for data to be placed into
the wrong column. If the names do not match, the SQLJ translator will generate an error
when it checks your SQL statements against the database.
Positional iterators offer a familiar paradigm and syntax to developers who have experience
with other embedded-SQL languages. With named iterators you use a next() method to
retrieve data, while with positional iterators you use FETCH INTO syntax similar to that of
Pro*C, for example. (Each fetch implicitly advances to the next available row of the iterator
before retrieving the next set of values.)
Positional iterators do, however, offer less flexibility than named iterators, because you are
selecting data into iterator columns by position, instead of by name. You must be certain of
the order of items in your SELECT statement. You also must select data into all columns of
the iterator, and it is possible to have data written into the wrong iterator column if the type
of that column happens to match the datatype of the table column being selected.
Oracle9i: Access the Database with Java and JDBC 7-28
Comparing Named Iterators and Positional Iterators (continued)
Access to individual data elements is also less convenient with positional iterators.
Named iterators, because they store data by name, are able to have convenient accessor
methods for each column (for example, there would be an ename() method to retrieve data
from an ename iterator column). With positional iterators, you must fetch data directly into
Java host expressions with your FETCH INTO statement, and the host expressions must be
in the correct order.
Finally, if you do not want to declare strongly typed iterator classes for your queries, you can
choose the alternative of using weakly typed result set iterators.
Result set iterators are most convenient when converting JDBC code to SQLJ code. You must
balance this consideration against the fact that result set iterators (either ResultSetIterator
instances or ScrollableResultSetIterator instances) do not allow complete SQLJ semantics-
checking during translation. With named or positional iterators, SQLJ verifies that SELECT-
list types match the Java types into which the data will be materialized. With result set
iterators, this is not possible.

Oracle9i: Access the Database with Java and JDBC 7-29


Embedding PL/SQL with SQLJ

PL/SQL blocks, can be used within the curly braces


of a SQLJ executable statement.
#sql {
DECLARE
n NUMBER;
BEGIN
n := 1;
WHILE n <= 100 LOOP
INSERT INTO emp (empno) VALUES(2000 + n);
n := n + 1;
END LOOP;
END
};
=
#sql { <DECLARE ...> BEGIN ... END };

7-30 Copyright © Oracle Corporation, 2002. All rights reserved.

PL/SQL with SQLJ


A PL/SQL block in SQLJ follows the syntactic rules of a SQL statement with SQLJ. It starts
with #SQL{ and ends up with };
Oracle9i: Access the Database with Java and JDBC 7-30
Calling a Procedure with SQLJ

Calling the MAX_DEADLINE procedure:


java.sql.Date maxDeadline;
...
#sql { CALL MAX_DEADLINE(:out maxDeadline) };
...

• Use the host expression tokens IN


(optional/default), OUT, and INOUT appropriately to
match the input, output, and input-output
parameters of the stored procedure.
• The types of the host variables you use in the
parameter list must be compatible with the
parameter types of the stored procedure.

7-31 Copyright © Oracle Corporation, 2002. All rights reserved.

Calling a Procedure with SQLJ


For any parameters, you must use the host expression tokens IN (optional/default), OUT, and
INOUT appropriately to match the input, output, and input-output designations of the stored
procedure. Additionally, the types of the host variables you use in the parameter list must be
compatible with the parameter types of the stored procedure.
Note: If you want your application to be compatible with Oracle7, do not include empty
parentheses for the parameter list if the procedure takes no parameters. For example:
#sql { CALL MAX_DEADLINE };
Oracle9i: Access the Database with Java and JDBC 7-31
Calling a Function with SQLJ

Calling the GET_MAX_DEADLINE function:


java.sql.Date maxDeadline;
...
#sql maxDeadline = { VALUES(GET_MAX_DEADLINE) };
...

• Use the host expression tokens IN


(optional/default), OUT, and INOUT appropriately to
match the input, output, and input-output
parameters of the stored function.
• The types of the host variables you use in the
parameter list must be compatible with the
parameter types of the stored function.

7-32 Copyright © Oracle Corporation, 2002. All rights reserved.

Calling a Function with SQLJ


In SQLJ, you can call this GET_MAX_DEADLINE function as follows:
java.sql.Date maxDeadline;
...
#sql maxDeadline = { VALUES(GET_MAX_DEADLINE) };
The result expression must have a type compatible with the return type of the function.
In Oracle SQLJ, the following syntax (outer parentheses omitted) is also allowed:
#sql maxDeadline = { VALUES GET_MAX_DEADLINE };
For stored function calls, as with stored procedures, you must use the host expression tokens
IN (optional/default), OUT, and INOUT appropriately to match the input, output, and input-
output parameters of the stored function. Additionally, the types of the host variables you use
in the parameter list must be compatible with the parameter types of the stored function.
Note: If you want your stored function to be portable to non-Oracle environments, then you
should use only input parameters in the calling sequence, not output or input-output
parameters.
If you want your application to be compatible with Oracle7, then do not include empty
parentheses for the parameter list if the function takes no parameters. For example:
#sql maxDeadline = { VALUES(GET_MAX_DEADLINE) };
not:
#sql maxDeadline = { VALUES(GET_MAX_DEADLINE()) };
Oracle9i: Access the Database with Java and JDBC 7-32
How to Add a New SQLJ File
to a JDeveloper Project

1. Open your project.


2. Select File > New from the menu.
3. Select the Objects category.
4. Double-click the SQLJ Class icon in the Items
block.

7-33 Copyright © Oracle Corporation, 2002. All rights reserved.

Adding New SQLJ File to a Project


When you add a new SQLJ file to a project, JDeveloper creates a new file with a .sqlj
suffix. This file contains only two lines of code, to import the SQLJ classes.
An alternative method is to create a new class file, rename it, and add the import
statements. This gives you a file with a class definition, header comments, and package
statement, but not the SQLJ imports. The steps for doing this are as follows:
1. Select File > New from the menu.
2. Select the Objects category.
3. Double-click the Class icon in the items gallery.
4. Enter the name of your class, the package, and the base class; select the optional
attributes you want; and then click OK.
5. Add the following import statements to your file:
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
import java.sql.*;
6. Use File > Rename to change the .java extension to .sqlj.
Instructor Note
The new .sqlj file created by JDeveloper does not contain the complete list of imports; you
also need to import the JDBC packages:
import java.sql.*;
Oracle9i: Access the Database with Java and JDBC 7-33
How to Add an Existing SQLJ File to a Project (continued)
You can add an existing SQLJ file to your project in the same way that you add any other file:
1. Select File > Open from the JDeveloper menu.
2. Use the File dialog box to select the file that you want to add; use the Files of Type
scroll box to restrict the display to SQLJ files.
3. Select the Add to Project check box.
4. Click Open.

Oracle9i: Access the Database with Java and JDBC 7-34


Deploying SQLJ Code in JDeveloper

• JDeveloper invokes the SQLJ translator as part of


the build process.
• You use JDeveloper to set SQLJ translator options.
• .sqlj files are translated to .java files.
• The generated .java files do not appear in the
navigator pane.
• You can debug the SQLJ source code directly.

7-35 Copyright © Oracle Corporation, 2002. All rights reserved.

Deploying SQLJ Code in JDeveloper


You build a project that contains .sqlj files in the same way that you build any other
project in JDeveloper. JDeveloper invokes the SQLJ translator, which generates a .java file
for each .sqlj file. Each generated .java file has the same name and resides in the same
file system location as the corresponding .sqlj file. The generated .java files do not
appear in JDeveloper’s navigator pane, and you will probably never need to access them.
Debugging SQLJ code
You debug SQLJ code by debugging the SQLJ source code directly, not the generated Java
code. For example, if you set a breakpoint on a SQLJ statement, the debugger pauses at that
statement.
Oracle9i: Access the Database with Java and JDBC 7-35
Configuring SQLJ Translator Options
in JDeveloper

• Select Project > Project Properties and then select


the SQLJ tab.
• JDeveloper allows you to set the level of checking
by the SQLJ translator.
• Checking is performed against the database - you
need to specify a database connection.

7-36 Copyright © Oracle Corporation, 2002. All rights reserved.

SQLJ Translator Options


One of the strengths of SQLJ is the ability to check the syntax and semantics of your SQL
statements against a database at compile time.
You use JDeveloper to set SQLJ translator options on the SQLJ tab of the Project Properties
dialog box.
Oracle9i: Access the Database with Java and JDBC 7-36
SQLJ Translator Options:
Translator Warnings
Checks that iterators are Checks for potential loss
consistent with SELECT of precision in numeric
statements values

Project settings

Checks for safe Checks for


handling of nullable vendor-specific
columns types

7-37 Copyright © Oracle Corporation, 2002. All rights reserved.

Translator Warnings

There are four options for translator warnings. By default, all of these warnings are enabled.
• Strict: The translator performs a matching test for named iterators. If this option is
enabled, the translator gives a warning if the number of columns selected from the
database is not the same as the number of columns in the named iterator being
populated.
• Null: If this option is enabled, the translator checks database columns against Java
variable data types. A warning is issued if the database column can be null and the Java
variable cannot be.
• Precision: The translator checks for the potential loss of precision when selecting SQL
numeric types into Java variables.
• Portable: If this option is enabled, the translator gives a warning when it encounters
any nonportable (that is, vendor-specific) SQLJ clauses.
If you do not enable online checking, the translator checks for portability but does not
perform strict, null, or precision checks.
Oracle9i: Access the Database with Java and JDBC 7-37
SQLJ Translator Options:
Online SQL Checking
Enable online
checking.

Project settings

Leave blank for the Select the connection


default context. to check against.

7-38 Copyright © Oracle Corporation, 2002. All rights reserved.

Online SQL Checking


You must enable online checking for the SQL translator to check your code against a
database. The slide shows how to do this for applications where all of your statements use the
default connection context.
Oracle9i: Access the Database with Java and JDBC 7-38
Summary

• SQLJ is another way for embedding SQL


statements in Java code
• SQLJ translates SQL statements in JDBC code
• SQLJ uses a connection context to perform SQL
statements
• Use iterators for queries that return multiple rows
• Iterators can be named or positional
• You can create SQLJ objects in JDeveloper

7-39 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 7-39


Practice 7 Overview

This practice covers:


• Setting up the Java environment for SQLJ
• Writing and Running a simple Java application that
access to a database using SQLJ
• Query the database using a named iterator

7-40 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC 7-40


Practice 7-1
Goal
The goal of this practice is to create a simple Java class that provides access to the
database using SQLJ and run it in an MS DOS window. You will have to set up the
environment variables to be able to compile and run a simple Java class that interacts
with the Oracle database. During this practice you perform Query statements.
Your assignment
You create the Practice7 class. In this class, you specify the code to connect to the
database, to query a single column from a table, and to disable the autocommit option.
Modify the PATH environment variable
1. Open Notepad
– Type in the CLASS variable:
set
PATH=<JDeveloper_home>\jdk\bin\;<oracle_home>\bin\;
< JDeveloper_home>\jdev\bin\;%PATH%;
– Type in the CLASSPATH variable to include the runtime and translator jar
files:
set CLASSPATH=.
set CLASSPATH=%CLASSPATH%;<oracle_home>\jdbc\lib\classes12.jar
set CLASSPATH=%CLASSPATH%;<oracle_home>\sqlj\lib\runtime12.jar
set CLASSPATH=%CLASSPATH%;< oracle_home>\sqlj\lib\translator.jar
2. Save the file with the name E:\mysqlj.bat
Setting up the environment
3. Open an MS DOS window
– Click Start on the taskbar
– Select the Start MS/DOS option
– Run the mysqlj.bat file
– Move to the E:\labs\sqlj directory
4. Checking the environment
– Verify the JDBC, SQLJ and JDK versions
E:\labs\sqlj> sqlj –version-long
Create the Java class
5. Open Notepad to enter the Java code
– Specify the packages to import
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.error.*;
import oracle.sqlj.runtime.*;
import sqlj.runtime.ref.*;
import sqlj.runtime.error.*;
import oracle.sql.*;

Oracle9i: Access the Database with Java and JDBC 7-41


Practice 7-1 (continued)
– Specify the following template statements
public class Practice7
{

public static void main (String args [])


throws Exception
{

6. Specify the connection to the database


– Use the Oracle.connect() method using a property file named
connect.properties to connect to the database.
Oracle.connect(Practice7Sol.class,
"connectSol.properties");
– Add a statement to display the message “connection established”
System.out.println("connection established");
7. Perform a single row query
– Declare a int type variable
int id;
– Add a SQLJ/SQL statement that queries the first customer_id of table
Customers (use rownum=1)
# sql{SELECT customer_id INTO :id FROM customers
WHERE ROWNUM=1};
– Print the customer id
System.output.println(("id "+ id);
– Close the connection context
Oracle.close();
– Add a statement to display the message “connection established”
System.out.println("connection closed");
8. Save the file in the E:\labs directory with the name Practice7.sqlj, using
File|Save menu option, but keep notepad running, you will need it again.
Create the connect.properties file
9. Using Notepad, create a connection properties file named connect.properties
– Type in the URL, username, and password provided by your instructor.
sqlj.url= jdbc:oracle:thin:@myhost:1521:SID
# User name and password here (edit to use 
different     
user/password)
sqlj.user=scott
sqlj.password=tiger
– Save the file in your labs current directory
Edit and run your Java application
10. Save the file in the E:\labs directory with the name Practice7.java, using
File|Save menu option, but keep Notepad running, you will need it again.

Oracle9i: Access the Database with Java and JDBC 7-42


Practice 7-1 (continued)
11. Compile the Practice7.sqlj file
– a. In the DOS window, ensure the current directory is E:\labs
– b. Check that the JDBC source file is saved to disk.
– c. Compile the file using command: sqlj Practice7.sqlj
– d. What files are created if you successfully compiled the code?
Practice7.java
Practice7.class
– e. Display the content of the .java file to see what is generated.
12. Run the Practice7 application.
– a. Run the file using command: java Practice7
– b. What was displayed in the ‘DOS’ window?
connection established
id 101
connection closed
13. Recompile the Practice7.sqlj file
– a. Recompile the file using the following command:
sqlj –codegen=iso Practice7.sqlj
– b. What files are created now, if you successfully compiled the code?
Practice7_SJProfile0.ser
Practice7_SJProfileKeys.class
Change the Connection method
14. Specify a default connection context using
DriverManager.registerDriver() method
– Reopen the file Practice7.sqlj with Notepad
– Remove the Oracle.connect() , and the Oracle.close() statements.
– Register the Oracle JDBC driver
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
– Connect to the database using the Connection type
Connection conn =
DriverManager.getConnection(URL,userid,password);
– Create a default context and set auto-commit off
DefaultContext.setDefaultContext(new
DefaultContext(conn));
conn.setAutoCommit(false);
– Close the context and the connection();

Oracle9i: Access the Database with Java and JDBC 7-43


Practice 7-1 (continued)
Edit and run your Java application
15. Save the file in the E:\labs directory with the name Practice7.sqlj
16. Compile the Practice7.sqlj file
sqlj Practice7.sqlj
17. Execute the class
java Practice7
Perform online checking for your Java application
18. Change your SQL statement to produce a semantic error.
– Reopen the file Practice7.sqlj with Notepad
– Change the name of the product_id column and name it product.
– Compile the Practice7.sqlj file
sqlj Practice7.sqlj
– Was the compilation successful?
– Recompile the file Practice7.sqlj with an online checking using the
thin driver
– E:\Labs\sqlj> sqlj -user=oraXX/oracle
-url=jdbc:oracle:
thin:@myhost:1521:SID Practice7.sqlj
– Was the compilation successful?

Oracle9i: Access the Database with Java and JDBC 7-44


Practice 7-2
Goal
The goal of this practice is to create a multi row query using a named iterator.
Your assignment
You use the Practice7.sqlj file previously created, rename the class name to
Practice72 and update the SQL statement in order to retrieve more than one row
with a named iterator.
Create a multi row query statement in the Java class
1. Define an iterator class for customer_id, cust_first_name and
cust_last_name columns of table CUSTOMERS
#sql iterator CustomerIterator(int customer_id, String
cust_last_name , String cust_first_name);
2. Declare a variable of the iterator class
CustomerIterator customers=null;
3. Declare three variables named id, first, and last of the appropriate type to
map with the columns of the iterator
int id= 0;
String first;
String last;
4. Define a SQLJ/SQL statement for the iterator that queries the three corresponding
columns of the CUSTOMERS table for customers having a credit_limit of 100
#sql customers={SELECT 
customer_id,cust_first_name,cust_last_name FROM 
customers WHERE credit_limit=100};
5. Specify a loop that prints each row returned by the query
while (customers.next()) 
{

id =customers.customer_id();
last=customers.cust_last_name();
first=customers.cust_first_name();
System.out.println(id+" "+last +" "+first);
}

6. Close the iterator


customers.close();
Edit and run your Java application
7. Save the file in the E:\labs directory with the name Practice72.java.
8. Compile the Practice72.sqlj file
9. Run the Practice72 application

Oracle9i: Access the Database with Java and JDBC 7-45


Practice 7-2 Additional (if you have time)
Update the Practice7 file and replace the named iterator by a positional one.

Oracle9i: Access the Database with Java and JDBC 7-46


Order Entry Schema

Appendix A

Copyright © Oracle Corporation, 2002. All rights reserved.


Practice 1
CREATE TYPE cust_address_typ AS OBJECT
( street_address VARCHAR2(40)

, postal_code VARCHAR2(10)
, city VARCHAR2(30)
, state_province VARCHAR2(10)
, country_id CHAR(2)
);

CREATE TYPE phone_list_typ AS VARRAY(5) OF VARCHAR2(25);

CREATE TABLE customers


( customer_id NUMBER(6)
, cust_first_name VARCHAR2(20) CONSTRAINT
cust_fname_nn NOT NULL
, cust_last_name VARCHAR2(20) CONSTRAINT
cust_lname_nn NOT NULL
, cust_address cust_address_typ

, phone_numbers phone_list_typ
, nls_language VARCHAR2(3)

, nls_territory VARCHAR2(30)
, credit_limit NUMBER(9,2)

, cust_email VARCHAR2(30)
, account_mgr_id NUMBER(6)
, cust_geo_location MDSYS.SDO_GEOMETRY
, CONSTRAINT
customer_credit_limit_max
CHECK (credit_limit <= 5000)
, CONSTRAINT customer_id_min
CHECK (customer_id > 0)
) ;
Oracle9i: Access the Database with Java and JDBC A-2
Practice 1 (continued)
CREATE TABLE warehouses
( warehouse_id NUMBER(3)
, warehouse_spec SYS.XMLTYPE
, warehouse_name VARCHAR2(35)

, location_id NUMBER(4)
, wh_geo_location MDSYS.SDO_GEOMETRY
) ;

ALTER TABLE warehouses

ADD (CONSTRAINT warehouses_pk PRIMARY KEY (warehouse_id)


);

CREATE TABLE order_items


( order_id NUMBER(12)
, line_item_id NUMBER(3) NOT NULL

, product_id NUMBER(6) NOT NULL


, unit_price NUMBER(8,2)
, quantity NUMBER(8)
) ;

ALTER TABLE order_items

ADD ( CONSTRAINT order_items_pk PRIMARY KEY (order_id,


line_item_id)
);
Oracle9i: Access the Database with Java and JDBC A-3
Practice 1 (continued)
CREATE TABLE orders
( order_id NUMBER(12)
, order_date TIMESTAMP WITH LOCAL TIME ZONE
CONSTRAINT order_date_nn NOT
NULL
, order_mode VARCHAR2(8)
, customer_id NUMBER(6)
CONSTRAINT order_customer_id_nn
NOT NULL
, order_status NUMBER(2)

, order_total NUMBER(8,2)
, sales_rep_id NUMBER(6)
, CONSTRAINT
order_mode_lov
CHECK (order_mode in
('direct','online'))
, constraint order_total_min
check (order_total >= 0)
) ;

ALTER TABLE orders

ADD ( CONSTRAINT order_pk PRIMARY KEY (order_id)


);

CREATE TABLE inventories


( product_id NUMBER(6)
, warehouse_id NUMBER(3)
CONSTRAINT
inventory_warehouse_id_nn NOT
NULL
, quantity_on_hand NUMBER(8)
CONSTRAINT inventory_qoh_nn NOT
NULL
, CONSTRAINT inventory_pk PRIMARY
KEY (product_id, warehouse_id)
) ;
Oracle9i: Access the Database with Java and JDBC A-4
Practice 1 (continued)
CREATE TABLE product_information
( product_id NUMBER(6)
, product_name VARCHAR2(50)
, product_description VARCHAR2(2000)
, category NUMBER(2)
, weight_class NUMBER(1)
, warranty_period INTERVAL YEAR TO MONTH
, supplier_id NUMBER(6)
, product_status VARCHAR2(20)
, list_price NUMBER(8,2)
, min_price NUMBER(8,2)
, catalog_url VARCHAR2(50)
, CONSTRAINT product_status_lov
CHECK (product_status in
('orderable'
,'planned'
,'under development'
,'obsolete')
)
) ;

ALTER TABLE product_information


ADD ( CONSTRAINT product_information_pk PRIMARY KEY
(product_id)
);
CREATE TABLE product_descriptions
( product_id NUMBER(6)
, language_id VARCHAR2(3)
, translated_name NVARCHAR2(50)
, translated_description NVARCHAR2(2000)
);

ALTER TABLE product_descriptions

ADD ( CONSTRAINT product_descriptions_pk


PRIMARY KEY (product_id, language_id));
Oracle9i: Access the Database with Java and JDBC A-5
Practice 1 (continued)
CREATE TABLE countries
( country_id CHAR(2)
CONSTRAINT country_id_nn NOT
NULL
, country_name VARCHAR2(40)
, currency_name VARCHAR2(25)
, currency_symbol VARCHAR2(3)
, region VARCHAR2(15)
, CONSTRAINT country_c_id_pk
PRIMARY KEY (country_id)
)

CREATE TABLE locations


( location_id NUMBER(4)
, street_address VARCHAR2(40)
, postal_code VARCHAR2(12)
, city VARCHAR2(30)
CONSTRAINT loc_city_nn NOT
NULL
, state_province VARCHAR2(25)
, country_id CHAR(2)
) ;

ALTER TABLE locations

ADD ( CONSTRAINT loc_id_pk PRIMARY KEY (location_id)


, CONSTRAINT loc_c_id_fk FOREIGN KEY (country_id)
REFERENCES countries(country_id)
) ;

CREATE TABLE departments


( department_id NUMBER(4)
, department_name VARCHAR2(30)
CONSTRAINT dept_name_nn NOT
NULL
, manager_id NUMBER(6)
, location_id NUMBER(4)
, dn VARCHAR2(300)
) ;
ALTER TABLE departments

ADD ( CONSTRAINT dept_id_pk PRIMARY KEY (department_id)


, CONSTRAINT dept_loc_fk FOREIGN KEY (location_id)
REFERENCES locations (location_id)
) ;

Oracle9i: Access the Database with Java and JDBC A-6


Practice 1 (continued)
CREATE TABLE jobs
( job_id VARCHAR2(10)
, job_title VARCHAR2(35)
CONSTRAINT job_title_nn NOT
NULL
, min_salary NUMBER(6)
, max_salary NUMBER(6)
) ;
ALTER TABLE jobs

ADD ( CONSTRAINT job_id_pk PRIMARY KEY(job_id)) ;

CREATE TABLE employees


( employee_id NUMBER(6)
, first_name VARCHAR2(20)
, last_name VARCHAR2(25)
CONSTRAINT emp_last_name_nn
NOT NULL
, email VARCHAR2(25)
CONSTRAINT emp_email_nn NOT
NULL
, phone_number VARCHAR2(20)
, hire_date DATE
CONSTRAINT emp_hire_date_nn
NOT NULL
, job_id VARCHAR2(10)
CONSTRAINT emp_job_nn NOT NULL
, salary NUMBER(8,2)
CONSTRAINT emp_salary_nn NOT
NULL
, commission_pct NUMBER(2,2)
, manager_id NUMBER(6)
, department_id NUMBER(4)
, dn VARCHAR2(300)
, CONSTRAINT emp_salary_min
CHECK (salary > 0)
, CONSTRAINT emp_email_uk
UNIQUE (email)
) ;

Oracle9i: Access the Database with Java and JDBC A-7


Practice 1 (continued)
ALTER TABLE employees
ADD ( CONSTRAINT emp_emp_id_pk PRIMARY KEY
(employee_id)
, CONSTRAINT emp_dept_fk FOREIGN KEY
(department_id)
REFERENCES departments
, CONSTRAINT emp_job_fk FOREIGN KEY (job_id)
REFERENCES jobs (job_id)
, CONSTRAINT emp_manager_fk FOREIGN KEY
(manager_id)
REFERENCES employees
) ;

ALTER TABLE departments


ADD ( CONSTRAINT dept_mgr_fk FOREIGN KEY (manager_id)
REFERENCES employees (employee_id)
) ;

CREATE TABLE job_history


( employee_id NUMBER(6)
CONSTRAINT jhist_employee_nn
NOT NULL
, start_date DATE
CONSTRAINT
jhist_start_date_nn NOT NULL
, end_date DATE
CONSTRAINT jhist_end_date_nn
NOT NULL
, job_id VARCHAR2(10)
CONSTRAINT jhist_job_nn NOT
NULL
, department_id NUMBER(4)
, CONSTRAINT
jhist_date_interval
CHECK (end_date > start_date)
) ;

ALTER TABLE job_history

ADD ( CONSTRAINT jhist_emp_id_st_date_pk PRIMARY KEY


(employee_id, start_date)
, CONSTRAINT jhist_job_fk FOREIGN KEY (job_id)
REFERENCES jobs
, CONSTRAINT jhist_emp_fk FOREIGN KEY (employee_id)
REFERENCES employees
, CONSTRAINT jhist_dept_fk FOREIGN KEY
(department_id)
REFERENCES departments
) ;

Oracle9i: Access the Database with Java and JDBC A-8


Practice Solutions

Appendix B

Copyright © Oracle Corporation, 2002. All rights reserved.


Practice 1
Goal
The goal of this practice is to review JDeveloper IDE and refresh your understanding of
some basic operations in order to feel comfortable with the tool.
Your assignment
You launch JDeveloper, and create a workspace and a project. You then upload a .java
file in your project, you compile it and run it. Finally you invoke the online help and do
some research on Class documentation.
Start Oracle9i JDeveloper
• Click the JDeveloper icon on the desktop
• Create a new workspace and a project
– Use the File | New menu option
– In the New Gallery select Projects in the Categories pane and the double-click the
Workspace object in the Items pane.
– In the directory name, leave the path and replace the Workspace name by
Lesson01
– Change the File Name to Lesson01.jws and click OK
– In the New Project dialog box, leave the indicated path , for the Directory Name, and
replace the Project name by Intro.
– Change the File Name to Intro.jws and click OK
Load a .java file
• Load a .Java file into your current project
– Use the File | Open menu option
– In the Location, specify the C:\ labs\ directory
– Select the HelloWorld.java file and click OK
– On the Add Project Source Path question, answer Yes to update the project source
path
– HelloWorld.java appears in the System Navigator.
Run a .java file
• Run a .Java file into your current project
– Read the HelloWorld.java file in the Editor window
– Right-click HelloWorld.java entry in the System Navigator
– Select the Run HelloWorld option in the menu
– Does the file compile?
– What is displayed in the Log window?
– Hello World should appear.
Use the online Help
• Searching for Java classes info
– Select Help in the menu
– In the Contents tab open the Reference node

Oracle9i: Access the Database with Java and JDBC Appendix B-2
Practice 1 (continued)
– Locate the Oracle JDBC entry
– Select the oracle.jdbc.driver package
– How many classes does this package contain?
– There are 11 classes in this package
– Locate the OracleConnection class and scroll through the documentation to see
class details
– Use the Back icon
– Click the left arrow
– Select the Oracle.jdbc package
– OracleConnection exists in this package as an interface
– Select the OracleConnection hyperlink to view the details
– Since which version of the database is this interface available?
– The interface is available since 8.1.7
– Select the Tree hyperlink in the Menu Items
– Scroll through the Package/Class/Interface hierarchy
– How many references to OracleResultSet do you find?
– There are two references to OracleResultSet, one is a class of the
Oracle.sqlj.driver package, the other one is an Interface of the Oracle.jdbc
package

Oracle9i: Access the Database with Java and JDBC Appendix B-3
Practice 2-1 Solution
Goal
The goal of this practice is to create a simple Java class that access to the database and run it
in an MS-DOS window. You will have to set up the environment variables to be able to
compile and run a simple Java class that interacts with the Oracle database. During this
practice you perform DDL, DML, and Query statements.
Your assignment
You create the Practice2 class. In this class, you specify the code to connect to the
database, to query a single column from a table, and to disable the autocommit option. You
then, create a new table and populate this table with some values. You commit the changes,
display the values that were populated and insert again the same set of values. After
displaying all the rows, you roll back your last changes and display the final result.
Modify the PATH environment variable
• Open Notepad
1. Type in the CLASS variable:
set PATH=< JDeveloper9i _home>\jdk\bin\;
<oracle_home>\bin\;
< JDeveloper9i_home>\jdev\bin\;%PATH%;
2. Type in the CLASSPATH variable
set CLASSPATH=.
set CLASSPATH=%CLASSPATH%;
<JDeveloper9i _home>\jdbc\lib\classes12.jar
• Save the file with the name E:\myjdbc.bat
Setting up the environment
• Open an MS-DOS window
– Click Start on the TaskBar
– Select the Start MS/DOS option
– Run the myjdbc.bat file
– Move to the E:\labs directory
Create the Java class
• Open Notepad to enter the Java code
3. Specify the packages to import
import java.sql.*;
import java.sql.SQLException.*;
import oracle.jdbc.driver.*;
4. Specify the following statements
public class Practice2
{

public static void main (String args [])


throws Exception
{

Oracle9i: Access the Database with Java and JDBC Appendix B-4
Practice 2-1 Solution (continued)
5. Register the Oracle JDBC driver
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());

6. Connect to the database using the connection, username, and password your
instructor provides you with.
// Connect to the database
// You can put a database name after the @ sign
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID",
"username","password");
Edit and Run your Java Application
• Save the file in the E:\labs directory with the name Practice2.java, using
File|Save menu option, but keep Notepad running, you will need it again.
• Compile the Practice2.java file (filename capitalization is important)
a. In the MS-DOS window, ensure the current directory is E:\labs
b. Check if the Java source file is saved to disk.
c. Compile the file using command: javac Practice2.java
d. What file is created if you successfully compile the code?
File Practice2.class now exists
• Run the Practice2 application. (again capitalization is important)
a. Run the file using command: java Practice2
b. What is displayed in the ‘DOS’ window?
The DOS prompt displays with no message
Create a query statement in the Java class
7. Add a statement to disable the autocommit mode for the connection
conn.setAutoCommit (false);
8. Create a statement object and add a SELECT statement using the executeQuery
method to query the region_id column of the table regions.
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery
("SELECT region_id FROM regions");
9. Add a loop that displays each region_id using the getInt() method.
while (rset.next ())
{

System.out.println(rset.getInt(1));
}

rest.close();
Note: At this point you should be able to compile and run your .java file

Oracle9i: Access the Database with Java and JDBC Appendix B-5
Practice 2-1 Solution (continued)
Create a DDL statement in the Java class
10. Drop the table PICTURES using the execute() method. Use the try catch
block structure to catch the exception when running the class the first time.
try
{

stmt.execute ("DROP TABLE pictures");
}

catch (SQLException e)
{

// An exception could be raised here if the table  
// did not exist already.
}

11. Create a new table using the execute() method, with the following definition:
CREATE TABLE pictures(id number (8), name varchar2(20),
pictureblob blob, picturebfile bfile)
stmt.execute ("CREATE TABLE pictures(id NUMBER(8),
name VARCHAR2(20), pictureblob BLOB, picturebfile
BFILE)");
Create a DML statement in the Java class
12. Using the executeUpdate() method, populate the PICTURES table with the
region_id from the regions table.
System.out.println("Table Insert");
stmt.executeUpdate ("INSERT INTO pictures (id)  
SELECT region_id FROM regions");

13. Add a SELECT statement using the executeQuery method to query the ID


column of the table PICTURES.
System.out.println("Start of Table query");
ResultSet rseta = stmt.executeQuery
("SELECT id FROM pictures");
14. Add a loop that displays each region_id using the getInt() method
while (rseta.next ())
{

System.out.println(rseta.getInt(1));
}

rseta.close();
15. Commit the INSERT
// commit set up
conn.commit();
System.out.println ("end of committed values");

Oracle9i: Access the Database with Java and JDBC Appendix B-6
Practice 2-1 Solution (continued)
16. Using the executeUpdate() method, populate a second time the PICTURES
table with the region_id from the regions table.
// second set of inserts
stmt.executeUpdate ("INSERT INTO pictures (id)
SELECT region_id FROM regions");
System.out.println ("committed and uncommitted
values");
17. Add a SELECT statement using the executeQuery method to query the ID
column of the table PICTURES.
ResultSet rsetb = stmt.executeQuery 
("SELECT id FROM pictures");
18. Add a loop that displays each region_id using the getInt() method.
while (rsetb.next ())
{

System.out.println(rsetb.getInt(1));
}

rsetb.close();
19. Uncommit the changes
// uncommit
conn.rollback();

20. Add a SELECT statement using the executeQuery method to query the ID


column of the table PICTURES.
System.out.println ("final committed rows");
System.out.println("Start of Table query");
ResultSet rsetc = stmt.executeQuery
("SELECT id FROM pictures");
21. Add a loop that displays each region_id using the getInt() method
while (rsetc.next ())
{

System.out.println(rsetc.getInt(1));
}

rsetc.close();
Closing resources
22. Close the statement object
stmt.close();
23. Close the connection.
conn.close();

Edit and run your Java application


• Save the file, using File > Save menu option, but keep the Notepad running, in case
compilation errors occur requiring you to edit the source to make corrections.
• Compile the Practice2.java file (filename capitalization is important)
• Run the Practice2 application. (again capitalization is important)

Oracle9i: Access the Database with Java and JDBC Appendix B-7
Practice 2-1 Solution (continued)
Complete code solution
import java.sql.*;
import java.sql.SQLException.*;
import oracle.jdbc.driver.*;

public class Practice2Sol


{

public static void main (String args [])


throws Exception
{

// 5 Register the Oracle JDBC driver


DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
// 6 Connect to the database
// (replace HOST_VALUE and SID by the appropriate
// values)
//(replace username and password by the appropriate
// values)
// -----------------------------------------------------
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@HOST_VALUE:1521:SID",
"username","password");
// 7
conn.setAutoCommit (false);
// 8 Create a Select Statement
Statement stmt = conn.createStatement ();
System.out.println("Table Regions query");
ResultSet rset = stmt.executeQuery
("SELECT region_id FROM regions");
// 9 Add a loop
while (rset.next ())
{

System.out.println(rset.getInt(1));
}

rset.close();

Oracle9i: Access the Database with Java and JDBC Appendix B-8
Practice 2-1 Solution (continued)
Complete code solution (continued)
// 10 Create a Drop Statement
try
{

stmt.execute ("DROP TABLE pictures");


}

catch (SQLException e)
{

// An exception could be raised here if the table did not


exist already.
}

// 11 Create a table containing a BLOB and a BFILE


System.out.println("Table Creation");
stmt.execute ("CREATE TABLE pictures(id NUMBER (8), name
VARCHAR2(20), pictureblob BLOB, picturebfile BFILE)");
// 12 Populate the table
System.out.println("Table Insert");
stmt.executeUpdate ("INSERT INTO pictures (id) SELECT
region_id FROM regions");
// 13 & 14 Add a SELECT and a loop
ResultSet rseta = stmt.executeQuery
("SELECT id FROM pictures");
while (rseta.next ())
{

System.out.println(rseta.getInt(1));
}

// 15 commit the insert


conn.commit();
System.out.println ("end of committed values");
// 16 Second set of inserts
System.out.println("Second Table Insert");
stmt.execute ("INSERT INTO pictures (id) SELECT region_id
FROM regions");

// 17 & 18 Add a SELECT


System.out.println("Print committed and uncommitted
values");
ResultSet rsetb = stmt.executeQuery
("SELECT id FROM pictures");
while (rsetb.next ())
{

System.out.println(rsetb.getInt(1));
}

rsetb.close();

Oracle9i: Access the Database with Java and JDBC Appendix B-9
Practice 2-1 Solution (continued)
Complete code solution (continued)
// 19 Uncommit changes
conn.rollback();
// 20 Final query
System.out.println ("final commited rows");
ResultSet rsetc = stmt.executeQuery ("SELECT id FROM
pictures");
while (rsetc.next ())
{

System.out.println(rsetc.getInt(1));
}

rsetc.close();
// Close all resources
stmt.close();
conn.close();
}

Oracle9i: Access the Database with Java and JDBC Appendix B-10
Practice 2-2 Solution (if you have time)
There is no solution for this practice

Oracle9i: Access the Database with Java and JDBC Appendix B-11
Practice 3-1 Solution
Goal
The goal of this practice is to test alternative ways to register the driver and also to
experiment other drivers.
Your Assignment
You use the Practice2 class that you used in previous lesson. In this class, you specify
the code to register the driver using the Class.forName method, You also register the
driver at launch time, and finally you change the thin driver for the OCI one.
Getting started
1. Open an MS-DOS window
– Run the myjdbc.bat file previously created
– Move to the E:\labs directory
Create the Java class
2. Open Notepad
3. Open the Practice2.java file using File|open menu option
4. Update the Java code
– Change the name of the class to Practice3thin
public class Practice3thin
– Change the following code so that you register the driver using the
Class.forName syntax:
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
// Register the Oracle JDBC driver
try{ Class.forName
("oracle.jdbc.driver.OracleDriver");
}

catch (ClassNotFoundException e){}


Edit and run your Java application
5. Save the file in the E:\labs directory with the name Practice3thin.java,
using File|Save menu option, but keep Notepad running, you will need it again.
6. Compile the Practice3thin.java file (filename capitalization is important)
a. In the Java, ensure the current directory is E:\labs
b. Check that the Java source file is saved to disk.
c. Compile the file using command: javac Practice3thin.java
d. What file is created if you successfully compiled the code?
7. Run the Practice3thin application.
a. Run the file using command: java Practice3thin
b. What is displayed in the ‘DOS’ window?

Oracle9i: Access the Database with Java and JDBC Appendix B-12
Practice 3-1 Solution (continued)
Register the driver at launch time
8. Go back to the Practice3thin file using Notepad
9. Comment out the statements registering the driver
10. Save your file
Edit and run your Java application
11. Save the file in the E:\labs directory with the name Practice3thin.java,
using File|Save menu option, but keep Notepad running, you will need it again.
12. Compile the Practice3thin.java file
13. Run the Practice3thin application.
– a. Run the file using command: java –Djdbc.drivers option
java –Djdbc.drivers=oracle.jdbc.OracleDriver
Practice3thin
– b. Did the class execute?
Using the OCI driver
14. Go back to the Practice3thin file using Notepad
– Change its name to Practice3oci
– Remove the comments in front of the registering driver statements
– Update the URL so that if uses the OCI driver
String url = "jdbc:oracle:oci:@SID";
Edit and run your Java application
15. Save the file in the E:\labs directory with the name Practice3oci.java, using
File|Save menu option, but keep Notepad running, you may need it again.
16. Compile the Practice3oci.java file
17. Run the Practice3oci application.

Oracle9i: Access the Database with Java and JDBC Appendix B-13
Practice 3-2 Overview

Oracle.gif

1-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Practice 3 Part II
Goal
The goal of this practice is to manipulate BLOB and BFILE type columns.
Your assignment
Oracle.gif is the file which is to be loaded into a BLOB column. Before loading it into
the blob column, you have a look at the file content and about its size.
Once loaded in the BLOB column, you read its content and get the size of it to verify that you
were able to retrieve the information.
Finally you read the .gif file and load it into a BFILE column.
Locate the file and determine its size
Viewing the file size
• Open Windows NT navigator
• Locate the E:\labs directory
• What is the exact size of the oracle.gif file?
In the Navigator the rounded size appears to be 138 KB
If you right-click on the filename and select the properties menu option, the exact
size of this file is 140.309 bytes.

Oracle9i: Access the Database with Java and JDBC Appendix B-14
Practice 3-2 Solution
Use the following applet and HTML file to view the picture.
Setting up the environment
1. Open an MS-DOS window
– Click Start on the taskbar
– Select the Start MS/DOS option
– Run the myjdbc.bat file
– Move to the E:\labs directory

Edit a Java applet to display the image


• Open Notepad to display the code of the file LoadPicture.java
import java.applet.Applet;
import java.awt.*;
import javax.swing.*;
public class LoadPicture extends JApplet
{

private Image picture;


// load image when applet is loaded
public void init()
{

picture = getImage( getDocumentBase(),


"oracle.gif" );
}

public void paint( Graphics g )


{
// display image
g.drawImage( picture, 50, 50, this );
// draw original image
}

// end class LoadPicture


• Close the file.

Oracle9i: Access the Database with Java and JDBC Appendix B-15
Practice 3-2 Solution (continued)
Edit an HTML file that starts the Applet to display the image
• Open the Notepad to display the code of the file LoadPicture.html
<HTML>
<HEAD>
<TITLE>
ORACLE
</TITLE>
</HEAD>
<BODY>
<APPLET CODE="LoadPicture.class" width = "750"
height = "500">
</APPLET>
</BODY>
</HTML>
• Close the file.
Compile the Java class and run the applet
1. Compile the Java program
Type the following syntax in the MS-DOS window:
E:\Labs> javac LoadPicture.java

2. Run the HTML file with appletviewer


Type the following syntax in the MS-DOS window:
E:\labs> appletviewer LoadPicture.html

Oracle9i: Access the Database with Java and JDBC Appendix B-16
Practice 3-2 Solution (continued)
Start JDeveloper.
• Double-click the JDeveloper icon on the desktop
Open a workspace in JDeveloper.
• Close previously opened workspace, if any.
• Open the workspace Lesson03.jws and open the project Blob.jpr.
Create class LobToTable and add statement and connection instance variables.
• Create a new class, LobToTable and accept the default package name
• Add an import statement to import the JDBC classes.
Select Projects | Project Properties in the menu options
Select the Libraries option
Scroll down and choose the Oracle JDBC line, then click OK
Create the database connection.
1. Add a method, getConnection() to connect to the database using the URL,
username, and password your instructor provided you with.
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:ORCL",
"username", "password");
2. Add a System.out.println statement just after loading the driver; print a
message that will let you know that you have loaded the driver when you test your
class.
System.out.println("I am connected");
//Diagnostic print
3. Set autocommit off for the connection object
conn.setAutoCommit (false);
4. Create a statement object
Statement stmt = conn.createStatement ();
5. Delete all the rows that exist in table temp_large and commit the changes
stmt.execute ("DELETE FROM pictures)";
conn.commit();
6. Populate the columns name and pictureblob of table pictures with the value
‘Oracle’ and a BLOB locator using the empty_blob() method
stmt.execute ("INSERT INTO pictures (name,
pictureblob) values ('Oracle', EMPTY_BLOB())");
7. Select the BLOB locator from the table
ResultSet rset = stmt.executeQuery ("SELECT
pictureblob FROM pictures WHERE name = 'Oracle'");
if (rset.next ())
BLOB blob = ((OracleResultSet)rset).getBLOB (1);
8. Declare a file handler for the oracle.gif file
File binaryFile = new File("E:/labs/oracle.gif");

Oracle9i: Access the Database with Java and JDBC Appendix B-17
Practice 3-2 Solution (continued)
9. Create a FileInputStream object to read the contents of the GIF file and an
OutputStream object to write the BLOB as a stream
FileInputStream istream = new FileInputStream
(binaryFile);
OutputStream ostream =
blob.getBinaryOutputStream ();
10. Call getBufferSize() to retrieve the ideal buffer size (according to calculation by
the JDBC driver) to use in writing to the BLOB, then create the buffer byte array.
int size =blob.getBufferSize();
System.out.println(size);
byte[] buffer = new byte[size];

11. You use the read() method to read the GIF file to the byte array buffer, then you use
the write() method to write it to the BLOB.
while ((length = istream.read(buffer)) != -1)
ostream.write(buffer, 0, length);
12. Close the inputstream and outputstream
istream.close();
ostream.close();
13. Test your application by checking the BLOB’s size
System.out.println ("Number of bytes written = "
+blob.length());
14. Close all resources
rset.close();
stmt.close();
conn.close();

Oracle9i: Access the Database with Java and JDBC Appendix B-18
Practice 3-2 (continued)
Complete Code Solution
/*
* This program writes the GIF file Oracle.gif to a BLOB.
*/
package mypackage1;
import java.sql.*;
import java.io.*;
import java.util.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;
//needed for new BLOB class

public class LobToTable


{

public static void main (String args [])


throws Exception
{

// Register the Oracle JDBC driver


DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
// Connect to the database
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID","username",
"password");
System.out.println("I am connected"); //Diagnostic
print
conn.setAutoCommit (false);
// It's faster when auto commit is off
Statement stmt = conn.createStatement ();
stmt.execute ("DELETE FROM pictures");
conn.commit();
stmt.execute ("INSERT INTO pictures (name,
pictureblob) VALUES ('Oracle', EMPTY_BLOB())");
// Query the blob column
ResultSet rset = stmt.executeQuery ("SELECT
pictureblob FROM pictures WHERE name = 'Oracle'");
if (rset.next ())
{

BLOB blob = ((OracleResultSet)rset).getBLOB (1);


// Declare a file handler for the oracle.gif file
File binaryFile = new File
("E:/labs/oracle.gif");

Oracle9i: Access the Database with Java and JDBC Appendix B-19
Practice 3-2 Solution (continued)
Complete Code Solution (continued)
// Create a FileInputStream object to read the contents of
// the GIF file

FileInputStream istream = new FileInputStream


(binaryFile);
// Create an OutputStream object to write the BLOB as a
// stream
OutputStream ostream =
blob.getBinaryOutputStream ();
// Call getBufferSize() to retrieve the ideal buffer size
int size =blob.getBufferSize();
System.out.println("ideal buffer size : " +
size);
byte[] buffer = new byte[size];
int length = 0;
// You use the read() method to read the GIF file to
// the byte array buffer, then you use the write()
// method to write it to the BLOB..
System.out.println("Please wait this operation
may take some time...");
while ((length = istream.read(buffer)) != -1)
ostream.write(buffer, 0, length);
// Close the inputstream and outputstream
istream.close();
ostream.close();

// Display the BLOB's size


System.out.println ("Number of bytes
written = " +blob.length());
}

// Close all resources


rset.close();
stmt.close();
conn.close();
}

Oracle9i: Access the Database with Java and JDBC Appendix B-20
Practice 3-3 Solution
Your assignment
The content of the Oracle.gif file is now loaded in the BLOB column of the PICTURES
table. You query the table to retrieve the content of the BLOB column and display the size of
the stored information.
1. Create a second application named LobToSQL and include the necessary Java code to
do the following:
a) Register the Oracle JDBC
b) Connect to the database
c) Create a Statement
2. Create a BLOB variable, query the BLOB column, to get the BLOB locator into a result
set
BLOB blob = null;
ResultSet rset = stmt.executeQuery ("SELECT pictureblob
FROM pictures");
if (rset.next())
{

//Get the blob data ­ cast to OracleResult set to
// retrieve the data in Oracle.sql format
blob = ((OracleResultSet)rset).getBLOB (1);
}

3. Get the length of the BLOB, then print its length


long length = blob.length();
System.out.println("The blob length is " + length);

4. Read the BLOB into a byte array, then print its length


int size =blob.getBufferSize();
byte[] buffer = new byte[size];
buffer = blob.getBytes(1, size);
System.out.println("The array length is " + 
buffer.length);
5. Close all resources
rset.close();
stmt.close();
conn.close();

Oracle9i: Access the Database with Java and JDBC Appendix B-21
Practice 3-3 Solution (continued)
Complete Code Solution
package mypackage1;
import java.sql.*;
import java.io.*;
import java.util.*;
import oracle.jdbc.driver.*;
import oracle.sql.*;
import oracle.sql.BLOB;
{

public static void main (String args [])


throws Exception
{

// Register the Oracle JDBC driver


DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
// Connect to the database
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID",
"username","password");
System.out.println("I am connected");
// It's faster when auto commit is off
conn.setAutoCommit (false);
// Create a Statement
Statement stmt = conn.createStatement ();
// Select the BLOB, get the BLOB locator into a result
// set
BLOB blob = null;
ResultSet rset = stmt.executeQuery ("SELECT pictureblob
FROM pictures WHERE name=‘Oracle’");
if (rset.next())
{

//Get the blob data - cast to OracleResult set to


// retrieve the data in Oracle.sql format
blob = ((OracleResultSet)rset).getBLOB (1);
}

// Get the length of the blob, then print its length


long length = blob.length();
System.out.println("The blob length is " + length);
//Read the blob into a byte array, then print its length
int size =blob.getBufferSize();
byte[] buffer = new byte[size];
System.out.println("The array length is " +
buffer.length);
//Close all resources
rset.close();
stmt.close();
conn.close();
}

Oracle9i: Access the Database with Java and JDBC Appendix B-22
Practice 3-4 Solution
Your assignment
You want to load the content of the oracle.gif file in a BFILE column and check that
the information is correctly stored in the table by displaying it. For this practice you will use
a directory object that points to the directory holding the oracle.gif file on the server.
1. Create a third application named GifToBfile.
a. Register the Oracle JDBC
b. Connect to the database
c. Disable autocommit mode

import java.sql.*;
import java.io.*;
import java.util.*;
import oracle.jdbc.*;
import oracle.sql.*;
public class GifToBfile
{
public static void main (String args [])
throws Exception
{
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
String url = "jdbc:oracle:thin:@hostname:1521:SID";
// Connect to the database
Connection conn = DriverManager.getConnection
(url,"username", "password");
// It's faster when auto commit is off
conn.setAutoCommit (false);
System.out.println ("I am connected");

• Compile your application

Oracle9i: Access the Database with Java and JDBC Appendix B-23
Practice 3-4 Solution (continued)
2. Update the PICTURES table and set the picturebfile column with the following
value: (bfilename ('TEST_DIR', 'oracle.gif')).
stmt.execute ("UPDATE pictures SET picturebfile=
(bfilename ('TEST_DIR', 'oracle.gif'))");
3. Query the name and picturebfile columns using a result set and print the content
of each column
ResultSet rset = stmt.executeQuery
("SELECT name, picturebfile FROM pictures");
while (rset.next ())
{

String x = rset.getString (1);


BFILE bfile = ((OracleResultSet)rset).getBFILE(2);
System.out.println ("name = "+x + " " + bfile);
4. Use the getName(),fileExists(), isFileOpen(), and length() methods
for the bfile object to display the corresponding information before and after
opening the bfile.
Display the name of the .gig file Get the length of the BLOB, then print its length.
System.out.println("bfile name "+ bfile.getName());
System.out.println("bfile exists "+ bfile.fileExists());
System.out.println("bfile open "+ bfile.isFileOpen());
System.out.println("open file ");
bfile.openFile();
System.out.println("bfile open "+ bfile.isFileOpen());
long len = bfile.length();
System.out.println("bfile length "+ len);
5. The following code displays the content of the .gif file:
byte [] buffer = new byte[(int)len];
System.out.println
("Wait for the image to be loaded...");
instream.read(buffer);
instream.close();
bfile.close();

javax.swing.JOptionPane.showInputDialog(new JLabel(new
ImageIcon(buffer)));
}

6. Close all resources


// Close input stream and file handler 
System.out.println("bye");
rset.close();    
stmt.close();    
conn.close();
} catch ( SQLException e) { System.out.println("caught 
SQLerror: " + e ); }
catch ( IOException e) { System.out.println("caught 
IOerror: " + e ); }
}

Oracle9i: Access the Database with Java and JDBC Appendix B-24
Practice 3-4 Solution (continued)
Complete Code Solution
import java.sql.*;
import oracle.jdbc.driver.*;
import oracle.sql.BFILE;
import java.io.*;
import javax.swing.*;

public class GifToBfile


{

public static void main( String [] args) throws


SQLException {

try {
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
Connection conn =
DriverManager.getConnection("jdbc:oracle:thin:@myhost:7
021:SID", "username", "password");
System.out.println("I am connected");
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("update pictures set picturebfile =
bfilename('TEST_DIR','oracle.gif')");

ResultSet rset = stmt.executeQuery


(" SELECT name, picturebfile FROM pictures");
while ( rset.next())
{

String x = rset.getString(1);
BFILE bfile = ((OracleResultSet) rset).getBFILE(2);
System.out.println("name " + x + " " + bfile);
System.out.println("bfile name "+ bfile.getName());
System.out.println("bfile exists "+ bfile.fileExists());
System.out.println("bfile open "+ bfile.isFileOpen());

System.out.println("open file ");

bfile.openFile();
System.out.println("bfile open "+ bfile.isFileOpen());

long len = bfile.length();


System.out.println("bfile length "+ len);

InputStream instream = bfile.getBinaryStream();

byte [] buffer = new byte[(int)len];


System.out.println
("Wait for the image to be loaded...");

Oracle9i: Access the Database with Java and JDBC Appendix B-25
Practice 3-4 Solution (continued)
Complete Code Solution (continued)
instream.read(buffer);
instream.close();
bfile.close();

javax.swing.JOptionPane.showInputDialog(new JLabel(new
ImageIcon(buffer)));
}

System.out.println("bye");
rset.close();
stmt.close();
conn.close();

} catch ( SQLException e) { System.out.println("caught


SQLerror: " + e ); }
catch ( IOException e) { System.out.println("caught
IOerror: " + e ); }
}

Oracle9i: Access the Database with Java and JDBC Appendix B-26
Practice 4-1 Solution
Goal
The goal of this practice is create a scrollable result set and navigate through the rows in an
HTML user interface.
Your assignment
You will create a Class that queries the database and you will display the result using a UI
(in the form of a servlet) that has been created for you, allowing you to navigate in the result
set.
Open lesson04.jws and select Navigate.jpr.
1. First, create a class to contain the JDBC code.
a. Create a new class file. Name it OrdersQuery.java and accept all other
defaults.
b. Open OrdersQuery.java in the editor.
2. You will create four methods in this class: setConnection, getOrders,
getOrderItems, and close.
a. Create four private instance variables to contain the Connection,
PreparedStatement, Statement, and ResultSet objects. Initialize all variables to
null.
b. Create the first method, setConnection(). This void method will be passed a
URL, username, and password from the servlet and create a connection for the
user.
i. Set the Statement variable created in Step 2a to be
TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY.
ii. Set the PreparedStatement variable created in Step 2a to select all the
columns in the ORDER_ITEMS table, where the ORDER_ID is dynamic.
iii.Set the ResultSet variable created in Step 2a to select all the columns in
the ORDERS table, ordered by the ORDER_ID column.
c. Create the method close(). This method should return void and close the
Connection object, Statement object, and ResultSet object if they are not null.
d. Compile and save the class. You will need to import java.sql.* in order to compile.
e. Next, create the getOrders method. This method will return rows from the
ORDERS table, formatted in an HTML table row for use in the servlet. The method
will take two arguments, String rsaction and int actionnum. These
arguments will be passed to the method depending on what the user selects in the
servlet.
i. Create a String method variable to store the value of the returned rows, and
initialize it to an empty string.
ii. If the actionnum argument is null, the user must have pressed a ‘previous’,
‘next’, ‘first’, or ‘last’ button in the servlet. Therefore, check if the
rsaction is one of these strings and navigate the Resultset as
necessary. Also, make sure that the resultset is not currently on the last
row when trying to navigate to the next row, the first row when trying to
navigate to the previous row, etc.
iii.Otherwise, if the actionnum argument is not null, the user must have
selected a row to ‘jump’ to. If so, create an int variable to store the value of
the current row in the ResultSet. Check to ensure that the actionnum
variable is not already the current row in the ResultSet and if it is not,
navigate the ResultSet to the value of the actionnum variable.

Oracle9i: Access the Database with Java and JDBC Appendix B-27
iv. Next, return the row in the ResultSet. Create String variables for the
ORDER_ID, ORDER_MODE, ORDER_STATUS, and ORDER_TOTAL
columns and set the variables equal to the value of their corresponding
column in the ResultSet.
v. Generate the row to be returned to the servlet. Set the variable created in step
“i” equal to the values of the variables in the previous step and the row
number for the row, formatting in an HTML table. The line of code should
look like this, replacing your variable names where appropriate:
"<tr><td>" + orderid + "</td><td>" + ordermode + 
"</td><td>" + orderstatus + "</td><td>" +
ordertotal + "</td><td>" + rs1.getRow() +
"</td></tr>";
f. Finally, create the getOrderItems method. This method will use a prepared
statement to display in a table the order items for whichever orderid is selected
in the servlet.
i. Create the getOrderItems method in the class. This method will return
the order item rows in an HTML table (in a String) for display in the servlet,
and accepts the String value of the selected orderid from the servlet.
ii. Use the setInt() method of PreparedStatement to parse the integer
value of order_id.
iii. Create a new method variable of type ResultSet and set it equal to the
value of the executed query of the PreparedStatement.
iv. Create a StringBuffer object and initialize it as follows:
StringBuffer itemrow = new StringBuffer(1000);
v. Using a while loop, loop through all records in the ResultSet object.
As you iterate through each row, fetch the ORDERID, LINEITEMID,
PRODUCTID, UNITPRICE, QUANTITY and DISCOUNT values and save
them in String variables by the same name. The values can be retrieved using
the number of their column, such as: rs.getString(1);
vi. Next in the while loop, add the following code:
itemrow.append += "<tr><td>" + orderid + 
"</td><td>" + lineitemid + "</td><td>" + productid
+ "</td><td>" + unitprice + "</td><td>" + quantity
+ "</td><td>" + discount + "</td></tr>“
Notice that you are creating a new HTML table row for each row returned
from the result set.
vii. Now outside of the while loop, close the ResultSet object.
viii.Return itemrow.toString() from the method.
ix. Compile to test the application.
g. Run ResultDisplay.java and use the HTML controls in the servlet to
navigate through the result set.

Oracle9i: Access the Database with Java and JDBC Appendix B-28
Practice 4-1 Solution (continued)
Complete code solution
import java.sql.*;
public class OrdersQuery
{

private Connection conn = null;


private PreparedStatement ps = null;
private Statement stmt = null;
private ResultSet rs1 = null;

public OrdersQuery()
{

public void setConnection (String url, String username,


String password)
throws ClassNotFoundException, SQLException {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, username,
password);
stmt =
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ps = conn.prepareStatement
("SELECT * FROM order_items WHERE ORDER_ID = ?");
rs1 = stmt.executeQuery
("SELECT o.* FROM orders o ORDER BY o.order_id");
}

public String getOrders(String rsaction, int actionnum)


throws SQLException{
String ordrow = "";
/*
Statement stmt =
conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultS
et.CONCUR_READ_ONLY);
String ordqry = "SELECT o.* FROM orders o";
ResultSet rs1 = stmt.executeQuery(ordqry);
*/
if (actionnum == 0) {
if (rsaction.equals("previous")) {
if (!rs1.isFirst()) {
rs1.previous();
}

Oracle9i: Access the Database with Java and JDBC Appendix B-29
Practice 4-1 Solution (continued)
Complete code solution
else if (rsaction.equals("next")) {
if (! rs1.isLast()) {
rs1.next();
}

else if (rsaction.equals("last")) {
rs1.last();
}

else {
rs1.first();
}

else {
int currRow = rs1.getRow();
if (!rs1.absolute(actionnum))
{

rs1.absolute(currRow);
}

String orderid = rs1.getString(1);


String ordermode = rs1.getString(3);
String orderstatus = rs1.getString(5);
String ordertotal = rs1.getString(6);

ordrow = "<tr><td>" + orderid + "</td><td>" + ordermode +


"</td><td>" + orderstatus + "</td><td>" + ordertotal +
"</td><td>" + rs1.getRow() + "</td></tr>";
return ordrow;
}

public String getOrderItems(String order_id) throws


SQLException {
ps.setInt(1, Integer.parseInt(order_id));
ResultSet rs = ps.executeQuery();

Oracle9i: Access the Database with Java and JDBC Appendix B-30
Practice 4-1 Solution (continued)
Complete code solution
StringBuffer itemrow = new StringBuffer(1000);
while (rs.next()) {
String orderid = rs.getString(1);
String lineitemid = rs.getString(2);
String productid = rs.getString(3);
String unitprice = rs.getString(4);
String quantity = rs.getString(5);
String discount = "0";//rs.getString(6);

itemrow.append("<tr><td>" + orderid + "</td><td>" +


lineitemid + "</td><td>" + productid +
"</td><td>" + unitprice + "</td><td>" + quantity +
"</td><td>" + discount +
"</td></tr>");
}

rs.close();
//ps.close();
return itemrow.toString();
}

public void close() throws SQLException {

// Close the connection object


if (stmt != null) stmt.close();
if (ps != null) ps.close();
if (conn != null) conn.close();
}

Oracle9i: Access the Database with Java and JDBC Appendix B-31
Practice 5-1 Solution
Goal
The goal of this practice is to use the JNDI service to connect to a database.
Your Assignment
You use already created Java files, and complete the existing code with additional statements
in order to use the JNDI service. The RegisterDataSource.java file creates a
temp/jndi directory with a file that contains the physical data sources information
needed to connect to a database.
The JndiConnection.java file establishes the connection based on a logical name
specified in the file by performing a lookup action in the file created in the previous action,
where the physical database information is stored.
To be able to run this practice, you need to had some specific .jar files to your project.
Setting up the environment
• Close any previously opened workspace in JDeveloper
• Open the workspace named Lesson05
• This workspace contains a Jndi project
• Add the following .jar files to your project
• Select Project | Project Settings from the menu
• Select the Libraries node
• Click New to add a library
• In the Library name type “JNDI Provider”
• Click Edit on the Class Path item
• Click Add Entry
• Locate the e:\labs\jndi\ directory
• Select fscontext.jar and providerutil.jar files
• Click on the Select button
• Verify that both .jar files appear in the Edit Class Path dialog and click OK
• Verify that both jar files appear in the Class Path and click OK
• The JNDI Provider should now appear in the Selected Libraries
• Then click OK to exit Project Settings
• Make sure that only the RegisterDataSource entry is in the system navigator, otherwise
remove other files (from IDE only)
Completing the RegisterDataSource class
This Java file when executed creates a temp/jndi directory on your system (if needed)
and create a datasource specification in the .bindings file
• Edit the RegisterDataSource.java file
1. Complete the following statements in the Main method
– String dsName = Type any name.
– String dbName = ""; //indicate the name of the SID
– String host = ""; // indicate the name of the host
– int port = ;// indicate the port number
String dsName = "ora9i";
String dbName = "iasdb";//indicate the name of the SID
String host="localhost";//indicate the name of the host
int port = 1521; //indicate the port number
Oracle9i: Access the Database with Java and JDBC Appendix B-32
Practice 5-1 Solution (continued)
• Edit the RegisterDataSource.java file(continued)
2. Locate the following comment in the Main method:
// Display the content of the database variables
- Use the println() method to display the

content of the previous variables


System.out.println("Host: " + host);
System.out.println("Port: " + port);
System.out.println("Database: " +
dbName);
System.out.println("Pooled: " + pooled);
- Display the content of the jndiURL variable too

System.out.println("Jndi URL Path: " + jndiURL);


• Compile and run the RegisterDataSource class
– Did it compile and run successfully?
– What is displayed in the log window?
Here is an example of what could be displayed
Host: ed-pdsun3.us.oracle.com
Port: 1521
Database: iasdb
Pooled: false
Jndi URL Path: file:/temp/jndi
Register DataSource: jdbc/ora9i
Done!
Process exited with exit code 0.
• Using Windows NT explorer, look for a /temp/jndi library.
• Does the library exist?
• Is there a file in the jndi directory, and what is its name?
The file is called .bindings
• Open the file to display its content.
Completing the JndiConnection class
This Java file when executed uses the dsName variable and performs a lookup in the
.bindings file previously created to get the necessary information to establish a database
connection. Then it performs a query on the REGIONS table.
• Open the file named JndiConnection.Java
Use the File | Open option in the menu
• Edit JndiConnection.java file
• Complete the following statements in the Main method
1. Create 5 null variables for
InitialContext
Connection
PreparedStatement
ResultSet
DataSource
Oracle9i: Access the Database with Java and JDBC Appendix B-33
Practice 5-1 Solution (continued)
InitialContext context = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
DataSource ds = null;

2. Complete the following statements in the Main method


String dsName = Type a name that maps the one used in the RegisterDataSource
class.
3. Create a datasource using the following syntax
Ds = (DataSource) context.lookup(dsName);
4. Create a connection using your username/password
conn = ds.getConnection("username", "password");
5. Create a prepare statement that queries all columns of Countries table using the
regionId parameter
pstmt = conn.prepareStatement("SELECT * FROM
countries WHERE region_id = ?");
6. Use the setXXX method to supply a value to SELECT statement parameter, based on
the following syntax: pstmt.setXXX(index, value);
pstmt.setInt(1, regionId);
rset = pstmt.executeQuery();
7. Display a title for your query
System.out.println("List of Countries in Region " +
regionId);
8. Create a while loop to display each of the rows retrieved by the query
while (rset.next()) {
System.out.println(rset.getString("country_id")+" "+
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

Oracle9i: Access the Database with Java and JDBC Appendix B-34
Practice 5-1 Solution (continued)
Complete Code Solution
import java.sql.SQLException;
import javax.naming.NamingException;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
import javax.sql.DataSource;
import oracle.jdbc.pool.OracleDataSource;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;
import java.io.File;
public class RegisterDataSource {

public static InitialContext getContext(String url) throws


NamingException
{

Hashtable env = new Hashtable ();


env.put (Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, url);
return new InitialContext(env);
}

public static DataSource getDataSource(String host, int


port, String dbName, boolean pooled)
throws SQLException
{

OracleDataSource ods = pooled ? new


OracleConnectionPoolDataSource() : new
OracleDataSource();
ods.setDriverType("thin");
ods.setNetworkProtocol("tcp");
ods.setServerName(host);
ods.setPortNumber(port);
ods.setDatabaseName(dbName);
return ods;
}

public static void main(String[] args) {


InitialContext context = null;

// 1 Complete the following statements


String dsName = ""; // Type any name
String dbName = ""; //indicate the name of the SID
String host = ""; // indicate the name of the host
int port = ; //indicate the port number
Oracle9i: Access the Database with Java and JDBC Appendix B-35
Practice 5-1 Solution (continued)
Complete Code Solution (continued)
String jndiURL = "file:/temp/jndi";
boolean pooled = false;
File f = new File("/temp/jndi");
if (!f.exists()) f.mkdirs();
//
for (int i = 0; i < args.length; i++)
{

if (args[i].equals("-ds"))
{

dsName = ((i+1) <= args.length) ? args[++i] : dsName;


}

else if (args[i].equals("-db"))
{

dbName = ((i+1) <= args.length) ? args[++i] : dbName;


}

else if (args[i].equals("-h"))
{

host = ((i+1) <= args.length) ? args[++i] : host;


}

else if (args[i].equals("-p"))
{

port = ((i+1) <= args.length) ?


Integer.parseInt(args[++i]) : port;
}

else if (args[i].equals("-u"))
{

jndiURL = ((i+1) <= args.length) ? args[++i] : jndiURL;


}

else if (args[i].equals("-pool"))
{

pooled = true;
}

Oracle9i: Access the Database with Java and JDBC Appendix B-36
Practice 5-1 Solution (continued)
Complete Code Solution (continued)
// 2 Display the content of the database variables (Host-
Port-Database-Pooled-Jndi URL)
DataSource dataSource = null;
try {
context = getContext(jndiURL);
dataSource = getDataSource(host, port, dbName, pooled);
if (pooled)
{

dsName = "jdbc/pooled/" + dsName;


}

else
{

dsName = "jdbc/" + dsName;


}

System.out.println("Register DataSource: " + dsName);


context.rebind(dsName, dataSource);
}

catch (Exception e)
{

e.printStackTrace();
}

System.out.println("Done!");
}

Oracle9i: Access the Database with Java and JDBC Appendix B-37
Practice 5-1 Solution (continued)
Complete Code Solution (continued)
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
import oracle.jdbc.pool.OracleDataSource;

public class JndiConnection {


public static InitialContext getContext(String url) throws
NamingException
{

Hashtable env = new Hashtable ();


env.put (Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, url);
return new InitialContext(env);
}

public static void main(String[] args)


{

InitialContext context = null;


Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
DataSource ds = null;

String dsName = ""; //Type a name that maps the one //


used in the RegisterDataSource class.
String jndiURL = "file:/temp/jndi";
int regionId = 1; // Specify a value between 1 and 4
try {
context = getContext(jndiURL);
dsName = "jdbc/" + dsName;
System.out.println("Lookup DataSource: " + dsName);

ds = (DataSource) context.lookup(dsName);
conn = ds.getConnection("username", "password");

pstmt = conn.prepareStatement("SELECT * FROM countries


WHERE region_id = ?");

Oracle9i: Access the Database with Java and JDBC Appendix B-38
Practice 5-1 Solution (continued)
Complete Code Solution (continued)

pstmt.setInt(1, regionId);

rset = pstmt.executeQuery();
System.out.println("List of Countries in Region " +
regionId);
while (rset.next()) {
System.out.println(rset.getString("country_id") + " "
+ rset.getString("country_name") +
" " + rset.getString("region_id"));
}

catch (Exception e)
{

e.printStackTrace();
}

finally
{

try { if (rset != null) rset.close(); } catch


(SQLException e) {}
try { if (pstmt != null) pstmt.close(); } catch
(SQLException e) {}
try { if (conn != null) conn.close(); } catch
(SQLException e) {}
}

System.out.println("Done!");
}

Oracle9i: Access the Database with Java and JDBC Appendix B-39
Practice 5-2 Solution
Goal
The goal of this practice is to illustrate the pool connection mechanism.
Your assignment
You use an already created Java files, and complete the existing code with additional
statements. You need to rerun the RegisterDataSource class in order to create a new
entry in the JNDI service.
Then you complete the code of a new class named JndiPooledConnection.java.
This class opens a physical connection, and then a logical one. Once the connection is
established, you execute a query statement to retrieve rows of the COUNTRIES table. After,
you close the logical and then the physical connection.
In the second step, after closing your logical connection, you reopen a new logical one and
resubmit your SELECT statement. And finally after having closed your logical and physical
connection, you try to reopen a logical one.
Setting up the environment
• Open the workspace named Lesson05 if closed
• Run the RegisterDataSource class with a program argument set to –pool
– Select Project Settings from the menu
– Select the Runner node
– Type –pool in the Program Arguments and click OK
– Run RegisterDataSource to create a new entry in the Jndi service
• Open the file named JndiPooledConnection.java
Use the File | Open option in the menu
• Edit JndiPooledConnection.java file and view its content
• Complete the following statements in the Main method
1. Create 6 null variables for
InitialContext
Connection
PreparedStatement
ResultSet
ConnectionPoolDataSource
PooledConnection

InitialContext context = null;


Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
ConnectionPoolDataSource ds = null;
PooledConnection pooledConn = null;

Oracle9i: Access the Database with Java and JDBC Appendix B-40
Practice 5-2 Solution (continued)
2. Complete the following statement in the Main method
String dsName = “”Type a name that maps the one used in the
RegisterDataSource class.
3. Create a data source using the following syntax
ds = (ConnectionPoolDataSource) context.lookup(dsName);
4. Create a pooled connection using your username/password
pooledConn = ds.getPooledConnection
("Username", "password");
5. Establish the connection for the pooledConnection
conn = pooledConn.getConnection();
6. Create a prepare statement that queries all columns of Countries table using the
regionId parameter.
pstmt = conn.prepareStatement("SELECT * FROM
countries WHERE region_id = ?");
7. Use the setXXX method to supply a value to SELECT statement parameter, based
on the following syntax: pstmt.setXXX(index, value);
pstmt.setInt(1, regionId);
8. Submit the prepared statement, and display a title for your query
rset = pstmt.executeQuery();
System.out.println("List of Countries in Region " +
regionId);
9. Create a while loop to display each of the rows retrieved by the query
while (rset.next()) {
System.out.println(rset.getString("country_id")+" "+
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

10. In the finally block, based on the following syntax close the Result set, the
prepared statement, the logical connection and the physical connection objects.
try { if (rset != null) rset.close(); } catch
(SQLException e) {}
finally
{

try { if (rset != null) rset.close(); } catch


(SQLException e) {}
try { if (pstmt != null) pstmt.close(); } catch
(SQLException e) {}
try { if (conn != null) conn.close(); } catch
(SQLException e) {}
try { if (pooledConn != null) pooledConn.close(); }
catch (SQLException e) {}
}

• Compile and run the JndiPooledConnection class


– Did it compile and run successfully?
– What is displayed in the log window?

Oracle9i: Access the Database with Java and JDBC Appendix B-41
Practice 5-2 Solution (continued)
Testing the pooled connection
• After the ResultSet loop, close the logical connection
conn.close();
• Reopen the logical connection
conn = pooledConn.getConnection();
• Cut and paste the code that performs the Query and displays the result
rset = pstmt.executeQuery();
System.out.println("List of Countries in Region "
+ regionId);
while (rset.next()) {
System.out.println(rset.getString("country_id")
+ " " +
rset.getString("country_name") + " " +
rset.getString("region_id"));
}

• Compile and run the RegisterDataSource class


– Did it compile and run successfully?
– What is displayed in the log window?
• After the first ResultSet loop, after the close of the logical connection, close the pooled
connection
PooledConn.close();
• Compile and run the RegisterDataSource class
– Did it compile and run successfully?
– What is displayed in the Log window?
– Explain the error

Oracle9i: Access the Database with Java and JDBC Appendix B-42
Practice 5-2 Solution (continued)
Complete code solution
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
import javax.sql.ConnectionPoolDataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
import oracle.jdbc.pool.OracleConnectionPoolDataSource;

public class JndiPooledConnection {


public static InitialContext getContext(String url) throws
NamingException
{

Hashtable env = new Hashtable ();


env.put (Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, url);
return new InitialContext(env);
}

public static void main(String[] args)


{

InitialContext context = null;


Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
ConnectionPoolDataSource ds = null;
PooledConnection pooledConn = null;
String dsName = ""; //Type a name that maps the one //
used in the RegisterDataSource class.
String jndiURL = "file:/temp/jndi";
int regionId = ; //Specify a value between 1and 4
try {
context = getContext(jndiURL);
dsName = "jdbc/pooled/" + dsName;
System.out.println("Lookup DataSource: " +
dsName);
ds = (ConnectionPoolDataSource)
context.lookup(dsName);

pooledConn = ds.getPooledConnection("username",
"password");

Oracle9i: Access the Database with Java and JDBC Appendix B-43
Practice 5-2 Solution (continued)
Complete code solution (continued)
conn = pooledConn.getConnection();
pstmt = conn.prepareStatement
("SELECT * FROM countries WHERE region_id = ?");

pstmt.setInt(1, regionId);

rset = pstmt.executeQuery();
System.out.println("List of Countries in Region "
+ regionId);
while (rset.next()) {
System.out.println(rset.getString("country_id") + " "
+ rset.getString("country_name")
+ " " + rset.getString("region_id"));
}

conn.close();
conn = pooledConn.getConnection();

while (rset.next()) {
System.out.println(rset.getString("country_id") + " "
+ rset.getString("country_name")
+ " " + rset.getString("region_id"));
}

catch (Exception e)
{

e.printStackTrace();
}

finally
{

try { if (rset != null) rset.close(); } catch


(SQLException e) {}
try { if (pstmt != null) pstmt.close(); } catch
(SQLException e) {}
try { if (conn != null) conn.close(); } catch
(SQLException e) {}
try { if (pooledConn != null) pooledConn.close(); }
catch (SQLException e) {}
}

System.out.println("Done!");
}

Oracle9i: Access the Database with Java and JDBC Appendix B-44
Practice 6 Solution
Goal
The goal of this practice is to create a Java Stored procedure in the database and to call it
from a database trigger.
Your assignment
You create a Java Stored procedure that logs into a log table the updates that are made on the
PROMOTION_ID column of the ORDERS table when the ORDER_MODE is online;
You create a log table in order to record these changes.
You create a trigger on the Orders table that fires when an update on the PROMOTION_ID
column is made for orders that are ‘online’ orders. This trigger calls the Java stored
procedure that keeps track of the changes.
Setting up the environment
• Close any previously opened workspace in JDeveloper
• Open the workspace named Lesson6
• Create a new project named StoredProc
• Make sure that the required libraries are included in the project.
• Create a new Connection
– In the Database node of the system navigator, right-click and select the New
connection option
– Fill in the dialogs specifying your usual hostname, username, and password
– Test the connection to make sure it works
• From File | New menu option, select Objects and choose SQL File
• Use this SQL file to type in the SQL statement in order to create a table name
order_audit with five columns allowing you to store the order_id, the order_total, the
new promotion_id, the date at which the change is made and the use that made the
change.
CREATE TABLE order_audit(
order_id    number(12),
order_total number(8,2),

new_promotion_id number(6),
update_date date,
username varchar2(15));
Creating the Java stored procedure

• Create a new class and name it DbOrder.


• Make sure that only Public is selected in the Optional attributes properties.
• Import the necessary packages
import java.sql.*;
import java.io.*;
import oracle.jdbc.*;
• Create a public static method
– Name it logPromotion
– Define three input parameters for the orderid, the ordertotal and promotionid values.
public static void logPromotion (int orderID, 
float oldOrderTotal, int newPromotionId)
• Add a throws SQLException statement
throws SQLException {
• Create a default internal connection
Connection conn =
DriverManager.getConnection("jdbc:default:connection:");

Oracle9i: Access the Database with Java and JDBC Appendix B-45
Practice 6 Solution (continued)
• Create a string variable that contains an Insert statement in the order_audit table and
takes three parameters plus today’s date and the user name.
String sql = "INSERT INTO order_audit VALUES (?, ?, ?,
sysdate,user)";
• Define a Prepared statement object with the sql statement variable.
try {
PreparedStatement pstmt = conn.prepareStatement(sql);
• Pass each input parameter to the prepared statement object using the setXXX methods
and the position of each parameter in the table.
pstmt.setInt(1, orderID);
pstmt.setFloat(2, oldOrderTotal);
pstmt.setInt(3, newPromotionId);
• Execute the statement using executeUpdate() method
pstmt.executeUpdate();
• Close the statement
pstmt.close();
• End the code
} catch (SQLException e)
{System.err.println(e.getMessage());}
Deploying the Java stored procedure
• Create a new deployement profile for stored procedures.
• Accept defaults values and click OK.
• Add a Stored procedure to your deployment profile
– Right-click on the Deployment profile
– Select the logPromotion method in the DbOrder Class
– Click OK
– A new entry appears in the Deployment profile with the method name
• Display the PL/SQL generated for publishing
– Right-click the method name
– Select the Edit Method Signature
– Select the Preview SQL Statement
• Deploy the Deployment profile in the database
– Right-click the Deployment profile and deploy using the connection created
previously

Oracle9i: Access the Database with Java and JDBC Appendix B-46
Practice 6 Solution (continued)
Creating the database trigger
• From File | New menu option, select Objects and choose SQL File
• Use this SQL file to type in the SQL statement in order to create a trigger that triggers for
each row after an update of the promotion_id column is done for an Order that has the
‘online’ order_mode value
CREATE OR REPLACE TRIGGER promo_trig
AFTER UPDATE OF promotion_id ON orders
FOR EACH ROW
WHEN (old.order_mode='online')
CALL logPromotion(:old.order_id, :old.order_total,
:new.promotion_id)
/
• Right-click on the file to run it using SQL*Plus
Note: At this point you are able to test your Java Stored Procedure
Testing the Java stored procedure
• Open a SQL*Plus window for your connection
• Query the ORDERS table to find an ORDER_ID having the online property for the
ORDER_MODE column
SELECT order_id FROM orders WHERE order_mode=‘online’
• Update the order table and set a value for the promotion_id column for one of the online
orders
UPDATE orders SET promotion_id=1 WHERE order_id=2390;
• Query the Orders table for the given order_id value and verify that PROMOTION_ID is
updated
SELECT * FROM orders WHERE order_id =2390;
• Query the order_audit table to verify that you Java Stored procedure executed and
populated the correct values
SELECT * FROM order_audit;

Oracle9i: Access the Database with Java and JDBC Appendix B-47
Practice 6 Solution (continued)
Complete code solution
CREATE TABLE order_audit
(order_id number(12),
old_order_total number(8,2),
new_promotion_id number(6),
change_date date,
username varchar2(15))
/

CREATE OR REPLACE TRIGGER promo_trig


AFTER UPDATE OF promotion_id ON orders
FOR EACH ROW
WHEN (old.order_mode='online')
CALL logPromotion(:old.order_id, :old.order_total,
:new.promotion_id)
/

CREATE OR REPLACE PROCEDURE log_promotion (


order_id NUMBER, old_order_total NUMBER, new_promotion_id
NUMBER)
AS LANGUAGE JAVA
NAME 'DbOrder.logPromotion (int, float, int)‘
/

Oracle9i: Access the Database with Java and JDBC Appendix B-48
Practice 7-1 Solution
Goal
The goal of this practice is to create a simple Java class that access to the database using
SQLJ and run it in an MS-DOS window. You will have to set up the environment variables
to be able to compile and run a simple Java class that interacts with the Oracle database.
During this practice you perform Query statements.

Your assignment
You create the Practice7 class. In this class, you specify the code to connect to the
database, to query a single column from a table, and to disable the autocommit option.

Modify the PATH environment variable


1. Open Notepad
– Type in the CLASS variable:
set PATH=<JDeveloper_home>\jdk\bin\;<oracle_home>\bin\;
< JDeveloper_home>\jdev\bin\;%PATH%;
– Type in the CLASSPATH variable to include the runtime and translator jar files:
set CLASSPATH=.
set CLASSPATH=%CLASSPATH%;<oracle_home>\jdbc\lib\classes12.jar
set CLASSPATH=%CLASSPATH%;<oracle_home>\sqlj\lib\runtime12.jar
set CLASSPATH=%CLASSPATH%;< oracle_home>\sqlj\lib\translator.jar
2. Save the file with the name E:\mysqlj.bat

Setting up the environment


3. Open an MS-DOS window
– Click Start on the TaskBar
– Select the Start MS/DOS option
– Run the mysqlj.bat file
– Move to the E:\labs\sqlj directory
4. Checking the environment
– Verify the JDBC, SQLJ and JDK versions
E:\labs\sqlj> sqlj –version-long
Create the Java class
5. Open Notepad to enter the Java code
– Specify the packages to import
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.error.*;
import oracle.sqlj.runtime.*;
import sqlj.runtime.ref.*;
import sqlj.runtime.error.*;
import oracle.sql.*;

Oracle9i: Access the Database with Java and JDBC Appendix B-49
Practice 7-1 Solution (continued)
– Specify the following template statements
public class Practice7
{

public static void main (String args [])


throws Exception
{

6. Specify the connection to the database


– Use the Oracle.connect() method using a property file named
connect.properties to connect to the database.
Oracle.connect(Practice7Sol.class,
"connectSol.properties");
– Add a statement to display the message “connection established”
System.out.println("connection established");
7. Perform a single row query
– Declare a int type variable
int id;
– Add a SQLJ/SQL statement that queries the first customer_id of table Customers (use
rownum=1)
# sql{SELECT customer_id INTO :id FROM customers
WHERE ROWNUM=1};
– Print the customer id
System.output.println(("id "+ id);
– Close the connection context
Oracle.close();
– Add a statement to display the message “connection established”
System.out.println("connection closed");
8. Save the file in the E:\labs directory with the name Practice7.sqlj, using
File|Save menu option, but keep Notepad running, you will need it again.
Create the connect.properties file
9. Using Notepad, create a connection properties file named connect.properties
– Type in the URL, username and password provided by your instructor.
sqlj.url= jdbc:oracle:thin:@myhost:1521:SID
# User name and password here (edit to use different      
user/password)
sqlj.user=scott
sqlj.password=tiger
– Save the file in your labs current directory
Edit and run your Java application
10. Save the file in the E:\labs directory with the name Practice7.java, using
File|Save menu option, but keep Notepad running, you will need it again.

Oracle9i: Access the Database with Java and JDBC Appendix B-50
Practice 7-1 Solution (continued)
11. Compile the Practice7.sqlj file
a. In the DOS window, ensure the current directory is E:\labs
b. Check that the JDBC source file is saved to disk.
c. Compile the file using command: sqlj Practice7.sqlj
d. What files are created if you successfully compiled the code?
Practice7.java
Practice7.class
e. Display the content of the .java file to see what is generated.
12. Run the Practice7 application.
a. Run the file using command: java Practice7
b. What is displayed in the ‘DOS’ window?
connection established
id 101
connection closed
13. Recompile the Practice7.sqlj file
a. Recompile the file using the following command:
sqlj –codegen=iso Practice7.sqlj
b. What files are created now, if you successfully compiled the code?
Practice7_SJProfile0.ser
Practice7_SJProfileKeys.class
Change the Connection method
14. Specify a default connection context using
DriverManager.registerDriver() method
– Reopen the file Practice7.sqlj with Notepad
– Remove the Oracle.connect() , and the Oracle.close() statements.
– Register the Oracle JDBC driver
// Register the Oracle JDBC driver
DriverManager.registerDriver(new
oracle.jdbc.OracleDriver());
– Connect to the database using the Connection type
Connection conn =
DriverManager.getConnection(URL,userid,password);
– Create a default context and set auto-commit off
DefaultContext.setDefaultContext(new
DefaultContext(conn));
conn.setAutoCommit(false);
– Close the context and the connection
DefaultContext.getDefaultContext().close();
conn.close();

Oracle9i: Access the Database with Java and JDBC Appendix B-51
Practice 7-1 Solution (continued)
Edit and run your Java application
15. Save the file in the E:\labs directory with the name Practice7.sqlj
16. Compile the Practice7.sqlj file
sqlj Practice7.sqlj
17. Execute the class
java Practice7
Perform online checking for your Java application
18. Change your SQL statement to produce a semantic error.
– Reopen the file Practice7.sqlj with Notepad
– Change the name of the product_id column and name it product.
– Compile the Practice7.sqlj file
sqlj Practice7.sqlj
– Was the compilation successful?
– Recompile the file Practice7.sqlj with an online checking using the thin
driver
– E:\Labs\sqlj> sqlj -user=oraXX/oracle
-url=jdbc:oracle:
thin:@myhost:1521:SID Practice7.sqlj
– Was the compilation successful?

Oracle9i: Access the Database with Java and JDBC Appendix B-52
Practice 7-1 Solution
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.error.*;
import sqlj.runtime.ref.*;
import oracle.sqlj.runtime.*;
import sqlj.runtime.error.*;
import oracle.sql.*;

public class Practice7Sol


{

public static void main (String args [])


throws Exception
{

(url,"scott","tiger");
Oracle.connect(Practice7.class,"connect.properties");

System.out.println("connection established ");


//
int id;
// Add a SQLJ/SQL statement that queries the first
customer_id // of table Customers (use rownum=1)

#sql{SELECT customer_id INTO :id FROM customers WHERE


ROWNUM = 1};
// Print the customer ID
System.out.println("id "+ id);
// Close the connection
Oracle.close();
System.out.println("connection closed ");
}

Oracle9i: Access the Database with Java and JDBC Appendix B-53
Practice 7-2 Solution
Goal
The goal of this practice is to create a multi row query using a named iterator.
Your assignment
You use the Practice7.sqlj file previously created, rename the class name to
Practice72 and update the SQL statement in order to retrieve more than one row with a
named iterator.
Create a multi row query statement in the Java class
1. Define an iterator class for customer_id, cust_first_name and
cust_last_name columns of table CUSTOMERS
#sql iterator CustomerIterator(int customer_id, String
cust_last_name , String cust_first_name);
2. Declare a variable of the iterator class
CustomerIterator customers=null;
3. Declare three variables named id, first, and last of the appropriate type to map
with the columns of the iterator
int id= 0;
String first;
String last;
4. Define a SQLJ/SQL statement for the iterator that queries the three corresponding
columns of the CUSTOMERS table for customers having a credit_limit of 100
#sql customers={SELECT 
customer_id,cust_first_name,cust_last_name FROM 
customers WHERE credit_limit=100};
5. Specify a loop that prints each row returned by the query
while (customers.next()) 
{

id =customers.customer_id();
last=customers.cust_last_name();
first=customers.cust_first_name();
System.out.println(id+" "+last +" "+first);
}

6. Close the iterator


customers.close();
Edit and run your Java application
7. Save the file in the E:\labs directory with the name Practice72.java.
8. Compile the Practice72.sqlj file
9. Run the Practice72 application.

Oracle9i: Access the Database with Java and JDBC Appendix B-54
Practice 7-2 Solution
Complete Code Solution
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.error.*;
import oracle.sqlj.runtime.*;
import sqlj.runtime.error.*;
import oracle.sql.*;
import sqlj.runtime.ref.*;

public class Practice72Sol


{

public static void main (String args [])


throws Exception
{

String url="jdbc:oracle:thin:@myhost:1521:SID";
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
(url,"username","password");
System.out.println("connection established");
int id= 0;
String first;
String last;

DefaultContext.setDefaultContext(new
DefaultContext(conn));//THIS IS MANDATORY

#sql iterator CustomerIterator(int customer_id, String


cust_last_name , String cust_first_name);
CustomerIterator customers=null;
#sql customers={SELECT
customer_id,cust_first_name,cust_last_name FROM customers
WHERE credit_limit=100};

Oracle9i: Access the Database with Java and JDBC Appendix B-55
Practice 7-2 Solution (continued)
Complete code Solution (continued)
while (customers.next())
{

customers.cust_last_name(),customers.cust_first_name());
id =customers.customer_id();
last=customers.cust_last_name();
first=customers.cust_first_name();
System.out.println(id+" "+last +" "+first);
}

customers.close();
DefaultContext.getDefaultContext().close();
conn.close();
System.out.println("connection closed");

Oracle9i: Access the Database with Java and JDBC Appendix B-56
Practice 7-2 Solution Additional (if you have time)
Update the Practice7 file and replace the named iterator by a positional one.
There is no solution for this practice

Oracle9i: Access the Database with Java and JDBC Appendix B-57
Practice AppendixC Solution
In this practice, you will use the JPublisher utility to create wrappers for retrieving object
types and print the object types for each customer in the CUSTOMERS table. Open
AppendixC.jws in JDeveloper and navigate to the objecttype.jpr project.
1. Create a database connection
a. Expand the connection node in the system navigator
b. Right click on the database node and select the New Connection option
c. Type in a name for the connection and select the Oracle(JDBC) connection type
d. Provide your name and password
e. Specify the HostName, JDBC port and SID and test the connection
2. Use the JPublisher utility to create the object type wrappers.
a. Navigate to your database connection in JDeveloper and expand the schema to
view all the objects in the schema.
b. Expand the Object Types node and right-click on CUST_ADDRESS_TYP.
Select ‘Generate Java’ from the pop-up list, select the objecttype.jpr
project in the Project field, and click OK. Note that two wrapper classes have been
added to your project, one containing wrappers for the object type itself, and one
containing wrappers for each of the components of the object type.
3. Now create a class to print the names of each customer and their address.
a. In objecttype.jpr, create a new class with a main method and give the class a
unique name.
b. Import the java.sql.*, oracle.sql.*, and oracle.jdbc.driver.*
libraries in the class.
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
c. In the main method, create a database connection in a try/catch block (the main
method should throw the appropriate exceptions for JDBC and using
Class.forName).
try {
Class.forName("oracle.jdbc.driver.OracleDriver");

}     
catch (SQLException e) 
{ System.out.println(e.getMessage());
}

d. Use the connection object to create a statement.


Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID", "username", 
"password");
Statement stmt = conn.createStatement();
e. Create a String variable to contain the query string for selecting all the columns
from the CUSTOMERS table but only for the first 50 rows.
String custquery = ("SELECT * FROM customers WHERE
ROWNUM <50 ");
Oracle9i: Access the Database with Java and JDBC Appendix B-58
Practice AppendixC Solution (continued)
f. Create an OracleResultSet variable to execute the query using the variable
created in the previous step.
OracleResultSet rs = (OracleResultSet)
stmt.executeQuery(custquery);
g. In a while loop, loop through the result set and retrieve the first and last name of
the customers in the table and store them in String variables.
while (rs.next()) {
String custFirstName = rs.getString(2);
String custLastName = rs.getString(3);
h. Create a variable of the object wrapper class type and use the getORAData()
method of the result set to retrieve the information in the CUST_ADDRESS_TYP.
custAddressTyp addr =
(custAddressTyp)rs.getORAData
(4,custAddressTyp.getORADataFactory());
i. Using the methods in the wrapper class, write code to print the customer’s first and
last name on one line, their street address on the next line, and their city, state,
postal code, and country code on the last line.
System.out.println(custFirstName + " " + custLastName);
System.out.println(addr.getStreetAddress());
System.out.println(addr.getCity() + " " +
addr.getStateProvince() + " " +
addr.getPostalCode());
System.out.println(addr.getCountryId());
j. Close the while loop and compile the project.
}

k. Run your class file to test the application.

Oracle9i: Access the Database with Java and JDBC Appendix B-59
Practice AppendixC Solution (continued)
Complete Code Solution
package objecttypeSol;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;

public class CustomerList


{

public CustomerList()
{

public static void main(String[] args)throws SQLException,


ClassNotFoundException
{

CustomerList customerList = new CustomerList();

try {
Class.forName("oracle.jdbc.driver.OracleDriver");

Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID", "username", "password");
Statement stmt = conn.createStatement();
String custquery = ("SELECT * FROM customers WHERE ROWNUM <50
");
OracleResultSet rs = (OracleResultSet)
stmt.executeQuery(custquery);

while (rs.next()) {

String custFirstName = rs.getString(2);


String custLastName = rs.getString(3);
custAddressTyp addr =

(custAddressTyp)rs.getORAData(4,custAddressTyp.getORADataFactor
y());
System.out.println(custFirstName + " " + custLastName);
System.out.println(addr.getStreetAddress());
System.out.println(addr.getCity() + " " +
addr.getStateProvince() + " " +
addr.getPostalCode());
System.out.println(addr.getCountryId());
}

catch (SQLException e) { System.out.println(e.getMessage());


System.out.println("Caught a SQLException");
}

catch (Exception e) { System.out.println(e.getMessage()); }


}

Oracle9i: Access the Database with Java and JDBC Appendix B-60
SQLJ Advanced Topics

Appendix C

Copyright © Oracle Corporation, 2002. All rights reserved.

Schedule: Timing Topic

60 minutes Lecture
20 minutes Practice
80 minutes Total
Objectives

After completing this lesson, you should be able to


do the following:
• Connect to multiple database sessions using SQLJ
• Perform dynamic SQL in SQLJ
• Access large-object data types
• Pass and retrieve streamed data
• Translate user-defined types to Java classes using
the JPublisher utility

C-2 Copyright © Oracle Corporation, 2002. All rights reserved.

Lesson Aim
A production application in SQLJ might require functionality such as the ability to handle multiple
connections and access large-object data types. This lesson teaches you how to write code that
handles these issues.

Oracle9i: Access the Database with Java and JDBC C-2


Creating an Additional
Connection Context

• Set more than one connection context


• Give a name to an additional connection context
(other than the default one)
• Name the connection context in the SQL statement
DefaultContext ctx1 = Oracle.getConnection
("jdbc:oracle:thin:@localhost1:1521:orcl1",
"scott", "tiger");
DefaultContext ctx2 = Oracle.getConnection
("jdbc:oracle:thin:@localhost2:1521:orcl2",
"bill", "lion");

C-3 Copyright © Oracle Corporation, 2002. All rights reserved.

Set the Default Connection Context


All SQLJ statements execute in a connection context. At a minimum, you need to set the default
connection context. The default connection context is implemented by the defaultContext
class.
You can combine the default connection context and named connection contexts.
The following example connects to the database and sets the default connection context:
Connection conn = null;
// Register the driver
DriverManager.registerDriver(
new oracle.jdbc.driver.OracleDriver());
// Connect to the database
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@myhost:1521:orcl",
"username","password");
// Set the default connection context
DefaultContext.setDefaultContext(new DefaultContext(conn));
Instructor Note
The Oracle9i SQLJ Developer’s Guide describes alternative methods of setting the default context.

Oracle9i: Access the Database with Java and JDBC C-3


How to Work with a Named
Connection Context

1. Declare a context class.


#sql context MyContext;

2. Create a context object.


MyContext mctx = new MyContext
(URL, userid, password, autocommit);

3. Use the context name in your SQLJ statement.


#sql [mctx] {statement};

C-4 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Work with a Named Connection Context


Each SQLJ statement executes within the scope of a connection context. In the previous lesson,
you learned how to work within the default connection context. This slide shows how to work with
a named connection context. This is useful if your program uses multiple connection contexts; you
can switch between contexts by specifying the context name in your SQLJ statement.
Follow these steps to create a new context:
1. Declare a SQLJ context class. For example:
#sql context OEContext;
This creates a Java class that implements the ConnectionContext interface. Because this
statement translates to a class declaration, you will usually put it after any import
statements and before the class definition.
2. Create a Java object whose type is your context class. For example:
OeContext oectx = new OeContext(
"jdbc:oracle:thin:@myhost:1521:ORCL", "scott", "tiger",
true);
The last parameter specifies whether transactions in this context will use autocommit.
You can now use your context name in your SQLJ statements. For example:
#sql [oectx] {
UPDATE orders SET order_status = 2 WHERE order_id = 2410};
Note: The context name must be enclosed in brackets ([]).

Oracle9i: Access the Database with Java and JDBC C-4


Example: Working with Multiple
Connection Contexts

You can mix queries that use the default context with
queries that use a named context.
Named context

OrderIter orders;
OeContext oectx;
...
#sql [oectx] orders = {
SELECT order_id, status FROM orders};
#sql {UPDATE orders SET status = 2};

Default context

C-5 Copyright © Oracle Corporation, 2002. All rights reserved.

Working with Multiple Connection Contexts


The slide shows an example using different contexts in SQLJ queries and using a context and an
iterator in the same query. You can mix statements that use the default context with statements that
use a named context, or you can use only named contexts.
The example in the slide assumes that you have declared a SQLJ iterator class named CopyIter
and a SQLJ context class named AcmeContext.
• The first statement uses the acmectx context and selects some data into an iterator.
• The second statement performs an update in the default context.
• The third statement performs an update in the acmectx context.

Oracle9i: Access the Database with Java and JDBC C-5


Data Sources and JNDI

• Provide an alternative to the DriverManager


mechanism
• Combine data source name with connection
context
• Give a flexible way to connect to a database
#sql public static context TestCtx with
(dataSource="jdbc/test");
// The default context looks up a JNDI DataSource under:
// "jdbc/defaultDataSource"
#sql { select ename, sal, empno into :name, :sal, :empid
from emp where ename='SCOTT' };
...
// Instances of TestCtx use the JNDI DataSource from the
// context declaration: "jdbc/test"
TestCtx ctx = new TestCtx();
#sql [ctx] { select ename, sal, empno into :name, :sal,
:empid from emp where ename='SMITH' };

C-6 Copyright © Oracle Corporation, 2002. All rights reserved.

Data Source Support


SQLJ uses the same mechanism that is available with JDBC 2.0 to create connection context
instances in a flexible and portable way. Data sources can also be implemented using a connection
pool or distributed transaction service, as defined by the JDBC 2.0 extended API.
Associating a connection context with a data source
In SQLJ it is natural to associate a connection context class with a logical schema, in much the
same way that a data source name serves as a symbolic name for a JDBC connection. Combine
both concepts by adding the data source name to the connection context declaration.
#sql context EmpCtx with (dataSource="jdbc/EmpDB");
Any connection context class that you declare with a dataSource property provides additional
constructors. To continue the EmpCtx example, the following constructors are provided:
• public EmpCtx() —Looks up the data source for jdbc/EmpDB and then calls the
getConnection() method on the data source to obtain a connection.
• public EmpCtx(String user, String password) —Looks up the data source
for jdbc/EmpDB and calls the getConnection(user,password) method on the data
source to obtain a connection.
• public EmpCtx(ConnectionContext ctx) —Delegates to ctx to obtain a
connection.

Oracle9i: Access the Database with Java and JDBC C-6


Data Source Support (continued)
Associating a connection context with a data source (continued)
Any connection context class declared with a dataSource property also omits a number of
DriverManager-based constructors. Continuing the EmpCtx example, the following constructors
are omitted:
public EmpCtx(Connection conn)
public EmpCtx(String url, String user, String password, boolean
autoCommit)
public EmpCtx(String url, boolean autoCommit)
public EmpCtx(String url, java.util.Properties info, boolean
autoCommit)
public EmpCtx(String url, boolean autoCommit)
Associating a data source with the default context
If a SQLJ program accesses the default connection context, and the default context has not yet been
set, then the SQLJ runtime will use the SQLJ default data source to establish its connection. The
SQLJ default data source is bound to the JNDI name "jdbc/defaultDataSource".
This mechanism provides a portable means to define and install a default JDBC connection for the
default SQLJ connection context.
Data source support requirements
For your program to use data sources, you must supply the packages javax.sql.* and
javax.naming.*, and an InitialContext provider in your Java environment. The latter is
required to obtain the JNDI context in which the SQLJ runtime can look up the data source object.
Typically, you would use data sources in a JDK 1.2.x environment with the Java Extension classes,
or in a J2EE environment. However, you can also use data sources under JDK 1.1.x with the Java
Extension classes.
All SQLJ run-time libraries provided by Oracle support data sources. However, if you use the
runtime12ee library you must have javax.sql.* and javax.naming.* in your classpath in
order for the run time to load. By contrast, the other run-time libraries use reflection to retrieve
DataSource objects.

Oracle9i: Access the Database with Java and JDBC C-7


Multiple Connections and SQLJ
Translator Options

1. Select “Check SQL semantics against database


schema.”
2. Enter the context class name, including the
package name.
3. Select the connection to perform online checking
against.

Package1.OeContext OeConnection

C-8 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Set SQLJ Translator Options in JDeveloper


If your SQLJ application uses multiple connection contexts and you want the SQLJ translator to
perform online checking for all of them, you need to enter a context name and a connection name
for each context that your application uses. You add each context as follows:
1. Click Add Context.
2. Type your context class name in the Context Name drop-down list. You must type the name
of your context class and not the name of your context object, and you must include the
package name. For example, your .sqlj file contains the following code:
package package1;
#sql context OeContext;

OeContext oectx = new OeContext(…);
You should enter package1.OeContext in the Context Name drop-down list.
3. Select a connection name to use for online checking. This does not have to be the same
database connection that your SQLJ file uses.
Oracle9i: Access the Database with Java and JDBC C-8
Multiple Connections and SQLJ
Translator Options

4. Leave Context Name blank to specify the default


context.
Context Name Connection Name
oeConnection

5. Select <No connection> if you do not want to


perform online checking for the specified context.

Context Name Connection Name


Package1.OeContext <No connection>

C-9 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Set SQLJ Translator Options in JDeveloper (continued)


In the example in the slide, the SQLJ translator performs online checking for the default context
against the acmeConnection connection and does not perform any online checking for
AcmeContext.
Oracle9i: Access the Database with Java and JDBC C-9
Dynamic SQL in SQLJ

• Oracle9i SQLJ supports dynamic SQL


• Use meta bind expression in place of:
– Table name
– Column name in a Select list
– All or part of a WHERE clause
– A SQL literal value or SQL expression

String metaBindExp;
...
:{metaBindExp [::SQL_expression]}

C-10 Copyright © Oracle Corporation, 2002. All rights reserved.

Support for Dynamic SQL


Oracle9i SQLJ includes extensions to support dynamic SQL—operations that are not predefined
and can change in real-time. Dynamic SQL expressions embedded in SQLJ statements are referred
to as meta bind expressions.
Meta bind expressions
Meta bind expressions are used for dynamic SQL in SQLJ statements, where otherwise static SQL
clauses would appear. A meta bind expression contains a Java identifier of type String or a string-
valued Java expression that is interpreted at run time. In addition, so that SQLJ can perform online
semantics-checking, a meta bind expression can optionally include static SQL replacement code to
be used for checking during translation.
Be aware of the following restrictions on meta bind expressions, enforced to ensure that the SQLJ
translator can properly determine the nature of the SQL operation and can perform syntactic
analysis of the SQLJ statement as a whole:
• A meta bind expression cannot be the first non-comment of the SQL operation within a SQLJ
statement.
• A meta bind expression cannot contain the INTO token of a SQLJ SELECT INTO statement
and cannot expand to become the INTO-list of a SELECT INTO statement.
• A meta bind expression cannot appear in any of the following kinds of SQL/SQLJ
instructions or clauses: CALL, VALUES, PSM SET, COMMIT, ROLLBACK, FETCH
INTO, or CAST.

Oracle9i: Access the Database with Java and JDBC C-10


Dynamic SQL Code Example

...

String table="emp";
String where="job=‘MANAGER’";
String column="ename";
...
#sql myIter = { SELECT :{column::job}
FROM :{table::temp}
WHERE :{where::deptno=10}};

SQL used at compilation time

SELECT job FROM temp WHERE deptno=10;

SQL used at execution time


SELECT ename FROM emp WHERE job="MANAGER";

C-11 Copyright © Oracle Corporation, 2002. All rights reserved.

SQL Replacement Code


A SQL replacement code clause consists of a sequence of zero or more SQL tokens, with the
following requirements and restrictions:
• It is subject to SQL lexing rules.
• Braces—"{" and "}"—must occur in matching pairs (with the exception of those that are part
of a SQL comment, constant, or identifier).
• There can be no SQLJ host expressions or nested meta bind expressions within the SQL
instructions.
Translation-time behavior
Whenever there is SQL replacement code (even if only an empty string) in a meta bind expression,
then the meta bind expression is replaced by the SQL code during translation. The purpose of SQL
replacement code is to enable the SQLJ translator to perform online semantics-checking.
If any meta bind expression within a SQLJ statement has no SQL replacement code clause, then
the SQLJ translator cannot perform online semantics-checking on the statement—it is only checked
syntactically.
Run time behavior
At run time, each meta bind expression is replaced by the evaluation of its Java bind expression.
If a Java bind expression evaluates to null, then the dynamic SQL statement as a whole becomes
undefined.
Note: It is permissible for the SQL replacement code to be empty.
Oracle9i: Access the Database with Java and JDBC C-11
The oracle.sql Package

• This package contains classes that map to Oracle


data types.
• You can use these variables in #sql expressions.
oracle.sql.NUMBER yr = null;
#sql {
SELECT year INTO :yr
FROM acme_titles
WHERE title_id = :id
};

C-12 Copyright © Oracle Corporation, 2002. All rights reserved.

The oracle.sql Package


The oracle.sql package contains a class for each Oracle SQL data type. You use these Java
types in #sql expressions just as you would use any other host variables. The oracle.sql.*
classes store the data in SQL format. The following table lists classes in the oracle.sql
package and the corresponding Oracle SQL types.
Java Class Oracle SQL Type

oracle.sql.NUMBER NUMBER
oracle.sql.CHAR CHAR, VARCHAR2
oracle.sql.RAW RAW
oracle.sql.DATE DATE
oracle.sql.ROWID ROWID
oracle.sql.BLOB BLOB
oracle.sql.CLOB CLOB
oracle.sql.BFILE BFILE

oracle.sql.STRUCT STRUCT
oracle.sql.REF REF
oracle.sql.ARRAY ARRAY
Instructor Note

Documentation for the oracle.sql package is available at


http://otn.oracle.com/tech/java/sqlj_jdbc/content.html
Oracle9i: Access the Database with Java and JDBC C-12
When to Use the oracle.sql Classes

• When you are selecting or updating an Oracle


extended type, such as BLOB or RAW
• When you are selecting or updating a basic SQL
type and you are moving data within the database

C-13 Copyright © Oracle Corporation, 2002. All rights reserved.

When to Use the oracle.sql Classes


You must use a variable from the oracle.sql package if you are selecting or updating columns
of an Oracle extended type such as BLOB or RAW.
For basic SQL types (numeric, character, and date types), the correct approach depends on what
your code is doing. If you are moving data within the database, it is usually more efficient to keep
your data in oracle.sql.* format, and you do not risk loss of precision. If you are displaying
the data or performing calculations on it in a Java application running outside of the database, then
it is usually better to convert the data to a java.lang.* or java.sql.* type.

Oracle9i: Access the Database with Java and JDBC C-13


REF CURSOR Types

• Cursor variables are equivalent to JDBC result sets


• You must use PL/SQL to return a REF CURSOR
parameter
• Stored Procedures or functions can return
parameters of Oracle REF CURSOR types
• REF CURSOR types can be used as:
– Result expressions for stored function returns
– Output host expressions for stored procedure or
function output parameters
– Output host expressions in INTO lists
– Iterator columns

C-14 Copyright © Oracle Corporation, 2002. All rights reserved.

Overview of REF CURSOR Types


Cursor variables are functionally equivalent to JDBC result sets, essentially encapsulating the
results of a query. A cursor variable is often referred to as a REF CURSOR, but REF CURSOR
itself is a type specifier, not a type name. Instead, named REF CURSOR types must be specified.
The following example shows a REF CURSOR type specification:
TYPE EmpCurType IS REF CURSOR;
Stored procedures and stored functions can return parameters of Oracle REF CURSOR types. You
must use PL/SQL to return a REF CURSOR parameter. A PL/SQL stored procedure or function
can declare a variable of some named REF CURSOR type, execute a SELECT statement, and
return the results in the REF CURSOR variable.
REF CURSOR types in SQLJ
In Oracle SQLJ, a REF CURSOR type can be mapped to iterator columns or host variables of any
iterator class type or of type java.sql.ResultSet, but host variables can be OUT only. Support for
REF CURSOR types can be summarized as follows:
• As result expressions for stored function returns
• As output host expressions for stored procedure or function output parameters
• As output host expressions in INTO-lists
• As iterator columns
You can use the Oracle SQL CURSOR operator for a nested SELECT within an outer SELECT
statement. This is how you can write a REF CURSOR object to an iterator column or ResultSet
column in an iterator, or write a REF CURSOR object to an iterator host variable or ResultSet host
variable in an INTO-list.

Oracle9i: Access the Database with Java and JDBC C-14


REF CURSOR Example

private static EmpIter


refCursInAnonBlock(String name, int no)
throws java.sql.SQLException {
EmpIter emps = null;
System.out.println
("Using anonymous block for ref cursor..");
#sql { begin
INSERT INTO emp (ename, empno)
VALUES (:name, :no);
OPEN :out emps FOR SELECT ename, empno
FROM emp ORDER BY empno;
end
};
return emps;
}

C-15 Copyright © Oracle Corporation, 2002. All rights reserved.

REF CURSOR Example


The following sample method shows a REF CURSOR type being retrieved from an
anonymous block.
You can retrieve a REF CURSOR type from the following:
• An anonymous block
• A stored procedure (as an OUT parameter)
• A stored function (as a return value)
Code example for a REF CURSOR retrieved from a stored function:
private static EmpIter refCursInStoredFunc (String name, int no)
throws java.sql.SQLException {
EmpIter emps = null;
System.out.println("Using stored function for ref cursor..");
#sql emps = { VALUES (SQLJREFCURSDEMO.REFCURSFUNC(:name,:no))
};
return emps;
}

Oracle9i: Access the Database with Java and JDBC C-15


Handling Streams in SQLJ

• The sqlj.runtime package contains classes for


handling data in streams:
– BinaryStream
– AsciiStream
– UnicodeStream
• Streams are useful with LONG and LONGRAW

C-16 Copyright © Oracle Corporation, 2002. All rights reserved.

Handling Streams in SQLJ


The sqlj.runtime package contains three classes for handling data in streams:
• BinaryStream: For handling binary data
• AsciiStream: For handling data in ASCII format
• UnicodeStream: For handling Unicode data
AsciiStream and UnicodeStream are typically used for datatype LONG
(java.sql.Types.LONGVARCHAR), but might also be used for datatype VARCHAR2
(Types.VARCHAR).
BinaryStream is typically used for data type LONG RAW (Types.LONGVARBINARY), but
might also be used for datatype RAW (Types.BINARY or Types.VARBINARY).
Of course, any use of streams is at your discretion. LONG and VARCHAR2 data can also be
manifested in Java strings, while RAW and LONGRAW data can also be manifested in Java byte
arrays. Furthermore, if your database supports large object types such as BLOB (binary large
object) and CLOB (character large object), you may find these to be preferable to using types such
as LONG and LONG RAW (although streams may still be used in extracting data from large
objects).
You can use the SQLJ stream types for host variables to either send or retrieve data. All three SQLJ
stream classes are subclasses of the standard Java input stream class, java.io.InputStream, and act
as wrappers to provide the functionality required by SQLJ. This functionality is to communicate to
SQLJ the type and length of data in the underlying stream so that it can be processed and formatted
properly.

Oracle9i: Access the Database with Java and JDBC C-16


How to Update LONG or LONG RAW Data
from an ASCII File

1. Create a java.io.File object.


import java.io.*; …
File file = new File (pathname);

2. Get the length of your file and cast it to an int.


int length = (int)file.length();

3. Create a FileInputStream object.


FileInputStream inputStream =
new FileInputStream(file);

C-17 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Update LONG or LONG RAW Data from a File


The slide shows the first three steps for updating a LONG or LONG RAW database column from an
ASCII file. The last three steps are shown on the following slide. The procedure for updating a
column from a binary or Unicode file is similar; the only difference is in step 4.
You need to add two import statements to your code:
import java.io.*;
import sqlj.runtime.*;
1. Create a java.io.File object from your ASCII file. Pass the pathname of the file to
the File constructor.
2. Get the length of your data. File.length() returns a long; you must cast this value
to an int to pass to the SQLJ stream class constructor.
3. Create a java.io.FileInputStream object from your File object. Pass your
File object to the FileInputStream() constructor.

Oracle9i: Access the Database with Java and JDBC C-17


How to Update LONG or LONG RAW Data
from an ASCII File

4. Create the SQLJ stream object.


AsciiStream asciiStream =
new AsciiStream(inputStream, length);

5. Execute the INSERT statement.

#sql { INSERT INTO table (colName)


VALUES (:asciistream) };

6. Close the SQLJ stream object.


asciistream.close();

C-18 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Update LONG or LONG RAW Data from a File (continued)


4. Create the AsciiStream object. Pass your FileInputStream object and the length of
your data to the AsciiStream constructor. If your file is binary or Unicode, you must call
a different constructor:
– For a binary file:
BinaryStream binaryStream =
new BinaryStream (inputStream, length);
– For a Unicode file:
UnicodeStream unicodeStream =
new UnicodeStream(inputStream, length);
5. Execute your INSERT statement. Use the SQLJ stream object as a host variable.
6. Close your AsciiStream object.
Code Example
File myfile = new File ("/private/mydir/myfile.html");
int length = (int)myfile.length();//Must cast long output to int
FileInputStream fileinstream = new FileInputStream(myfile);
AsciiStream asciistream = new AsciiStream(fileinstream, length);
#sql { INSERT INTO filetable (asciidata) VALUES (:asciistream) };
asciistream.close();

Oracle9i: Access the Database with Java and JDBC C-18


Dealing With LOBs and BFILEs

• Oracle extensions to JDBC 2.0 provide the


following Java types:
Java Type Oracle Types Oracle
definition Datatype
oracle.sql.BLOB BLOB BLOB
oracle.sql.CLOB CLOB CLOB
oracle.sql.BFILE BFILE BFILE

• These Oracle specific classes can be used:


– As IN, OUT, INOUT host variables of SQL
– As return values from stored function calls
– As column types in iterator declarations

C-19 Copyright © Oracle Corporation, 2002. All rights reserved.

Handling Large Objects in SQLJ


The oracle.sql package contains classes for handling large objects:
• oracle.sql.BLOB
• oracle.sql.CLOB
• oracle.sql.BFILE
The data types are supported by the BLOB, CLOB, and BFILE classes in the oracle.sql
package. Each class has methods to set and get the object data. For each of these data types, the
database stores a locator representing the data. Instances of the BLOB, CLOB, and BFILE classes
contain these locators, not the LOB data itself.
For example, you could add a PHOTO column of type BLOB to the ACME_MEMBERS table. The
following SQLJ statement selects the locator of a photo from the database:
BLOB blob;
#sql {select PHOTO into :blob from ACME_MEMBERS 
where MEMBER_ID = 2250};
You would then use methods of the BLOB class to access the data represented by blob. For
example, blob.getBinaryStream() retrieves the whole BLOB as a binary stream.
Oracle9i: Access the Database with Java and JDBC C-19
Using CLOB Method to Read
CLOB Example

This example reads data from a CLOB using methods


of the oracle.sql.CLOB class.
void readFromClob(CLOB clob) throws SQLException
{
long clobLen, readLen;
String chunk;
clobLen = clob.length();
for (long i = 0; i < clobLen; i+= readLen) {
chunk = clob.getSubString(i, 10);
readLen = chunk.length();
System.out.println("read " +
readLen + " chars: " + chunk);
}
}

C-20 Copyright © Oracle Corporation, 2002. All rights reserved.

Using CLOB Method to Read CLOB


Example: Use of DBMS_LOB Read Routines with CLOB This example uses routines of the
DBMS_LOB package to read from a CLOB.
void readFromClob(CLOB clob) throws SQLException
{

long clobLen, readLen;


String chunk;
#sql clobLen = { VALUES(dbms_lob.getlength(:clob)) };
for (long i = 1; i <= clobLen; i += readLen) {
readLen = 10;
#sql { CALL dbms_lob.read(:clob, :inout readLen, :i, :out chunk)
};
System.out.println("read " + readLen + " chars: " + chunk);
}

This method reads the contents of a CLOB in chunks of 10 characters at a time. Note that the chunk
host variable is of the type String.

Oracle9i: Access the Database with Java and JDBC C-20


Using LOB in SQL
Statements Example

Host variables of type BLOB, CLOB, and BFILE can


appear in the INTO list of a SELECT statement.
...
BLOB blob;
CLOB clob;
#sql { SELECT blob_col, clob_col INTO :blob, :clob
FROM my_lob_table WHERE col1=’one’};
#sql { INSERT INTO my_lob_table2
VALUES(’three’, :blob, :clob) };
...

C-21 Copyright © Oracle Corporation, 2002. All rights reserved.

Using LOB in SQL statements


The following example is for a BLOB and CLOB, but code for BFILEs would be functionally the
same.
Example: Use of DBMS_LOB Read Routines with CLOB.
This example uses routines of the DBMS_LOB package to read from a CLOB.
void readFromClob(CLOB clob) throws SQLException
{

long clobLen, readLen;
String chunk;
#sql clobLen = { VALUES(dbms_lob.getlength(:clob)) };
for (long i = 1; i <= clobLen; i += readLen) {
readLen = 10;
#sql { CALL dbms_lob.read(:clob, :inout readLen, :i, :out chunk)
};
System.out.println("read " + readLen + " chars: " + chunk);
}

This method reads the contents of a CLOB in chunks of 10 characters at a time. Note
that the chunk host variable is of the type String.

Oracle9i: Access the Database with Java and JDBC C-21


Example: How to Read BLOB Data
into an Input Stream

1. Read the BLOB locator from the database.


BLOB blob;
#sql {SELECT pictureblob INTO :blob FROM pictures
WHERE name = ‘Oracle’};

2. Retrieve the BLOB into a binary stream.


java.io.InputStream in = blob.getBinaryStream();

C-22 Copyright © Oracle Corporation, 2002. All rights reserved.

Example: How to Read BLOB Data into a Binary Stream


The slide shows how to select a BLOB locator from the database and use the
getBinaryStream() method of class oracle.sql.BLOB to retrieve the BLOB itself into
an input stream. You then write the input stream to an output stream. For example, the following
code completes the example by writing the BLOB to an array of bytes:
int curbyte = 0;
while (curbyte != -1) {
curbyte = in.read();
out.write(curbyte);
}

out.flush();
byte[] bytearray = out.toByteArray();
in.close();
out.close();

Oracle9i: Access the Database with Java and JDBC C-22


Example: How to Select a CLOB
and Write It to Standard Output

1. Read the CLOB locator from the database.


CLOB clob;
#sql {SELECT ad_finaltext INTO :clob
FROM print_media
WHERE product_id = 2056};
2. Get the length of the CLOB.
long clobLen = clob.length();

3. Write the CLOB to standard output.


long readLen;
for (long i = 0; i < clobLen; i+= readLen) {
String chunk = clob.getSubString(i, 10);
readLen = chunk.length();
System.out.println(chunk); }

C-23 Copyright © Oracle Corporation, 2002. All rights reserved.

Example: How to Select a CLOB and Write It to Standard Output


The example in the slide assumes that you have added a CREDIT_REPORT column of type CLOB
to the PRINT_MEDIA table. It selects a single credit report from the database and writes it to
standard output.
The example uses the following methods from the oracle.sql.CLOB class:
• length(): Returns the length of the object in bytes.
• getSubString(): Returns a substring of the object. In the example, the substring contains
10 bytes of data, starting from position i in the object.

Oracle9i: Access the Database with Java and JDBC C-23


Example: Manipulating a BFILE

• Print the full pathname of the file.


BFILE bfile;
… // Select a BFILE from the database into bfile
String dirAlias = bfile.getDirAlias();
String name = bfile.getName();
System.out.println
("name: " + dirAlias + "/" + name);
• Open the file and read it in 10-byte chunks.
bfile.openFile();
InputStream in = bfile.getBinaryStream();
int length;
byte[] buf = new byte[10];
while ((length = in.read(buf)) != -1){
… // Process the data in buf

C-24 Copyright © Oracle Corporation, 2002. All rights reserved.

Example: Manipulating a BFILE


The example in the slide shows how to use some of the methods in oracle.sql.BFILE. The
example uses the following methods:
• getDirAlias(): Gets the BFILE’s directory alias
• getName(): Gets the BFILE’s filename
• openFile(): Opens the file
• getBinaryStream(): Retrieves the entire BFILE as a stream
Note: You have to open the file before you can read it, get its length, or display it.

Oracle9i: Access the Database with Java and JDBC C-24


How to Access User-Defined Types

• The JPublisher utility generates a custom Java


class that maps to your user-defined type (UDT).
• The JPublisher utility supports three types of
mapping:
– Oracle mapping
– JDBC
– Object JDBC

C-25 Copyright © Oracle Corporation, 2002. All rights reserved.

The JPublisher Utility


The JPublisher is a utility, written in Java, that generates Java classes to represent the following
user_defined database entities in your Java program:
• SQL object types
• Object reference types(“REF types”)
• SQL collection types (VARRAY types or nested table types)
• PL/SQL packages
When you run JPublisher for a user-defined type, it creates the following:
• A custom class that maps to your Oracle object type. This class includes get and set
methods for each attribute in your object type.
• (Optional) Wrapper methods in your class that invoke the associated Oracle object methods
executing in the server.
• A custom reference class for object references to your Oracle object type. This class includes
a getValue() method that returns an instance of your custom object class and a
setValue() method that updates an object value in the database, taking as input an
instance of the custom object class.
• If your user-defined type (UDT) has any attributes that are themselves user-defined objects,
JPublisher generates custom classes for these object attributes of the top-level object.

Oracle9i: Access the Database with Java and JDBC C-25


How to Create a Custom Class
by Using the JPublisher Wizard

1. Edit a connection.

2. Open the Object Types node.

C-26 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Create a Custom Class by Using the JPublisher Wizard


• Create or edit a connection using the connection manager.
• Select a user and open the new Object Types subnode to show user-defined object types.
Instructor Note
You can use the slides to demonstrate this process, or you can perform a live demonstration.
To perform a live demonstration, you must first create a UDT and then create an object table
(use SQL*Plus):
SQL> CREATE OR REPLACE TYPE cuisine_typ AS OBJECT
2 (cuisine VARCHAR2(30),
3 description VARCHAR2(1970));
SQL> CREATE TABLE cuisine OF cuisine_typ;
Run the SQL script Jpubdemo.sql, which will populate the table.
Step 1. Create a project containing business components and create an entity object based
on the CUSINE table.
Step 2. Select acmeConnections from the navigation pane.
Step 3. Traverse the acmeConnection dialog box (Database Schema > Object Types).
You will see the CUSINE_TYP object.

Oracle9i: Access the Database with Java and JDBC C-26


How to Create a Custom Class
by Using the JPublisher Wizard

3. Select Generate Java to call the JPublisher


Wizard.

C-27 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Create a Custom Class by Using the JPublisher Wizard (continued)


You can invoke JPublisher on the command line typing Jpub followed by a series of option settings
as follows:
Jpub –option1=value1 –option2=value2…
Example
Jpub –user=scott/tiger –input=demoin –numbertypes=oracle –
usertypes=oracle –dir=demo –package=corp
Instructor Note (continued)
Step 4. Right-click CUSINE_TYP and select Generate Java from the pull-down menu.

Oracle9i: Access the Database with Java and JDBC C-27


How to Create a Custom Class
by Using the JPublisher Wizard

4. Select the project.


5. Specify the package and class names.
6. Choose the mapping.

C-28 Copyright © Oracle Corporation, 2002. All rights reserved.

How to Create a Custom Class by Using the JPublisher Wizard (continued)


Mapping
Oracle mapping: JPublisher maps Oracle data types to their corresponding oracle.sql class.
In the Oracle mapping, JPublisher maps any numeric,LOB, or other built-in type to a class in the
oracle.sql.package. For example, the DATE type is mapped to oracle.sql.date, and all numeric
types are mapped to oracle.sql.number.
JDBC: JPublisher uses standard Java types such as int or float, or
java.lang.BigDecimal. This does not protect against null data; assigning null data to
primitive types such as int and float will cause an exception.
Object JDBC: This is similar to JDBC, except wrapper classes of the java.lang package are
used instead of the Java primitive types. For example, java.lang.Integer and
java.lang.Float are used instead of int and float. This allows null values.
Instructor Note (continued)
Step 5. Select Oracle Mapping and click OK

Oracle9i: Access the Database with Java and JDBC C-28


Summary

• You can connect to multiple database sessions


using SQLJ using named contexts
• SQLJ now supports dynamic SQL
• Access Oracle extended data types, by using
oracle.sql classes
• Access LONG and LONG RAW data types, by using
the stream classes in sqlj.runtime
• Access user-defined data types, by creating a
custom class using JPublisher

C-29 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC C-29


Practice 7 Overview

This practice covers:


• Using JPublisher to Generate mapping classes for
Object types
• Using generated mapping classes to retrieve
Object types from the database

C-30 Copyright © Oracle Corporation, 2002. All rights reserved.

Oracle9i: Access the Database with Java and JDBC C-30


Practice 7-1 (continued)
In this practice, you will use the JPublisher utility to create wrappers for retrieving object types
and print the object types for each customer in the CUSTOMERS table. Open Lesson07.jws
in JDeveloper and navigate to the objecttype.jpr project.
1. Create a database connection.
a. Expand the connection node in the system navigator.
b. Right-click the database node and select the New Connection option.
c. Type in a name for the connection and select the Oracle(JDBC) connection type.
d. Provide your name and password.
e. Specify the hostname, JDBC port and SID and test the connection.
2. Use the JPublisher utility to create the object type wrappers.
a. Navigate to your database connection in JDeveloper and expand the schema to view all
the objects in the schema.
b. Expand the Object Types node and right-click CUST_ADDRESS_TYP. Select
‘Generate Java’ from the pop-up list, select the objecttype.jpr project in the
Project field, and click OK. Note that two wrapper classes have been added to your
project, one containing wrappers for the object type itself, and one containing wrappers
for each of the components of the object type.
3. Now create a class to print the names of each customer and their address.
a. In objecttype.jpr, create a new class with a main method and give the class a
unique name.
b. Import the java.sql.*, oracle.sql.*, and oracle.jdbc.driver.* libraries
in the class.
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
c. In the main method, create a database connection in a try/catch block (the main method
should throw the appropriate exceptions for JDBC and using Class.forName).
try {
Class.forName("oracle.jdbc.driver.OracleDriver");

}     
catch (SQLException e) 
{ System.out.println(e.getMessage());
}

d. Use the connection object to create a statement.


Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:SID", "username", 
"password");
Statement stmt = conn.createStatement();
e. Create a String variable to contain the query string for selecting all the columns from
the CUSTOMERS table but only for the first 50 rows.
String custquery = ("SELECT * FROM customers WHERE
ROWNUM <50 ");

Oracle9i: Access the Database with Java and JDBC C-31


Practice 7-1 (continued)
f. Create an OracleResultSet variable to execute the query using the variable created
in the previous step.
OracleResultSet rs = (OracleResultSet)
stmt.executeQuery(custquery);
g. In a while loop, loop through the result set and retrieve the first and last name of the
customers in the table and store them in String variables.
while (rs.next()) {
String custFirstName = rs.getString(2);
String custLastName = rs.getString(3);
h. Create a variable of the object wrapper class type and use the getORAData() method
of the result set to retrieve the information in the CUST_ADDRESS_TYP.
custAddressTyp addr =
(custAddressTyp)rs.getORAData
(4,custAddressTyp.getORADataFactory());
i. Using the methods in the wrapper class, write code to print the customer’s first and last
name on one line, their street address on the next line, and their city, state, postal code,
and country code on the last line.
System.out.println(custFirstName + " " + custLastName);
System.out.println(addr.getStreetAddress());
System.out.println(addr.getCity() + " " +
addr.getStateProvince() + " " +
addr.getPostalCode());
System.out.println(addr.getCountryId());
j. Close the while loop and compile the project.
}

k. Run your class file to test the application.

Oracle9i: Access the Database with Java and JDBC C-32

You might also like