Introduction to JDBC Programming
Download
Report
Transcript Introduction to JDBC Programming
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
Overview of Querying a Database
With JDBC
Connect
Query
Process
results
Close
Stage 1: Connect
Connect
Register the driver
Query
Connect to the database
Process
results
Close
A JDBC Driver
Is an interpreter that translates JDBC method calls
to vendor-specific database commands
Database
commands
JDBC calls
Driver
Database
Implements interfaces in java.sql
Can also provide a vendor’s extensions to the JDBC
standard
Oracle JDBC Driver
Oracle 8i
JDBC “Thin”
driver
Java Socket
JDBC “OCI”
driver
SQL*Net
SQL*Net
OCI C Lib
Java
Store
Procedure
SQL & PL/SQL
Engines
JDBC “Thin” driver (also available in server)
JDBC “OCI” driver
Java Engine
JDBC “ServerSide Internal”
driver
database Lib
JDBC “Server-Side Internal” driver (Kernal PRogram Bundled
Calls driver)
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 middletier scenarios
server-side internal driver
–
for code that runs inside the target server
Oracle JDBC Drivers: Thin Client Driver
Written entirely in Java
Applets must use this driver
Applet
JDBC
Thin driver
O7 or O8
Client
Server
Oracle JDBC Drivers: OCI Client Drivers
Written in C and Java
Must be installed on the client
Application
JDBC
OCI driver
O7 or O8
ocixxx.dll
Client
Server
Oracle JDBC Drivers: 3. Server-Side
Driver
Runs inside the database
Java stored procedures must use this driver
Stored procedure
Oracle8i
JDBC
Server side driver
C library
SQL
Engine
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
About JDBC URLs
JDBC uses a URL to identify the database
connection.
jdbc:<subprotocol>:<subname>
Protocol
Subprotocol
Database
identifier
jdbc:oracle:<driver>:@<database>
JDBC URLs with Oracle Drivers
Thin driver
jdbc:oracle:thin:@<host>:<port>:<SID>
OCI driver
jdbc:oracle:oci8:@<TNSNAMES entry>
Server-side driver: Use the default
connection
How to Make the Connection
1. Register the driver.
DriverManager.registerDriver (new
oracle.jdbc.driver.OracleDriver());
2. Connect to the database.
Connection conn = DriverManager.getConnection
(URL, userid, password);
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@myhost:1521:orcl",
"scott", "tiger");
Using Connection
java.sql.Connection
Creating Statement
createStatment()
prepareStatment(String)
prepareCall(String)
Transaction Management
commit()
rollback()
Get database metadata
getMetaData()
close()
isClosed()
Conneciton related
Demonstration
Connection
Stage 2: Query
Connect
Query
Create a statement
Process
results
Query the database
Close
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
How to Query the Database
1. Create an empty statement object.
Statement stmt = conn.createStatement();
2. Execute the statement.
ResultSet rset = stmt.executeQuery(statement);
int count = stmt.executeUpdate(statement);
boolean isquery = stmt.execute(statement);
Querying the Database: Examples
Execute a select statement.
Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery
("select RENTAL_ID, STATUS from ACME_RENTALS");
•
Execute a delete statement.
Statement stmt = conn.createStatement();
int rowcount = stmt.executeUpdate
("delete from ACME_RENTAL_ITEMS
where rental_id = 1011");
Stage 3: Process the Results
Connect
Query
Step through the results
Process
results
Close
Assign results to Java
variables
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.
How to Process the Results
1. Step through the result set.
while (rset.next()) { … }
2. Use getXXX() to get each column value.
String val =
rset.getString(colname);
String val =
rset.getString(colIndex);
while (rset.next()) {
String title = rset.getString("TITLE");
String year = rset.getString("YEAR");
… // Process or display the data
}
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.
while (rset.next()) {
String year = rset.getString("YEAR");
if (rset.wasNull() {
… // Handle null value
}
…}
Mapping 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
Type
RENTAL_ID
NUMBER
RENTAL_DATE
DATE
STATUS
VARCHAR2
Stage 4: Close
Connect
Query
Close the result set
Process
results
Close the statement
Close
Close the connection
How to Close the Connection
1. Close the ResultSet object.
rset.close();
2. Close the Statement object.
stmt.close();
3. Close the connection (not necessary for
server-side driver).
conn.close();
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.
How to Obtain Database Metadata
1. Get the DatabaseMetaData object.
DatabaseMetaData dbmd = conn.getMetaData();
2. Use the object’s methods to get the
metadata.
DatabaseMetaData dbmd = conn.getMetaData();
String s1 = dbmd getURL();
String s2 = dbmd.getSQLKeywords();
boolean b1 = dbmd.supportsTransactions();
boolean b2 = dbmd.supportsSelectForUpdate();
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.
ResultSetMetaData rsmd = rset.getMetaData();
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);
…
}
Demonstration
Dynamic 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.
pstmt.setXXX(index, value);
2. Execute the statement.
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.
How to Create a Callable Statement
Register the driver and create the database
connection.
Create the callable statement, identifying
variables with a question mark (?).
CallableStatement cstmt =
conn.prepareCall("{call " +
ADDITEM + "(?,?,?)}");
cstmt.registerOutParameter(2,Types.INTEGER);
cStmt.registerOutParameter(3,Types.DOUBLE);
How to Execute a Callable
Statement
1. Set the input parameters.
cstmt.setXXX(index, value);
2. Execute the statement.
cstmt.execute(statement);
3. Get the output parameters.
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
Oracle JDBC Extensions
Oracle provides many extensions to standard
JDBC;
for example:
Connection
OracleConnection
Statement
OracleStatement
PreparedStatement
OraclePreparedStatement
CallableStatement
OracleCallableStatement
ResultSet
OracleResultSet
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
1. create statement
2. create resultset
3. get Blob locator
4. get InputStream
5. InputStream 처리
6. InputStream close
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();
}
BLOB : Writing
1. create statement
2. create resultset
3. get Blob locator
4. get OutputStream
5. Source read
6. write blob
7. close stream
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();
}
CLOB
Reading
–
–
–
getAsciiStream() : 아스키 스트림
getCharacterStream() : 유니코드 스트림.
Return된 InputStream을 이용하여 처리(파일,
데이터베이스에 Writing)
• Writing
–
–
–
getAsciiOutputStream() 메서드 사용해서
locator 획득
getCharacterOutputStream() 메서드 사용.
java.io.OutputStream 객체를 이용하여 Writing
CLOB : Reading
1. create statement
2. create resultset
3. get Clob locator
4. get InputStream
5. InputStream 처리
6. InputStream close
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();
}
CLOB : Writing
1. create statement
2. create resultset
3. get clob locator
4. get OutputStream
5. Source read
6. write clob
7. close stream
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();
}
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 : Processing
cmd = "SELECT * FROM my_bfile_table WHERE x =
’one’";
1. select the locator
rset = stmt.executeQuery (cmd);
if (rset.next ()) {
2. Open the bfile
BFILE bfile = ((OracleResultSet)rset).getBFILE (2);
bfile.openFile();
InputStream in = bfile.getBinaryStream();
3. get a binary stream
int length ;
byte[] buf = new byte[512];
while ((length = in.read(buf)) != -1)
4. InputStream 처리
{
// to do something using byte buffer
}
5. Close resoruce
in.close();
bfile.closeFile();
Demonstration
LOB 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
SSN
oracle.sql.STRUCT
Person(empid, name)
(1001, ’Scott’)
(1002, ‘Alice’)
...
s
rset.getObject(2) or
rset.getSTRUCT(2)
Object [ ]
(0) 1001
(1) ‘Scott’
s.getAttributes()
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]);
}
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
oracle.sql.ARRAY
ResultSet
Name
‘Scott’
‘Alice’
...
Phones
varray(10) of varchar2(25)
(‘111-2222’, ‘222-3333’)
(‘333-4444’)
...
s
rset.getObject(2) or
rset.getArray(2) or
rset.getARRAY(2)
s.getArray()
Object [ ]
(0)
‘111-2222’
(1)
‘‘222-3333’
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]);
}
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
ADDR
oracle.sql.REF
(street_name, house_no)
name varchar2,
PEOPLE col1 REF ADDR
(‘sam’,
addr1)
(‘sam’
0000280209420D2400 ….)
ref
r.getValue()
rset.getObject(2) or
rset.getREF(2) or rset.getRef(2)
(
‘Samsung-dong’,
144-17
)
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]);
}
Demonstration
Advanced 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
Java Program
Statement stmt =
conn.createStatemen(
ResultSet.TYPE_SCROLL_IN
SENSITIVE,
ResultSet.CONCURR_READ_
ONLY);
ResultSet rset =
stmt.executeQuery();
rset.absolute(2);
...
Scrollable
ResultSet
Oracle 8i
Cache
Cursor
next()
previous()
relative()
absolute()
first()
last()
Table
APIs
java.sql.Connection
Statement createStatement (int resultSetType, int resultSetConcurrency)
PreparedStatement prepareStatement (String sql, int resultSetType, int
resultSetConcurrency)
CallableStatement prepareCall (String sql, int resultSetType, int resultSetConcurrency)
resultSetType
resultSetConcurrency
ResultSet.TYPE_FORWARD_ONLY
ResultSet.CONCUR_READ_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.CONCUR_UPDATABLE
ResultSet.TYPE_SCROLL_SENSITIVE
APIs
java.sql.ResultSet
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
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 row
Statement stmt = conn.createStatement
(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery("SELECT empno, sal FROM emp");
if (rs.absolute(10)) // (returns false if row does not exist)
{
rs.updateString(1, "28959");
rs.updateFloat("sal", 100000.0f);
rs.updateRow();
}
// Changes 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
Can See Can See Can See
Internal
Internal
Internal
DELETE? UPDATE? INSERT?
Can See Can See
Can See
External External
External
DELETE? UPDATE? INSERT?
forward-only
no
yes
no
no
no
no
scroll-sensitive
yes
yes
no
no
yes
no
scroll-insensitive
yes
yes
no
no
no
no
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()
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 Specific
PreparedStatement 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 : Standard
conn.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
conn.setAutoCommit (false);
Prefetch Rows
conn.setDefaultRowPrefetch (20);
Batch Updates
conn.setDefaultExecuteBatch (10);
stmt.setExecuteBatch (15);
Define Column types
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 Status
int 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
getConnection
getPooledConnection
PooledConnection
ConnectionPoolDataSource
( close or error event)
ConnectionEvent
ConnectionEventListener
Connection Pooling : API
public 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 =
1. Creating ConnectionPoolDataSource
new OracleConnectionPoolDataSource();
// Set connection parameters
2. Creating PooledConnection
ocpds.setURL("jdbc:oracle:oci8:@");
ocpds.setUser("scott");
3. Creating Connection Object
ocpds.setPassword("tiger");
// Create a pooled connection
PooledConnection pc = ocpds.getPooledConnection();
// Get a Logical connection
Connection conn = pc.getConnection();
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 middletier 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 Transaction
XA 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
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();
SQLJ
#sql { INSERT INTO emp
VALUES
(:name,:dept,:mgr,
:sal,:today)};
What you need to learn
SQLJ program template
Issuing a query
Updating a table using a statement with bind
variables
SQLJ 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
}
}
SQLJ clauses
• A executable SQLJ clause has this form:
#sql { SQL-statement } ;
• The SQL statement appears inside the curly
braces:
#sql { DELETE FROM tab WHERE col < 0 };
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 Type
• The Iterator definition lists the SQL names and the
Java types of the result columns
#sql iterator EmpCursor (String ENAME, Double SAL);
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
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
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 ':'
String ename = “Seik Waljay”;
Double sal = 15000;
#sql { update EMP set SAL = :sal
where ENAME = :ename };
Q&A