Professional Documents
Culture Documents
D11678GC31
Edition 3.1
August 2002
D37106
Authors Copyright © Oracle Corporation, 2002. All rights reserved.
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
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
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
Bold italic Glossary term (if there is The algorithm inserts the new key.
a glossary)
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.
20 minutes Lecture
20 minutes Total
Objectives
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.
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
20 minutes Lecture
15 minutes Practice
35 minutes Total
Objectives
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.
OC4J OC4J
Oracle
Oracle9i Database
Application Server
J2EE Certified Environment
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.
JDBC
Client application
or applet
Database
JDBC calls commands
Driver Database
SQLJ Java
Translator compiler
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
Development Debug
UML Exchange
Multi-tier Database
SCM Deployment
Command Area
Navigator
window
Structure
window
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).
Project
files
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.
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
40 minutes Lecture
60 minutes Practice
100 minutes Total
Objectives
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.
Connect
Close
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.
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();
}
}
Example:
Statement stmt = conn.createStatement();
int rowcount = stmt.executeUpdate
("DELETE FROM order_items
WHERE order_id = 2354");
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) {}
}
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.
System.out.println(rset.getInt(1));
}
rest.close();
Note: At this point you should be able to compile and run your .java file
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");
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();
80 minutes Lecture
70 minutes Practice
150 minutes Total
Objectives
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.
Load/Register
JDBC Driver
Connect
Process
results
Close
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
Applet
JDBC
Client Server
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
Application
JDBC
OCI driver
Oracle 9i
ocixxx.dll
Client Server
• 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
Oracle9i
Java Engine
Server Side Thin Driver
JDBC Server-side
Internal driver SQL
engine
C library
Oracle 9i
• 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
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).
Applet Thin
Thin
EJB, servlet
(on the middle tier)
OCI
jdbc:<subprotocol>:<subname>
Protocol Database Identification
jdbc:oracle:<driver>:@<database>
• Example using Oracle Thin JDBC driver:
– jdbc:oracle:thin:@myhost:1521:ORCL
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
Connect
Process
results
Close
while (rset.next()) {
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.
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.
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.
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.
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();
in.close();
bfile.closeFile();
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.
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.
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.
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.
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 ();
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.
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.
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.
DriverManager
URL
Connection Driver+Database+Id
Statement
Oracle9i
ResultSet
Oracle.gif
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.
//Get the blob data cast to OracleResult set to
// retrieve the data in Oracle.sql format
blob = ((OracleResultSet)rset).getBLOB (1);
}
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");
javax.swing.JOptionPane.showInputDialog(new JLabel(new
ImageIcon(buffer)));
}
60 minutes Lecture
50 minutes Practice
110 minutes Total
Objectives
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
... JVM
Choosing a position
col1 col2
void beforeFirst()
boolean first()
boolean next()
boolean absolute(int row)
void afterLast()
Cannot be SELECT *
No ORDER BY
No aggregate or
derived columns
Cannot be returned from
a Stored Procedure or
from a PL/SQL block
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;
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
PreparedStatement pstmt =
conn.prepareStatement
("UPDATE emp SET ename = ? WHERE empno = ?");
PreparedStatement pstmt =
conn.prepareStatement
("SELECT ename FROM emp WHERE empno = ? ");
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
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)
• A REF CURSOR:
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
ResultSet rs = stmt.executeQuery(
"SELECT * FROM customers");
… // process results
((OracleStatement)stmt).setRowPrefetch(2);
rs = stmt.executeQuery(" SELECT * FROM customers ");
… // process results
ResultSet rs = stmt.executeQuery
(" SELECT customer_id FROM customers ");
… // process results
• 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
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();
}
70 minutes Lecture
40 minutes Practice
110 minutes Total
Objectives
Lesson Aim
This lesson discusses some J2EE features and how they are implemented using JDBC 2.0.
JNDI
Connection pooling
Distributed
transaction
• JDBC 2.0 standard extensions API
• Oracle9i, Release 2 will provide partial support for
JDBC 3.0
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
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.
Java servlet
Data source
ConnectionPoolDataSource
JDBC
driver Database
Database
commands
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.
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.
OracleConnectionPoolDataSource ocpds =
new OracleConnectionPoolDataSource();
ocpds.setDriverType("oci");
ocpds.setDatabaseName("orcl");
ocpds.setPortNumber(1521);
ocpds.setUser("scott");
ocpds.setPassword("tiger");
PooledConnection pc =
ocpds.getPooledConnection();
ocacheimpl.setMaxLimit(5);
ocacheimpl.setMinLimit(2);
Ocacheimpl.setCacheScheme
(OracleConnectionCacheImpl.
FIXED_RETURN_NULL_SCHEME);
• Testing cache properties
getActiveSize()
getCacheSize()
Application code
Data source
XADataSource
JDBC Database
driver
Database Database
commands
branch
branchB
A
Using Distributed Connections
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.*;
Statement Cache
Automatic cache • Case sensitive check
check for implicit • Statement type
• Scrollable type
N
New statement Found ?
Y
Statement Cache
WithKey()
Statement Cache
N
null
Found ?
• Allocate a statement
PreparedStatement pstmt = conn.prepareStatement
("UPDATE emp SET ename = ? WHERE rowid = ?");
• 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
For more information about these settings, refer to Appendix A of the Oracle Advanced
Security Administrator’s Guide.
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
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.
WebHost
WebHost
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.
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
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
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
{
60 minutes Lecture
45 minutes Practice
105 minutes Total
Objectives
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.
Server Benefits
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.
Java Stored
Procedure
PL/SQL Stored
Procedure
Oracle9i
SQL
Oracle Net
PL/SQL
Interpreter &
SQL Calls Run-time System
Memory
Natively
Compiled Code
Loadjava Utility
RDBMS RDBMS
Library Manager Memory Manager
CREATE JAVA Statement
Develop
Load
Deploy
Publish
Call
Develop
Load
Deploy
Publish
Call
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.)
Develop
Load
Deploy
Publish
Call
loadjava
Database
Options
Java
Table
Compiler
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
Develop
Load
Deploy
Publish
Call
Call Java
Application Spec Class
Schema
Data
Dictionary
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;
}
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.
Java Class
PL/SQL wrapper
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.
– From SQL*Plus
SQL> drop java class " myPackage3.GenericDrop ";
Develop
Load
Deploy
Publish
Call
beginOrderStmt.registerOutParameter(3,Types.INTEGER);
beginOrderStmt.registerOutParameter(4,Types.VARCHAR);
beginOrderStmt.registerOutParameter(5,Types.VARCHAR);
beginOrderStmt.setInt(1, customerId);
beginOrderStmt.setInt(2, salesRepId);
beginOrderStmt.execute();
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.
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
UPDATE EMP
SET sal=3010 ...
SCOTT 3016
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
DECLARE
emp_id NUMBER;
percent NUMBER;
BEGIN
-- get values for emp_id and percent
raise_salary(emp_id, percent);
...
END;
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.
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.
new_promotion_id number(6),
update_date date,
username varchar2(15));
Creating the Java stored procedure
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
SQL
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
SQL
• 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
Standard
Packages
Copyright © Oracle Corporation, 2002. All rights reserved.
Oracle
Packages
{
{
7-6
#sql {
UPDATE orders
SET order_status = 2
WHERE order_id = :orderId
};
– Disable Auto-commit
Conn.setAutoCommit(false);
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
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);
}
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
int id = ...
Integer acc_man = null;
#sql {
SELECT account_manager INTO :acc_man
FROM customers
WHERE customer_id = :id
};
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
{
SELECT COUNT(*)
FROM product_information
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
Column alias
Project settings
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
id =customers.customer_id();
last=customers.cust_last_name();
first=customers.cust_first_name();
System.out.println(id+" "+last +" "+first);
}
Appendix A
, postal_code VARCHAR2(10)
, city VARCHAR2(30)
, state_province VARCHAR2(10)
, country_id CHAR(2)
);
, 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
) ;
, 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)
) ;
Appendix B
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
{
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");
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();
System.out.println(rsetc.getInt(1));
}
rsetc.close();
Closing resources
22. Close the statement object
stmt.close();
23. Close the connection.
conn.close();
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.*;
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
{
catch (SQLException e)
{
System.out.println(rseta.getInt(1));
}
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");
}
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
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
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
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
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
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);
}
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;
{
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");
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 ())
{
javax.swing.JOptionPane.showInputDialog(new JLabel(new
ImageIcon(buffer)));
}
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.*;
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')");
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());
bfile.openFile();
System.out.println("bfile open "+ bfile.isFileOpen());
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();
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
{
public OrdersQuery()
{
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);
}
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);
rs.close();
//ps.close();
return itemrow.toString();
}
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
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 {
if (args[i].equals("-ds"))
{
else if (args[i].equals("-db"))
{
else if (args[i].equals("-h"))
{
else if (args[i].equals("-p"))
{
else if (args[i].equals("-u"))
{
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)
{
else
{
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;
ds = (DataSource) context.lookup(dsName);
conn = ds.getConnection("username", "password");
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
{
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
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
{
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"));
}
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;
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
{
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
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))
/
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.
Oracle9i: Access the Database with Java and JDBC Appendix B-49
Practice 7-1 Solution (continued)
– Specify the following template statements
public class Practice7
{
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.*;
(url,"scott","tiger");
Oracle.connect(Practice7.class,"connect.properties");
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);
}
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.*;
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
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());
}
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 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()) {
(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());
}
Oracle9i: Access the Database with Java and JDBC Appendix B-60
SQLJ Advanced Topics
Appendix C
60 minutes Lecture
20 minutes Practice
80 minutes Total
Objectives
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.
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
Package1.OeContext OeConnection
String metaBindExp;
...
:{metaBindExp [::SQL_expression]}
...
String table="emp";
String where="job=‘MANAGER’";
String column="ename";
...
#sql myIter = { SELECT :{column::job}
FROM :{table::temp}
WHERE :{where::deptno=10}};
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
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.
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.
out.flush();
byte[] bytearray = out.toByteArray();
in.close();
out.close();
1. Edit a connection.
}
catch (SQLException e)
{ System.out.println(e.getMessage());
}