Sei sulla pagina 1di 17

BLOBs and CLOBs: Storing large fields in a table with the other data

is not necessarily the optimum place especially if the data has a


variable size. One way to handle large, variable sized objects is with
the Large Objects (LOBs) type. LOBs use a locator, essentially a
pointer, in the database record that points to the real database field.
There are two types of LOBs: Binary Large Objects (BLOBs) and
Character Large Objects (CLOBs). When you access a BLOB or CLOB,
the data is not copied to the client. To retrieve the actual data from a
result set, you have to retrieve the pointer with a call to BLOB
blob=getBlob(1) or CLOB clob=getClob(1), and then retrieve the data with
a call to blob.getBinaryStream() or clob.getBinaryStream().
By default, JDBC statements are processed in full auto-commit mode.
Storing Classes, Images and Other Large Objects
Many databases can store binary data as part of a row if the database
field is assigned a long raw, longvarbinary, or other similar type. These
fields can accommodate up to two Gigabytes of data. This means if
you can convert the data into a binary stream or array of bytes, it can
be stored and retrieved from the database in the same way you would
store a string or double.
This technique can be used to store and retrieve images and Java
objects.
Storing and retrieving an image: It is very easy to store an object
that can be serialized or converted to a byte array. Unfortunately,
java.awt.Image is not Serializable. However, as shown in this next code
example, you can store the image data to a file and store the the
information in the file as bytes in a database binary field.
int itemnumber=400456;
File file = new File(itemnumber+".jpg");
FileInputStream fis = new FileInputStream(file);
PreparedStatement pstmt = con.prepareStatement(
"update auctionitems
set theimage=? where id= ?");
pstmt.setBinaryStream(1, fis, (int)file.length()):
pstmt.setInt(2, itemnumber);
pstmt.executeUpdate();
pstmt.close();
fis.close();

To retrieve this image and create a byte array that can be passed to
createImage, do the following:
int itemnumber=400456;
byte[] imageBytes;

PreparedStatement pstmt = con.prepareStatement(


"select theimage from auctionitems where id= ?");
pstmt.setInt(1, itemnumber);
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
imageBytes = rs.getBytes(1);
}
pstmt.close();
rs.close();
Image auctionimage =
Toolkit.getDefaultToolkit().createImage(
imageBytes);

Storing and retrieving an object: A class can be serialized to a


binary database field in much the same way as the image was in the
previous example. In this example, the RegistrationImpl class is
changed to support default serialization by adding implements
Serializable to the Class declaration.
Next, a ByteArrayInputStream is created to be passed as the JDBC Binary
Stream. To create the ByteArrayInputStream, RegistrationImpl is first
piped through an ObjectOutputStream to an underlying
ByteArrayInputStream with a call to RegistrationImpl.writeObject The
ByteArrayInputStream is then converted to a byte array, which can then
be used to create the ByteArrayInputStream. The create method in
RegistrationServer.java is changed as follows:
public registration.RegistrationPK create(
String theuser,
String password,
String emailaddress,
String creditcard)
throws registration.CreateException{
double balance=0;
Connection con = null;
PreparedStatement ps = null;;
try {
con=getConnection();
RegistrationImpl reg= new RegistrationImpl();
reg.theuser = theuser;
reg.password = password;
reg.emailaddress = emailaddress;
reg.creditcard = creditcard;

reg.balance = balance;
ByteArrayOutputStream regStore =
new ByteArrayOutputStream();
ObjectOutputStream regObjectStream =
new ObjectOutputStream(regStore);
regObjectStream.writeObject(reg);
byte[] regBytes=regStore.toByteArray();
regObjectStream.close();
regStore.close();
ByteArrayInputStream regArrayStream =
new ByteArrayInputStream(regBytes);
ps=con.prepareStatement(
"insert into registration (
theuser, theclass) values (?, ?)");
ps.setString(1, theuser);
ps.setBinaryStream(2, regArrayStream,
regBytes.length);

}
}
}
}

if (ps.executeUpdate() != 1) {
throw new CreateException ();
}
RegistrationPK primaryKey =
new RegistrationPKImpl();
primaryKey.theuser(theuser);
return primaryKey;
catch (IOException ioe) {
throw new CreateException ();
catch (CreateException ce) {
throw ce;
catch (SQLException sqe) {
System.out.println("sqe="+sqe);
throw new CreateException ();
finally {
try {
ps.close();
con.close();
} catch (Exception ignore) {
}

The object is retrieved and reconstructed by extracting the bytes from


the database, creating a ByteArrayInputStream from those bytes to be
read from an ObjectInputStream, and calling readObject to create the
instance again.
This next example shows the changes needed to the
RegistrationServer.refresh method to retrieve the registration instance
from the database.
private Registration refresh(RegistrationPK pk)
throws FinderException {

if (pk == null) {
throw new FinderException ();
}
Connection con = null;
PreparedStatement ps = null;
try {
con=getConnection();
ps=con.prepareStatement("
select theclass from
registration where theuser = ?");
ps.setString(1, pk.theuser());
ps.executeQuery();
ResultSet rs = ps.getResultSet();
if(rs.next()){
byte[] regBytes = rs.getBytes(1);
ByteArrayInputStream regArrayStream =
new ByteArrayInputStream(regBytes);
ObjectInputStream regObjectStream =
new ObjectInputStream(
regArrayStream);
RegistrationImpl reg=
(RegistrationImpl)
regObjectStream.readObject();
return reg;
}
else {
throw new FinderException ();
}
} catch (Exception sqe) {
System.out.println("exception "+sqe);
throw new FinderException ();
}
finally {
try {
rs.close();
ps.close();
con.close();
}
catch (Exception ignore) {}
}
}

BLOBs and CLOBs: Storing large fields in a table with the other data
is not necessarily the optimum place especially if the data has a
variable size. One way to handle large, variable sized objects is with
the Large Objects (LOBs) type. LOBs use a locator, essentially a
pointer, in the database record that points to the real database field.
There are two types of LOBs: Binary Large Objects (BLOBs) and
Character Large Objects (CLOBs). When you access a BLOB or CLOB,
the data is not copied to the client. To retrieve the actual data from a
result set, you have to retrieve the pointer with a call to BLOB

blob=getBlob(1) or CLOB clob=getClob(1), and then retrieve


a call to blob.getBinaryStream() or clob.getBinaryStream().

the data with

Controlling Transactions
By default, JDBC statements are processed in full auto-commit mode.
This mode works well for a single database query, but if an operation
depends on several database statements that all have to complete
successfully or the entire operation is cancelled, a finer transaction is
needed.
A description of transaction isolation levels is covered in more detail in
Chapter 3: Data and Transaction Management. To use transaction
management in the JDBC platform, you first need to disable the full
auto-commit mode by calling:
Connection con= getConnection();
con.setAutoCommit(false);

At this point, you can either commit any following JDBC statements or
undo any updates by calling the Connection.rollback method. The
rollback call is commonly placed in the Exception handler, although it
can be placed anywhere in the transaction flow.
This next example inserts an auction item and decrements the user's
balance. If the balance is less than zero, the entire transaction is rolled
back and the auction item is removed.
public int insertItem(String seller,
String password,
String description,
int auctiondays,
double startprice,
String summary) {
Connection con = null;
int count=0;
double balance=0;
java.sql.Date enddate, startdate;
Statement stmt=null;
PreparedStatement ps = null;
try {
con=getConnection();
con.setAutoCommit(false);
stmt= con.createStatement();
stmt.executeQuery(
"select counter from auctionitems");
ResultSet rs = stmt.getResultSet();
if(rs.next()) {
count=rs.getInt(1);

}
Calendar currenttime=Calendar.getInstance();
java.util.Date currentdate=currenttime.getTime();
startdate=new java.sql.Date(
currentdate.getTime());
currenttime.add(Calendar.DATE, auctiondays);
enddate=new java.sql.Date((
currenttime.getTime()).getTime());
ps=con.prepareStatement(
"insert into auctionitems(
id, description, startdate, enddate,
startprice, summary)
values (?,?,?,?,?,?)");
ps.setInt(1, count);
ps.setString(2, description);
ps.setDate(3, startdate);
ps.setDate(4, enddate);
ps.setDouble(5, startprice);
ps.setString(6, summary);
ps.executeUpdate();
ps.close();
ps=con.prepareStatement(
"update registration
set balance=balance -0.50
where theuser= ?");
ps.setString(1, seller);
ps.close();
stmt= con.createStatement();
stmt.executeQuery(
"select balance from registration
where theuser='"+seller+"'");
rs = stmt.getResultSet();
if(rs.next()) {
balance=rs.getDouble(1);
}
stmt.close();
if(balance <0) {
con.rollback();
con.close();
return (-1);
}
stmt= con.createStatement();
stmt.executeUpdate(
"update auctionitems set
counter=counter+1");
stmt.close();
con.commit();
con.close();
return(0);
} catch(SQLException e) {
try {
con.rollback();
con.close();
stmt.close();

ps.close();
}catch (Exception ignore){}
}
return (0);
}

Escaping Characters
The JDBC API provides the escape keyword so you can specify the
character you want to use to escape characters. For example, if you
want to use the percent sign (%) as the percent sign and not have it
interpreted as the SQL wildcard used in SQL LIKE queries, you have to
escape it with the escape character you specify with the escape
keyword.
This next statements shows how you would use the escape keyword to
look for the value 10%.
stmt.executeQuery(
"select tax from sales where tax like
'10\%' {escape '\'}");

If your program stores names and addresses to the database entered


from the command line or by way of a user interface, the single quotes
(') symbol might appear in the data. Passing single quotes directly into
a SQL string causes problems when the SQL statement is parsed
because SQL gives this symbol another meaning unless it is escaped.
To solve this problem, the following method escapes any ' symbol
found in the input line. This method can be extended to escape any
other characters such as commas , that the database or database
driver might interpret another way.
static public String escapeLine(String s) {
String retvalue = s;
if (s.indexOf ("'") != -1 ) {
StringBuffer hold = new StringBuffer();
char c;
for(int i=0; i < s.length(); i++ ) {
if ((c=s.charAt(i)) == '\'' ) {
hold.append ("''");
}else {
hold.append(c);
}
}
retvalue = hold.toString();
}
return retvalue;
}

However, if you use a PreparedStatement instead of a simple Statement,


most of these escape problems go away. For example, instead of this
line with the escape sequence:
stmt.executeQuery(
"select tax from sales where tax like
'10\%' {escape '\'}");

You could use this line:


preparedstmt = C.prepareStatement(
"update tax set tax = ?");

Mapping Database Types


Apart from a few JDBC types such as INTEGER that are represented as
an INTEGER in most popular databases, you might find that the JDBC
type for a table column does not match the type as it is represented in
the database. This means calls to ResultSet.getObject,
PreparedStatement.setObject and CallableStatement.getObject() will very
likely fail.
Your program can determine the database column type from the
database meta data and use that information to check the value before
retrieving it. This next code checks that the value is in fact type
INTEGER before retrieving its value.
int count=0;
Connection con=getConnection();
Statement stmt= con.createStatement();
stmt.executeQuery(
"select counter from auctionitems");
ResultSet rs = stmt.getResultSet();
if(rs.next()) {
if(rs.getMetaData().getColumnType(1) ==
Types.INTEGER) {
Integer i=(Integer)rs.getObject(1);
count=i.intValue();
}
}
rs.close();

Mapping Date types


The DATE type is where most mismatches occur. This is because the
java.util.Date class represents both Date and Time, but SQL has the
following three types to represent data and time information:
A DATE type that represents the date only (03/23/99).
A TIME type that specifies the time only (12:03:59)
A TIMESTAMP that represents time value in nanoseconds.

These three additional types are provided in the java.sql package as


java.sql.Date, java.sql.Time and java.sql.Timestamp and are all
subclasses of java.util.Date. This means you can use convert
java.util.Date values to the type you need to be compatible with the
database type.

Note: The Timestamp class loses precision when it is


converted to a java.util.Date because java.util.Date does
not contain a nanosecond field, it is better to not convert a
Timestampinstance if the value will be written back to the
database.

This example uses the java.sql.Date class to convert the java.util.Date


value returned by the call to Calendar.getTime to a java.sql.Date.
Calendar currenttime=Calendar.getInstance();
java.sql.Date startdate=
new java.sql.Date((
currenttime.getTime()).getTime());

You can also use the java.text.SimpleDateFormat class to do the


conversion. This example uses the java.text.SimpleDateFormat class to
convert a java.util.Date object to a java.sql.Date object:
SimpleDateFormat template =
new SimpleDateFormat("yyyy-MM-dd");
java.util.Date enddate =
new java.util.Date("10/31/99");
java.sql.Date sqlDate =
java.sql.Date.valueOf(
template.format(enddate));

If you find a database date representation cannot be mapped to a Java


type with a call to getObject or getDate, retrieve the value with a call to
getString and format the string as a Date value using the
SimpleDateFormat class shown above.

What is JServer and what is it used for?


Oracle JServer Option is a Java Virtual Machine (Java VM) which runs within the Oracle database server's
address space. Oracle also provides a JServer Accelerator to compile Java code natively. This speeds up the
execution of Java code by eliminating interpreter overhead.
Back to top of file

How does one install the Oracle JServer Option?


Follow these steps to activate the Oracle JServer/ JVM option:

Make sure your database is started with large java_pool_size (>20M) and shared_pool_size
(>50M) INIT.ORA parameter values.
Run the $ORACLE_HOME/javavm/install/initjvm.sql script from SYS AS SYSDBA to install the
Oracle JServer Option on a database.
Grant JAVAUSERPRIV to users that wants to use Java:
SQL> GRANT JAVAUSERPRIV TO SCOTT;

The rmjvm.sql script can be used to deinstall the JServer option from your database.
Follow the steps in the Oracle Migrations Guide to upgrade or downgrade the JServer option from one
release to another.
Back to top of file

How does one load Java Source code into the database?
Use the "CREATE OR REPLACE JAVA SOURCE" command or "loadjava" utility. See this script for an
example.
Loaded code can be viewed by selecting from the USER_SOURCE view.
Back to top of file

Why does one need to publish Java in the database?


Publishing Java classes on the database makes it visible on a SQL and PL/SQL level. It is important to
publish your code before calling it from SQL statements or PL/SQL code. Look at this example:
create or replace function hello (str varchar2) return varchar
as
language java name 'Hello.Msg(java.lang.String) return
java.lang.String';
/
Back to top of file

What is JDBC and what is it used for?


JDBC is a set of classes and interfaces written in Java to allow other Java programs to send SQL statements
to a relational database management system.
Oracle provides three categories of JDBC drivers:

JDBC Thin Driver (No local Net8 installation required/ handy for applets)
JDBC OCI for writing stand-alone Java applications
JDBC KPRB driver (default connection) for Java Stored Procedures and Database JSP's.

Oracle's JDBC Thin driver uses Java sockets to connect directly to Oracle. It provides its own TCP/IP
version of Oracle's Net8 (SQL*Net) protocol. Because it is 100% Java, this driver is platform independent
and can also run from a Web Browser (applets).
Oracle's JDBC OCI drivers uses Oracle OCI (Oracle Call Interface) to interact with an Oracle database.
You must use a JDBC OCI driver appropriate to your Oracle client installation. The OCI driver works
through either SQL*Net or Net8.

JDBC OCI7 works with an Oracle7 client.


JDBC OCI8 works with an Oracle8 client.

Either of these client versions can access Oracle7 or Oracle8 servers.


The JDBC OCI drivers allow you to call the OCI directly from Java, thereby providing a high degree of
compatibility with a specific Version of Oracle. Because they use native methods, they are platform
specific.
Oracle's JDBC KBPR driver is mainly used for writing Java stored procedures, triggers and database
JSPs. It uses the default/ current database session and thus requires no additional database username,
password or URL.
All three drivers support the same syntax and API's. Oracle needs three drivers to support different
deployment options. Looking at source code, they will only differ in the way you connect to the database.
Remember, you must use a JDBC version that matches the version of your Java Development Kit.
Back to top of file

How does one connect with the JDBC Thin Driver?


The the JDBC thin driver provides the only way to access Oracle from the Web (applets). It is smaller and
faster than the OCI drivers, and doesn't require a pre-installed version of the JDBC drivers.
import java.sql.*;
class dbAccess {
public static void main (String args []) throws SQLException
{
DriverManager.registerDriver (new
oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@qit-uq-cbiw:1526:orcl", "scott",
"tiger");
// @machineName:port:SID,
userid,
password
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select BANNER from
SYS.V_$VERSION");
while (rset.next())

System.out.println (rset.getString(1));
stmt.close();

// Print col 1

}
}
Back to top of file

How does one connect with the JDBC OCI Driver?


One must have Net8 (SQL*Net) installed and working before attempting to use one of the OCI drivers.
import java.sql.*;
class dbAccess {
public static void main (String args []) throws SQLException
{
try {
Class.forName ("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = DriverManager.getConnection
("jdbc:oracle:oci8:@qit-uq-cbiw_orcl", "scott", "tiger");
// or oci7 @TNSNames_Entry,
userid, password
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select BANNER from
SYS.V_$VERSION");
while (rset.next())
System.out.println (rset.getString(1));
// Print col 1
stmt.close();
}
}
Back to top of file

How does one connect with the JDBC KPRB Driver?


One can obtain a handle to the default or current connection (KPRB driver) by calling the
OracleDriver.defaultConenction() method. Please note that you do not need to specify a database URL,
username or password as you are already connected to a database session. Remember not to close the
default connection. Closing the default connection might throw an exception in future releases of Oracle.
import java.sql.*;
class dbAccess {
public static void main (String args []) throws SQLException
{
Connection conn = (new
oracle.jdbc.driver.OracleDriver()).defaultConnection();
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery("select BANNER from
SYS.V_$VERSION");
while (rset.next())
System.out.println (rset.getString(1));
// Print col 1
stmt.close();
}

}
Back to top of file

Where can one get more info about JDBC?

Download Sun's Java Developers Kit and various other API's


JDBC Guide: Getting Started
Download Oracle's JDBC Drivers
The comp.lang.java FAQ List

Back to top of file

What is SQLJ and what is it used for?


SQLJ is an ANSI standard way of coding SQL access in Java. It provides a Java precompiler that translates
SQLJ call to JDBC calls. The idea is similar to that of other Oracle Precompilers.
SQLJ is more concise and thus easier to write than JDBC, and provides compile-time schema validation
and syntax checking for easier debugging. SQLJ reads input either from a *.SQLJ file, or a Java source file
in which SQLJ statements are embedded. The SQLJ precompiler translates the SQLJ statements into their
equivalent JDBC calls. SQLJ supports static SQL.
Back to top of file

How does one write SQLJ programs?


See the Scripts and sample programs section for some SQLJ example programs.
Back to top of file

How does one deploy SQLJ programs?


Use the sqlj compiler to compile your *.sqlj files to *.java and *.ser files. The *.ser files contain vendor
specific database code. Thereafter one invokes the javac compiler to compile the .java files to *.class files.
The *.class and *.ser files needs to be deployed.
Back to top of file

Where can one get more info about SQLJ?

The SQLJ Organization


Sun's InfoBus Controls

Back to top of file

What is JDeveloper and what is it used for?

JDeveloper is the Oracle IDE (Integrated Development Environment) for developing SQLJ and JDBC
programs, applets, stored procedures, EJB's, JSP's etc.
JDeveloper are extremely resource hungry and requires a big workstation. However, it provides an
extremely productive environment for Java Developers.
Back to top of file

How does one set runtime parameter in JDeveloper?


Navigate to Project |--> Project Properties... |--> Run/Debug and enter field parameters. These parameters
will be picked up when you execute a Java program from JDeveloper.
public static void main(String[] args) { ...
Back to top of file

What is InfoBus DAC and what is it used for?


InfoBus DAC (Data Aware Controls) is a standard Java extension used in JDeveloper to create data aware
forms. It replaced the JBCL interface that were used in JDeveloper V1 and V2. More info about Infobus are
available from the following URL: java.sun.com/beans/infobus
To use InfoBus DAC, import javax.infobus.*; into your Java program.
Back to top of file

What is a JSP and what is it used for?


Java Server Pages (JSP) is a platform independent presentation layer technology that comes with SUN's
J2EE platform. JSPs are normal HTML pages with Java code pieces embedded in them. JSP pages are
saved to *.jsp files. A JSP compiler is used in the background to generate a Servlet from the JSP page.
Back to top of file

What is the difference between ASP and JSP?


Active Server Pages (ASP) is a Microsoft standard, which is easier to develop than Java Server Pages
(JSP). However ASP is a proprietary technology and is less flexible than JSP. For more information about
ASP, see the Oracle ASP FAQ.
Back to top of file

How does one invoke a JSP?


A JSP gets invoked when you call a *.jsp file from your Web Server like you would call a normal *.html
file. Obviously your web server need to support JSP pages and must be configured properly to handle them.
Back to top of file

How does a JSP gets executed?


The first time you call a JSP, a servlet (*.java) will be created and compiled to a .class file. The class file is
then executed on the server. Output produced by the servlet is returned to the web browser. Output will
typically be HTML or XML code.
Back to top of file

How does one write a JSP page?


You can use Oracle JDeveloper to create JSP pages. Alternatively you can open a standard text file and
code the required HTML and Java manually. Look at this example:
<HTML>
<BODY>
<% out.println("Hello World"); %> <P>
Today is: <%= new java.util.Date() %> <P>
Page generated with: <%= this.getServeleteInfo() %> <P>
Back to top of file

What is a Java Stored Procedure/ Trigger?


A Java Stored Procedure is a procedure coded in Java (as opposed to PL/SQL) and stored in the Oracle
database. Java Stored procedures are executed by the database JVM in database memory space.
Java Stored Procedures can be developed in JDBC or SQLJ. Interfacing between PL/SQL and Java are
extremely easy. Please note that Java Stored procedures are by default executed with invokers rights.
PL/SQL procedures are by default executed with defines rights.
Note: JSP is Java Server Pages and NOT Java Stored Procedures.
Back to top of file

How does one write a Java Stored Procedure?


Java Stored Procedures must comply with the following rules:
No constructor method is needed
Variables and methods must be declared static
Use the default database connection (no userid/ password required, run in session)
Declare output variables as arrays
public static void getEmpInfo(int empno, String[] empName, int[]
salary) {
Back to top of file

How does on load a Java Stored Procedure into the database?


Create a deployment profile from JDeveloper or use the loadjava command line utility.
Back to top of file

How does on drop a Java Stored Procedure from the database?

SQL*Plus: drop java class .../ drop package ... (drop the wrapper)
dropjava utility: dropjava -u scott/tiger myPackage.myClass

Back to top of file

How does on call/execute a Java Stored Procedure?

From SQL*Plus: Use execute or call


From JDBC: Use the CallableStatement object
From SQLJ: #sql { call ...} eg: #sql { call ACME.BEGINRENTAL(:in memberID, :in
employeeID, :out, ...) };

import java.sql.*;
public class CreateCoffees {
public static void main(String args[]) {
String url = "jdbc:mySubprotocol:myDataSource";
Connection con;
String createString;
createString = "create table COFFEES " +
"(COF_NAME VARCHAR(32), " +
"SUP_ID INTEGER, " +
"PRICE FLOAT, " +
"SALES INTEGER, " +
"TOTAL INTEGER)";
Statement stmt;
try {
Class.forName("myDriver.ClassName");
} catch(java.lang.ClassNotFoundException e) {
System.err.print("ClassNotFoundException: ");
System.err.println(e.getMessage());
}
try {
con = DriverManager.getConnection(url, "myLogin", "myPassword");
stmt = con.createStatement();
stmt.executeUpdate(createString);
stmt.close();
con.close();

} catch(SQLException ex) {
System.err.println("SQLException: " + ex.getMessage());
}
}
}
=============================================

Potrebbero piacerti anche