Introduction to JDBC Programming Oracle Korea 발 표 순 서발 표 순 서 Basic JDBC Programming...

Preview:

Citation preview

Introduction to

JDBC Programming

Oracle Korea

발 표 순 서

Basic JDBC Programming Advanced Programming JDBC 2.0 Features SQLJ Q&A

Basic JDBC Programming

Basic JDBC Programming

After completing this lesson, you should be able to do the following:

– Connect to a database using Java Database Connectivity (JDBC)

– Create and execute a query using JDBC– Invoke prepared statements – Commit and roll back transactions– Use the Oracle JDBC extensions to

improve performance

JDBC

JDBC is a standard interface for connecting to relational databases from Java.

The JDBC classes and interfaces are in the java.sql package.

JDBC 1.22 is part of JDK 1.1; JDBC 2.0 is part of Java 2

Query

Close

Connect

Processresults

Overview of Querying a Database With JDBC

Query

Close

Connect

Processresults

Register the driver

Connect to the database

Stage 1: Connect

Is an interpreter that translates JDBC method calls to vendor-specific database commands

Implements interfaces in java.sql Can also provide a vendor’s extensions to the

JDBC standard

DriverJDBC calls

Database commands

Database

A JDBC Driver

Oracle JDBC Driver

JDBC “Thin” driver (also available in server) JDBC “OCI” driver JDBC “Server-Side Internal” driver (Kernal PRogram

Bundled Calls driver)

JDBC “Thin”driver

Java SocketSQL*Net

JDBC “OCI”driver

OCI C Lib

SQL*Net

JDBC “Server-Side Internal”

driver

database Lib

SQL & PL/SQL Engines

JavaStore

ProcedureJava Engine

Oracle 8i

Oracle JDBC Drivers

Thin driver– a 100% Java driver for client-side use without an

Oracle installation, particularly with applets

OCI drivers (OCI8 and OCI7)– for client-side use with an Oracle client installation

server-side Thin driver– which is functionally the same as the client-side

Thin driver, but is for code that runs inside an Oracle server and needs to access a remote server, including middle-tier scenarios

server-side internal driver– for code that runs inside the target server

O7 or O8

Applet

JDBC

ClientClient ServerServer

Thin driver

Oracle JDBC Drivers: Thin Client Driver

Written entirely in Java Applets must use this driver

ClientClient ServerServer

O7 or O8

Application

JDBC

OCI driver

ocixxx.dll

Oracle JDBC Drivers: OCI Client Drivers

Written in C and Java Must be installed on the client

Oracle8Oracle8ii

Stored procedure

JDBC

Server side driver

C library

SQLEngine

Oracle JDBC Drivers: 3. Server-Side Driver

Runs inside the database Java stored procedures must use this

driver

Other JDBC Drivers

JDBC-ODBC Bridge– Translates JDBC into 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:<subprotocol>:<subname>

ProtocolDatabaseidentifier

jdbc:oracle:<driver>:@<database>

Subprotocol

About JDBC URLs

JDBC uses a URL to identify the database connection.

Thin driver

OCI driver

Server-side driver: Use the default connection

jdbc:oracle:thin:@<host>:<port>:<SID>

jdbc:oracle:oci8:@<TNSNAMES entry>

JDBC URLs with Oracle Drivers

DriverManager.registerDriver (neworacle.jdbc.driver.OracleDriver());

Connection conn = DriverManager.getConnection

(URL, userid, password);

Connection conn = DriverManager.getConnectionConnection conn = DriverManager.getConnection

("jdbc:oracle:thin:@myhost:1521:orcl", ("jdbc:oracle:thin:@myhost:1521:orcl",

"scott", "tiger");"scott", "tiger");

2. Connect to the database.2. Connect to the database.

How to Make the Connection 1. Register the driver.

Using Connection

java.sql.Connection Creating Statement

Transaction Management

Get database metadata

Conneciton related

createStatment()prepareStatment(String)prepareCall(String)

commit()rollback()

getMetaData()

close()isClosed()

Demonstration

Connection

Close

Connect

Query Create a statement

Processresults

Query the database

Stage 2: Query

The Statement Object

A Statement object sends your SQL statement to the database.

You need an active connection to create a JDBC statement.

Statement has three methods to execute a SQL statement:

– executeQuery() for QUERY statements– executeUpdate() for INSERT, UPDATE,

DELETE, or DDL statements– execute() for either type of statement

Statement stmt = conn.createStatement();

ResultSet rset = stmt.executeQuery(statement);

int count = stmt.executeUpdate(statement);

boolean isquery = stmt.execute(statement);

How to Query the Database

1. Create an empty statement object.

2. Execute the statement.

Statement stmt = conn.createStatement();

ResultSet rset = stmt.executeQuery

("select RENTAL_ID, STATUS from

ACME_RENTALS");

Statement stmt = conn.createStatement();

int rowcount = stmt.executeUpdate

("delete from ACME_RENTAL_ITEMS

where rental_id = 1011");

Querying the Database: Examples

Execute a select statement.

• Execute a delete statement.

Close

QueryStep through the results

Processresults

Assign results to Java variables

Connect

Stage 3: Process the Results

The ResultSet Object

JDBC returns the results of a query in a ResultSet object.

A ResultSet maintains a cursor pointing to its current row of data.

Use next() to step through the result set row by row.

getString(), getInt(), and so on assign each value to a Java variable.

while (rset.next()) { … }

String val =

rset.getString(colname);

while (rset.next()) {

String title = rset.getString("TITLE");

String year = rset.getString("YEAR");

… // Process or display the data

}

String val =

rset.getString(colIndex);

How to Process the Results 1. Step through the result set.

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

while (rset.next()) { String year = rset.getString("YEAR"); if (rset.wasNull() { … // Handle null value }…}

How to Handle SQL Null Values

Java primitive types cannot have null values.

Do not use a primitive type when your query might return a SQL null.

Use ResultSet.wasNull() to determine whether a column has a null value.

Mapping Database Types to Java TypesMapping Database Types to Java Types

ResultSet maps database types to Java types.

ResultSet maps database types to Java types.

ResultSet rset = stmt.executeQuery ("select RENTAL_ID, RENTAL_DATE, STATUS from ACME_RENTALS");

int id = rset.getInt(1);Date rentaldate = rset.getDate(2); String status = rset.getString(3);

Col Name

RENTAL_ID

RENTAL_DATE

STATUS

Type

NUMBER

DATE

VARCHAR2

Connect

Query

Processresults

Close

Close the result set

Close the statement

Close the connection

Stage 4: Close

1. Close the ResultSet object.

2. Close the Statement object.

3. Close the connection (not necessary for server-side driver).

rset.close();

stmt.close();

conn.close();

How to Close the Connection

Demonstration

A Simple JDBC Program

The DatabaseMetaData Object

The Connection object can be used to get a DatabaseMetaData object.

This object provides more than 100 methods to obtain information about the database.

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

How to Obtain Database Metadata

1. Get the DatabaseMetaData object.

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

DatabaseMetaData dbmd =

conn.getMetaData();

The ResultSetMetaData Object

The ResultSet object can be used to get a ResultSetMetaData object.

ResultSetMetaData object provides metadata, including:

– Number of columns in the result set– Column type– Column name

How to Obtain Result Set Metadata

1. Get the ResultSetMetaData object.

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

ResultSetMetaData rsmd = rset.getMetaData();for (int i = 0; i < rsmd.getColumnCount(); i++) { String colname = rsmd.getColumnName(i); int coltype = rsmd.getColumnType(i); … }

ResultSetMetaData rsmd = rset.getMetaData();

DemonstrationDynamic Query using MetaData

The PreparedStatement Object

A PreparedStatement object holds precompiled SQL statements.

Use this object for statements you want to execute more than once.

A prepared statement can contain variables that you supply each time you execute the statement.

How to Create a Prepared Statement

1.Register the driver and create the database connection.

2.Create the prepared statement, identifying variables with a question mark (?). PreparedStatement pstmt = conn.prepareStatement("update ACME_RENTALS set STATUS = ? where RENTAL_ID = ?");

PreparedStatement pstmt = conn.prepareStatement("select STATUS from ACME_RENTALS where RENTAL_ID = ?");

How to Execute a Prepared Statement

1. Supply values for the variables.

2. Execute the statement.

pstmt.setXXX(index, value);

pstmt.executeQuery();

pstmt.executeUpdate();

PreparedStatement pstmt = conn.prepareStatement("update ACME_RENTALS set STATUS = ? where RENTAL_ID = ?");pstmt.setString(1, "OUT");pstmt.setInt(2, rentalid);pstmt.executeUpdate();

The CallableStatement Object

A CallableStatement object holds parameters for calling stored procedures.

A callable statement can contain variables that you supply each time you execute the call.

When the stored procedure returns, computed values (if any) are retrieved through the CallabableStatement object.

CallableStatement cstmt = conn.prepareCall("{call " + ADDITEM + "(?,?,?)}"); cstmt.registerOutParameter(2,Types.INTEGER); cStmt.registerOutParameter(3,Types.DOUBLE);

How to Create a Callable Statement

Register the driver and create the database connection.

Create the callable statement, identifying variables with a question mark (?).

1. Set the input parameters.

2. Execute the statement.

3. Get the output parameters.

1. Set the input parameters.

2. Execute the statement.

3. Get the output parameters.

How to Execute a Callable StatementHow to Execute a Callable Statement

cstmt.setXXX(index, value);

cstmt.execute(statement);

var = cstmt.getXXX(index);

Using Transactions

The server-side driver does not support autocommit mode.

With other drivers:– New connections are in autocommit

mode. – Use conn.setAutoCommit(false) to

turn autocommit off.

To control transactions when you are not in autocommit mode:

– conn.commit(): Commit a transaction– conn.rollback(): Roll back a transaction

PreparedStatement

CallableStatement

Oracle JDBC Extensions Oracle JDBC Extensions

Oracle provides many extensions to standard JDBC;

for example:

Oracle provides many extensions to standard JDBC;

for example:Connection

Statement

ResultSet

OraclePreparedStatement

OracleCallableStatement

OracleStatement

OracleResultSet

OracleConnection

Advanced Programming

Advanced Programming

LOB Data type Advanced data type

LOB Data type

oracle.sql.BLOB – java.sql.Blob– Processing locator : getBLOB(), setBLOB()

methods using jdk1.2.x

oracle.sql.CLOB– java.sql.Clob– Processing locator : getCLOB(), setCLOB()

methods using jdk1.2.x

oracle.sql.BFILE– Oracle Specific Datatype

BLOB

Reading– getBinaryStream() 메서드 사용 .– Return 된 InputStream 을 이용하여 처리 (

파일 , 데이터베이스 )

Writing– getBinaryOutputStream() 메서드 사용– java.io.OutputStream 객체를 이용하여

Writing

BLOB : Reading

Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery

(“select blob_column from blob_table”);while (rs.next()){BLOB blob = ((OracleResultSet)rs).getBLOB(1);InputStream is = blob.getBinaryStream();int read = 0;while ( (read = is.read()) != -1){// to do like writing a file using the stream}is.close();}

1. create statement

2. create resultset

3. get Blob locator

4. get InputStream

5. InputStream 처리

6. InputStream close

BLOB : Writing

Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery (“select blob_column from blob_table for update”);while (rs.next()){BLOB blob = ((OracleResultSet)rs).getBLOB(1);OutputStream os = blob.getBinaryOutputStream();InputStream src = new InputStream(…);byte [] buffer = new byte[1024];int read = 0;while ( (read = src.read(buffer)) != -1){os.write(buffer, 0, read); // write blob.}src.close();os.close();}

1. create statement

2. create resultset

3. get Blob locator

4. get OutputStream

5. Source read

6. write blob

7. close stream

CLOB

Reading– getAsciiStream() : 아스키 스트림– getCharacterStream() : 유니코드 스트림 .– Return 된 InputStream 을 이용하여 처리 (

파일 , 데이터베이스에 Writing) • Writing

– getAsciiOutputStream() 메서드 사용해서 locator 획득

– getCharacterOutputStream() 메서드 사용 .– java.io.OutputStream 객체를 이용하여

Writing

CLOB : Reading

Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery

(“select clob_column from clob_table”);while (rs.next()){CLOB blob = ((OracleResultSet)rs).getCLOB(1);Reader reader = clob.getCharacterStream();char [] buffer = new char[10];int length = 0;while ( (length = reader.read (buffer)) != -1){System.out.println (new String(buffer));}is.close();}

1. create statement

2. create resultset

3. get Clob locator

4. get InputStream

5. InputStream 처리

6. InputStream close

CLOB : Writing

Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery (“select clob_column from clob_table for update”);while (rs.next()){ CLOB clob = ((OracleResultSet)rs).getCLOB(1); Writer writer = clob.getCharacterOutputStream(); FileInputStream src = new FileInputStream(“tmp”); byte [] buffer = new byte[512]; int read = 0; while ( (read = src.read(buffer)) != -1) { writer.write(buffer, 0, read); // write clob. } src.close(); writer.close();}

1. create statement

2. create resultset

3. get clob locator

4. get OutputStream

5. Source read

6. write clob

7. close stream

BFILE

Locator : – getOracleObject(), getBFILE() 메서드 이용

oracle.sql.BFILE methods– fileExists(), isFileOpen() 메서드– openFile(), closeFile()

Creating a BFILE column Reading Writing

BFILE : Creating a BFILE column

cmd ="INSERT INTO my_bfile_table VALUES (’one’, bfilename(test_dir,’file1.data’))";

stmt.execute (cmd);

cmd ="INSERT INTO my_bfile_table VALUES (’three’, null)";

stmt.execute(cmd);

BFILE : Processingcmd = "SELECT * FROM my_bfile_table WHERE x = ’one’";

rset = stmt.executeQuery (cmd);

if (rset.next ()) {

BFILE bfile = ((OracleResultSet)rset).getBFILE (2);

bfile.openFile();

InputStream in = bfile.getBinaryStream();

int length ;

byte[] buf = new byte[512];

while ((length = in.read(buf)) != -1)

{

// to do something using byte buffer

}

in.close();

bfile.closeFile();

1. select the locator

2. Open the bfile

3. get a binary stream

4. InputStream 처리

5. Close resoruce

DemonstrationLOB Data Handling

Advanced data type

STRUCT Customized mapping ARRAY REF

Struct

The Oracle JDBC drivers materialize database objects as instances of Java objects

Multiple ways to map between Java and SQL:– Default Mapping: JDBC materializes the object as an

oracle.sql.STRUCT– Customized mappings: You explicitly specify mappings

between database objects and Java classes

SQLData CustomDatum

JPublisher can help generate CustomDatum and SQLData mappings

Default Mapping -- oracle.sql.STRUCT

Holds the pickle image (in the low level storage format)

Contains a “values” array of oracle.sql.Datum objects

Each attribute is already in its true data type getAttribute() retrieves values array as

java.lang.Object[] Casts Struct to oracle.sql.STRUCT to use oracle.sql

extensions– getOracleAttributes() returns value array as oracle.sql

objects (native SQL format)

getSQLTypeName() retrieves object type name References StructDescriptor for type information

Access Data in oracle.sql.STRUCT

ResultSet rset = st.executeQuery("select * from hr_table");while(rset.next()){ System.out.println(rset.getString(1)); // SSN STRUCT s = (STRUCT) rset.getObject(2); // Person Object[] attrs = s.getAttributes(); System.out.println(((BigDecimal) attrs[0]).intValue()); System.out.println((String) atts[0]);}

Person(empid, name)

ResultSet

SSN

oracle.sql.STRUCT

(0)

(1)(1001, ’Scott’)(1002, ‘Alice’)...

1001‘Scott’

Object [ ]

rset.getObject(2) orrset.getSTRUCT(2)

s.getAttributes()

s

Customized Mapping

You can specify how our drivers materialize object data

– The JDBC 2.0 way -- SQLData– The Oracle way -- CustomDatum

The custom Java class you create must implement one of these interfaces

Two steps:– step 1) create the customized class– step 2) register the customized mapping

Implementing SQLData

public class JCustomer implements java.sql.SQLData { private String sql_type; public int custNo; public String custName;

public String getSQLTypeName() throws SQLException { return sql_type; } public void readSQL (SQLInput stream, String typeName) throws SQLException { sql_type = typeName; custNo = stream.readInt(); custName = stream.readString(); } public void writeSQL (SQLOutput stream) throws SQLException { stream.writeInt(custNo); stream.writeString(custName); }}

Reading & Writing SQLData

//put an entry in the typemap

Map map = conn.getTypeMap(); // Dictionary in JDK 1.1.x

map.put("CUSTOMER_INFO_T", Class.forName("JCustomer"));

ResultSet rs =

stmt.executeQuery("select VALUE p from CUSTOMER_TAB p");

while (rs.next())

{

//retrieve the object

JCustomer jc = (JCustomer) rs.getObject(1);

PreparedStatement pstmt = conn.prepareStatement

("INSERT INTO NEW_CUSTOMER_TAB VALUES (?)");

pstmt.setObject(1, jc); // insert the object

pstmt.executeUpdate();

}

CustomDatum

A flexible, efficient and powerful mapping

You need to provide two classes:– one that implements the

CustomDatumFactory interface

– one that implements CustomDatum

– The factory is used to generate the instance of type CustomDatum

Can be used for any customized conversion

Implementing CustomDatum & CustomDatumFactory

public class JCustomer implements oracle.sql.CustomDatum

{

public Datum toDatum (OracleConnection c) throws SQLException

{ StructDescriptor sd =

StructDescriptor.createDescriptor(“CUSTOMER_INFO_T",c);

Object [] attributes = { empName, empNo };

return new STRUCT(sd, c, attributes);

}

}

public class JCustomerFactory implement oracle.sql.CustomDatumFactory

{

public CustomDatum create(Datum d, int sqlType) throws SQLException

{

if (d == null) return null;

Object [] attributes = ((STRUCT) d).getAttributes();

return new JCustomer(attributes[0], attributes[1]);

}

}

Reading & Writing CustomDatum

Statement s = conn.createStatement();OracleResultSet rs = (OracleResultSet) s.executeQuery("SELECT VALUE p FROM CUSTOMER_TAB p");while(rs.next()) { // retrieve the CustomDatum object Jcustomer jc = (JCustomer) rs.getCustomDatum (1, new JCustomDatumFactory()); PreparedStatement pstmt = conn.prepareStatement ("INSERT INTO NEW_CUSTOMER_TAB VALUES (?)"); // inserts a CustomDatum object pstmt.setObject(1, jc); pstmt.executeUpdate();}

Array

Accesses collection types in database Handles both VARRAY and Nested Table oracle.sql.ARRAY holds the pickle image or

locator bytes References ArrayDescriptor for type

information getArray() retrieves the array contents in

“default” JDBC types getOracleArray() retrieves elements in

oracle.sql format getResultSet() retrieves elements as a

ResultSet

Access Data in Array

ResultSet rset = st.executeQuery("select * from hr_table");while(rset.next()){ System.out.println(rset.getString(1)); // Name ARRAY s = (ARRAY) rset.getObject(2); // Phones Object[] elems = s.getArray(); // retrieve elements for (int i<0; i<elems.length; i++) System.out.println((String) elems[i]);}

Phonesvarray(10) of varchar2(25)

ResultSet

Name

oracle.sql.ARRAY

(0)

(1)(‘111-2222’, ‘222-3333’)(‘333-4444’)...

‘111-2222’

‘‘222-3333’

Object [ ]

rset.getObject(2) orrset.getArray(2) orrset.getARRAY(2)

s.getArray()‘Scott’‘Alice’...

s

Ref

Accesses object reference in database oracle.sql.REF holds the ref getValue() to dereference setValue() to update the referenced

object in the database immediately

Access Data using REF

ResultSet rset = st.executeQuery("select name, ref(p) from people p");

while(rset.next()){ System.out.println(rset.getString(1)); // Name REF r = (REF)rset.getObject(2); // ADDR REF STURCT addr = r.getValue(); // get ADDR struct Object [] elems = addr.getAttributes(); // retrive attributes for (int i<0; i<elems.length; i++) System.out.println((String) elems[i]);}

name varchar2,col1 REF ADDR

ResultSet

PEOPLE(‘Samsung-dong’,144-17)

oracle.sql.REF

(‘sam’ 0000280209420D2400 ….)

ADDR(street_name, house_no)

rset.getObject(2) orrset.getREF(2) or rset.getRef(2)

r.getValue()

(‘sam’,addr1)

ref

DemonstrationAdvanced Data type

JDBC 2.0 Features

JDBC 2.0 Features

ResultSet enhancements Batch updates Statement Caching JNDI Connection Pooling & Caching Distributed Transactions

ResultSet enhancements

Scrollability– The ability to move backward as well as forward

through a result set.– The ability to move to any particular position in

the result set– Sensitivity must be specified. Sensitivity can

detect whether data is changed or not. – Sensitive or Insensitive Mode

Updatability– Can insert, modify, delete using while navigating

a resultset

6 Types of ResultSet

forward-only/read-only forward-only/updatable scroll-sensitive/read-only scroll-sensitive/updatable scroll-insensitive/read-only scroll-insensitive/updatable

Scrollable Resultset

Scrollable ResultSet

next()previous()relative()absolute()first()last()

Cursor Table

Oracle 8i

Statement stmt = conn.createStatemen(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCURR_READ_ONLY);

ResultSet rset =stmt.executeQuery();

rset.absolute(2);...

Java Program

Cache

APIs

Statement createStatement (int resultSetType, int resultSetConcurrency)

PreparedStatement prepareStatement (String sql, int resultSetType, int resultSetConcurrency)

CallableStatement prepareCall (String sql, int resultSetType, int resultSetConcurrency)

java.sql.Connection

ResultSet.TYPE_FORWARD_ONLY

ResultSet.TYPE_SCROLL_INSENSITIVE

ResultSet.TYPE_SCROLL_SENSITIVE

ResultSet.CONCUR_READ_ONLY

ResultSet.CONCUR_UPDATABLE

resultSetType resultSetConcurrency

APIs

void beforeFirst() throws SQLException

void afterLast() throws SQLException

boolean first() throws SQLException

boolean last() throws SQLException

boolean absolute(int row) throws SQLException

boolean relative(int row) throws SQLException

java.sql.ResultSet

void deleteRow(int row) throws SQLException

void updateXXX(int idx, XXX x) throws SQLException

void updateRow() throws SQLException

void moveToInsertRow () throws SQLException

void moveToCurrentRow() throws SQLException

void insertRow() throws SQLException

Example : Backward

Statement stmt = conn.createStatement

(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp");

rs.afterLast();

while ( rs.previous() )

{

System.out.println(rs.getString("empno") + " " + rs.getFloat("sal"));

}

...

Example : delete row

...

rs.absolute(5);

rs.deleteRow();

...

Example : update rowStatement stmt = conn.createStatement

(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp");

if (rs.absolute(10)) // (returns false if row does not exist)

{

rs.updateString(1, "28959");

rs.updateFloat("sal", 100000.0f);

rs.updateRow();

}

// Changes will be made permanent with the next COMMIT operation.

...

Example : insert row...

Statement stmt = conn.createStatement

(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp");

rs.moveToInsertRow();

rs.updateString(1, "28959");

rs.updateFloat("sal", 100000.0f);

rs.insertRow();

// Changes will be made permanent with the next COMMIT operation.

rs.moveToCurrentRow(); // Go back to where we came from...

...

Visibility of Internal & External Changes

Detection of External Changes– no use of rowDeleted(), rowUpdated(), rowInserted()

Oracle Implementation of Scroll-Sensitive Result Sets– the concept of a window based on the fetch size

refreshRow()

forward-only

scroll-sensitive

scroll-insensitive

Can SeeInternalDELETE?

Can SeeInternalUPDATE?

Can SeeInternalINSERT?

Can SeeExternalDELETE?

Can SeeExternalUPDATE?

Can SeeExternalINSERT?

no

yes

yes

yes

yes

yes

no

no

no

no

no

no

no

yes

no

no

no

no

Demonstration

ResultSet

Batch updates

Grouping multiple UPDATE, DELETE, or INSERT statements into a single "batch“

Performance improvement because of reducing round trip !!

Two type of batch update– Standard model : Sun’s JDBC Spec. since 8.1.6– Oracle specific model : Oracle’s implementation.

since 8.1.5

Don’t mix these types in a single connection

Batch update : Oracle specific model

Oracle model use batch value and results in implicit processing.

The driver knows ahead of time how many operations will be batched.

Only OraclePreparedStatement is suppored. Casting is required.

batch value : 5 ~ 30 (default 1) sendBatch() method will be executed, when

– commit() method call– statement’close() method call– connection’ close() method call

Examples : Oracle SpecificPreparedStatement ps = conn.prepareStatement("insert into dept values (?, ?, ?)");

//Change batch size for this statement to 3

((OraclePreparedStatement)ps).setExecuteBatch (3);

ps.setInt(1, 23);

ps.setString(2, "Sales");

ps.setString(3, "USA");

ps.executeUpdate(); //JDBC queues this for later execution

//Third insert statement

ps.setInt(1, 26);

ps.setString(2, "HR");

ps.setString(3, "Mongolia");

ps.executeUpdate(); //JDBC send the requests to the database

((OraclePreparedStatement)ps).sendBatch(); // JDBC sends the queued request

conn.commit();

ps.close();

Batch update : Standard model

Explicitly add statement to the batch using addBatch() method

explicitly executing the batch using an executeBatch() method after finish to add batch.

Statement, PreparedStatement, CallableStatement are supported.

Example : Standardconn.setAutoCommit(false);

PreparedStatement pstmt =

conn.prepareStatement("INSERT INTO employees VALUES(?, ?)");

pstmt.setInt(1, 2000);

pstmt.setString(2, "Milo Mumford");

pstmt.addBatch();

pstmt.setInt(1, 3000);

pstmt.setString(2, "Sulu Simpson");

pstmt.addBatch();

int[] updateCounts = pstmt.executeBatch();

conn.commit();

pstmt.close();

...

Performance Issues

– Disable Auto-Commit Mode 매번 커밋하지 않고 필요할 때에만 , 커밋하도록 한

다 . 기본적으로 'auto-commit' 으로 되어 있다 .– Prefetch Rows

질의 시 , 클라이언트가 미리 패치하는 행의 수 명시 . 기본적으로는 10 개의 행을 패치한다 .

– Batch Updates 오라클 JDBC 드라이버에서는 삽입 /갱신 작업을

배치 작업으로 처리할 수 있다 .– Define Column types

데이터베이스에게 타입을 알려주는 팁 설정 . 데이터 베이스 컬럼 알기 위한 network round-trip 을 줄일 수 있다 .

Performance Issues Disable Auto-Commit Mode

Prefetch Rows

Batch Updates

Define Column types

conn.setAutoCommit (false);

conn.setDefaultRowPrefetch (20);

conn.setDefaultExecuteBatch (10);

stmt.setExecuteBatch (15);

stmt.defineColumntype (1, <type> );

stmt.defineColumnType (1, <type>, <length> );

Statement Caching

Performance Improved by Caching Executable Statements

– Repeated use (e.g. loop) prevent the overhead of repeated cursor

creation prevent repeated statement parsing and

creation– Cache statements associated with a particular

physical connection– Two Types

implicit explicit

Using Statement Caching

Enabling and Disabling Statement Caching((OracleConnection)conn).setStmtCacheSize(10)

((OracleConnection)conn).setStmtCacheSize(0);

Checking for Statement Creation Statusint state = ((OracleStatement)stmt).creationState()

Physically Closing a Cached Statement– The close() method of a statement object caches the

statement instead of closing it.

Using Implicit Statement Caching Using Explicit Statement Caching

((OraclePreparedStatement(pstmt).closeWithKey(“mykey”);

pstmt=((OracleConnection)conn).prepareStatementWithKey(“mykey”);

JNDI JNDI(Java Naming and Directory Interface) can be

used in addition to the JDBC driver manager to manage data sources and connections.

Don’t care about JDBC connection string. It isn’t hard coded anymore.

Can access databases using their names not connection string.

Steps– creating datasource : set datasource’s properties– Register : register connection properties to JNDI Server– Lookup : find datasource object using given name within

JNDI Server.– Create Connection : using datasource

Example : JNDI// Creating

OracleDataSource ods = new OracleDataSource();

ods.setDriverType("oci8");

ods.setServerName("dlsun999");

ods.setNetworkProtocol("tcp");

ods.setDatabaseName("816");

ods.setPortNumber(1521);

ods.setUser("scott");

ods.setPassword("tiger");

// Register

Context ctx = new InitialContext();

ctx.bind("jdbc/sampledb", ods);

Example : JNDI

// lookup and create connection

OracleDataSource odsconn = (OracleDataSource)ctx.lookup("jdbc/sampledb");

Connection conn = odsconn.getConnection();

...

Connection Pooling

Connection pooling is a framework for caching database connection

reuse of physical connections. reduce overhead of creating new connections.

Connection pool data source– Factory to creating pooled connections

Pooled connection– represents a physical connection to a data source.– Factory for the Connection Objects.

Connection Cache

Connection Pooling

Connection

PooledConnection

ConnectionEvent

ConnectionPoolDataSource

ConnectionEventListener

getPooledConnection

getConnection

( close or error event)

Connection Pooling : APIpublic interface ConnectionPoolDataSource

{

PooledConnection getPooledConnection() throws SQLException;

PooledConnection getPooledConnection(String user, String password)

throws SQLException;

}

public interface PooledConnection

{

Connection getConnection() throws SQLException;

void close() throws SQLException;

void addConnectionEventListener(ConnectionEventListener listener) ... ;

void removeConnectionEventListener(ConnectionEventListener listener);

void setStmtCacheSize(int size);

void setStmtCacheSize(int size, boolean clearMetaData);

int getStmtCacheSize();

}

Example : Connection Pooling// Create a OracleConnectionPoolDataSource instance

OracleConnectionPoolDataSource ocpds =

new OracleConnectionPoolDataSource();

// Set connection parameters

ocpds.setURL("jdbc:oracle:oci8:@");

ocpds.setUser("scott");

ocpds.setPassword("tiger");

// Create a pooled connection

PooledConnection pc = ocpds.getPooledConnection();

// Get a Logical connection

Connection conn = pc.getConnection();

1. Creating ConnectionPoolDataSource

2. Creating PooledConnection

3. Creating Connection Object

Connection Cache

JDBC 2.0 doesn’t mandate that JDBC vendors provide one, but they highly recommend it

2-fold strategy– We implemented a cache with 3

commonly used schemes– Provide an interface for the end user to

develop their own cache but they still would like to reuse OracleConnectionEventListener

OracleConnectionCache

An interface one needs to implement if they like to have their own Cache but reuse our infrastructure

Extends DataSource interface Additional methods

– reusePooledConnection(PooledConnection)

– closePooledConnection(PooledConnection)

– close

OracleConnectionCacheImpl

Oracle’s implementation of a basic Cache

Extends OracleDataSource and implements OracleConnectionCache

JNDI Referenceable Implements java.io.Serializable Simple, Easy and Efficient 3 Schemes are provided

OracleConnectionCacheImpl

Dynamic : A typical grow and shrink scheme. Could create new connections beyond the maximum limit when all the existing ones are active. This is the default Scheme.

Fixed with No Wait : Request for new connections beyond the maximum limit will return null.

Fixed With Wait : Request for new connections are blocked when all the connections in the cache up to the limit are active and consumed.

OracleConnectionCacheImpl

All Connections in a cache are to the same Database and have the schema

Connections obtained are logical connections

Connection Properties can be set in 2 ways

– Set Properties directly like on DataSource– Through a ConnectionPoolDataSource

Demonstration

Connection Pooling

Distributed Transactions

A set of two or more related transactions that must be managed in a coordinated way.

Global transaction vs Branch transaction X/Open Standard : XA. not specific java Each transaction is managed by Transaction

Manager that implements Java Transaction API (JTA).

XA functionality is usually isolated from a client application, being implemented instead in a middle-tier environment such as an application server.

Distributed Transactions : XA Components

XA data source – extensions of connection pool data sources and other data sources,

and similar in concept and functionality.

XA connection– extensions of pooled connection

XA resource– Database resource– XA connection : XA resource = 1:1– Physical DB session : XA resource = 1:1

Transaction ID– Identifier of each transaction branch.

Distributed Transactions : XA APIs

oracle.jdbc.xa package– OracleXid– OracleXAException

oracle.jdbc.xa.client package– XADatasource, XAConnection, XAResource– outside Oracle database

oracle.jdbc.xa.server package– XADatasource, XAConnection, XAResource– inside Oracle database

Distributed Transactions : XA APIs

public interface XADatasource . XAConnection getXAConnection() throws SQLException

public interface XAConnection extends PooledConnection . XAResource getXAResource() throws SQLException;

public interface XAResource . void commit(Xid xid, boolean onePhase) throws XAException; . void end(Xid xid, int flags) throws XAException; . void forget(Xid xid) throws XAException; . int prepare(Xid xid) throws XAException; . Xid[] recover(int flag) throws XAException; . void rollback(Xid xid) throws XAException; . void start(Xid xid, int flags) throws XAException; . boolean isSameRM(XAResource xares) throws XAException;

Example : Distributed TransactionXA with Two-Phase Commit Operation

1. Start transaction branch #1.

2. Start transaction branch #2.

3. Execute DML operations on branch #1.

4. Execute DML operations on branch #2.

5. End transaction branch #1.

6. End transaction branch #2.

7. Prepare branch #1.

8. Prepare branch #2.

9. Commit branch #1.

10. Commit branch #2.

SQLJ

SQLJ

Standard way to embed SQL statements in Java programs.

More concise than JDBC Early checking of SQL statements

eliminates many run time errors: – SQL syntax errors– Incorrect assumption of table structures– Java/SQL type mismatch

Comparing SQLJ with JDBC

java.sql.PreparedStatement stmt;

stmt = conn.prepareStatement (“INSERT INTO emp ” + “VALUES(?, ?, ?, ?, ?”);

stmt.setString(1, name);stmt.setInt(2, dept);stmt.setString(3, mgr);stmt.setDouble(4, sal);stmt.setDate(5,today);

stmt.execute();

stmt.close();

JDBC

#sql { INSERT INTO emp VALUES (:name,:dept,:mgr, :sal,:today)};

SQLJ

What you need to learn

SQLJ program template Issuing a query Updating a table using a statement

with bind variables

SQLJ Program TemplateSQLJ Program Template

import java.sql.*; // Program uses JDBC

import oracle.sqlj.runtime.*; // and SQLJ

class Example1 {

public static void main (String args [])

throws SQLException {

// Your SQLJ code goes here

}

}

import java.sql.*; // Program uses JDBC

import oracle.sqlj.runtime.*; // and SQLJ

class Example1 {

public static void main (String args [])

throws SQLException {

// Your SQLJ code goes here

}

}

SQLJ clauses

• A executable SQLJ clause has this form:

• The SQL statement appears inside the curly braces:

#sql { DELETE FROM tab WHERE col < 0 };

#sql { SQL-statement } ;

Doing a Query

Define an Iterator Type Create instances of the Iterator Type Populate Iterator with results from

query Use Iterator methods to access the

data

Define an Iterator TypeDefine an Iterator Type

• The Iterator definition lists the SQL names and the Java types of the result columns

A class EmpCursor will be produced with the following methods:

• The Iterator definition lists the SQL names and the Java types of the result columns

A class EmpCursor will be produced with the following methods:

boolean next(); //Moves to next row, if any

String ENAME(); //Gets column ENAME as String

Double SAL(); //Gets column SAL as Double

#sql iterator EmpCursor (String ENAME, Double SAL);

Use the Iterator Type to do a Query

• Declare variable of the Iterator Type

• Populate iterator with results from query

• Use the Iterator methods to access data

• Declare variable of the Iterator Type

• Populate iterator with results from query

• Use the Iterator methods to access data

EmpCursor c;

#sql c = {select ENAME, SAL from EMP};

while (c.next ()) {

String ename = c.ENAME ();

Double sal = c.SAL ();

}

How to do an Update

• The SQL statement may have Java bind variables prefixed with a colon ':'

• The SQL statement may have Java bind variables prefixed with a colon ':'

String ename = “Seik Waljay”;

Double sal = 15000;

#sql { update EMP set SAL = :sal

where ENAME = :ename };

Q & A