3 4
Scenario JDBC API
• Small coffee house called The Coffee Break, where • To use the JDBC API is necessary to include in your
coffee beans are sold by the pound file the command
• The database contains only two tables, one for types import java.sql.*;
of coffee and one for coffee suppliers. • For some functionalities you need to include also the
JDBC Optional Package
import javax.sql.*;
• Make sure the .jar file containing the JDBC driver is
in the classpath or use an IDE such as Eclipse
5 6
• Two steps: • Your driver documentation will give you the class
1. loading the driver name to use. For instance, if the class name is
2. making the connection. jdbc.DriverXYZ , you would load the driver with the
following line of code:
– Class.forName("jdbc.DriverXYZ");
• Calling Class.forName locates the driver class, loads,
and links it, and registers it with the DriverManager
7 8
Loading the Driver Making the Connection
9 10
11 12
SQL Server Driver Url Examples SQL Server Driver Connection Examples
• Connect to the default database on the local • Note that if you specify an instance name, you should
computer: use double \ in the url
jdbc:sqlserver://localhost;user=MyUserName;password Connection con = DriverManager.getConnection(
=prova “jdbc:sqlserver://localhost\\si2006”, "myLogin",
• Connect to a named instance on the local machine: "myPassword");
jdbc:sqlserver://localhost\si2006;user=MyUserName;pa Connection con = DriverManager.getConnection(
ssword=prova “jdbc:sqlserver://192.168.0.252”, “utente", “Infonew1");
• Connect on the non-default port 4000 to the local
machine:
jdbc:sqlserver://localhost:4000;user=MyUserName;pass
word=prova
13 14
15 16
DB2 Driver URLs Examples DriverManager.getConnection
17 18
• It contains the essential information about the coffees • SUPPLIERS gives information about each of the
sold at The Coffee Break, including the coffee suppliers:
names, the ID of their supplier their prices, the
number of pounds sold the current week, and the SUP_ID SUP_NA STREET CITY STATE ZIP
number of pounds sold to date. ME
101 Acme, Inc. 99 Market Groundsville CA 95199
Street
49 Superior 1 Party Mendocino CA 95460
COF_NAME SUP_ID PRICE SALES TOTAL
Coffee Place
Colombian 101 7.99 0 0
150 The High 100 Coffee Meadows CA 93966
French_Roast 49 8.99 0 0
Ground Lane
Espresso 150 9.99 0 0
Colombian_Decaf 101 8.99 0 0
French_Roast_Decaf 49 9.99 0 0
19 20
CREATE TABLE COFFES Table Creation
21 22
• A Statement object is what sends your SQL • It takes an instance of an active connection to create
statement to the DBMS. a Statement object. In the following example, we use
• You simply create a Statement object and then our Connection object con to create the Statement
execute it, supplying the appropriate execute method object stmt :
together with the SQL statement you want to send. Statement stmt = con.createStatement();
• For a SELECT statement, the method to use is
executeQuery . For statements that create or modify
tables, the method to use is executeUpdate.
23 24
Executing Statements Inserting Data in COFFEES
• At this point stmt exists, but it does not have an SQL Statement stmt = con.createStatement();
statement to pass on to the DBMS. We need to stmt.executeUpdate( "INSERT INTO COFFEES " +
supply that to the method we use to execute stmt . "VALUES ('Colombian', 101, 7.99, 0, 0)");
For example, in the following code fragment, we • The code that follows inserts a second row into the
supply executeUpdate with the SQL statement from table COFFEES . Note that we can just reuse the
the example above: Statement object stmt rather than having to create a
stmt.executeUpdate(createTableCoffees); new one for each execution.
• We used the method executeUpdate because the stmt.executeUpdate("INSERT INTO COFFEES " +
SQL statement contained in createTableCoffees is a "VALUES ('French_Roast', 49, 8.99, 0, 0)");
DDL (data definition language) statement.
executeUpdate is also used to execute SQL
statements that update a table.
25 26
27 28
Retrieving Results next
• The variable rs, which is an instance of ResultSet, • next returns true if the successive row is a valid row
contains the rows of coffees and prices shown above. otherwise it returns false
• In order to access the names and prices, we will go • If it is called when the cursor is on the last row it
to each row and retrieve the values according to their returns false
types. The method next moves what is called a
cursor to the next row and makes that row (called • It can be used for cycles
the current row) the one upon which we can operate.
• Since the cursor is initially positioned just above the
first row of a ResultSet object, the first call to the
method next moves the cursor to the first row and
makes it the current row.
• Successive invocations of the method next move the
cursor down one row at a time from top to bottom.
29 30
• We use the getXXX method of the appropriate type to String query = "SELECT COF_NAME, PRICE “+
retrieve the value in each column. For example, the “ FROM COFFEES";
first column in each row of rs is COF_NAME , which ResultSet rs = stmt.executeQuery(query);
stores a value of SQL type VARCHAR .
while (rs.next()) {
• The method for retrieving a value of SQL type
VARCHAR is getString. String s = rs.getString("COF_NAME");
• The second column in each row stores a value of float n = rs.getFloat("PRICE");
SQL type FLOAT, and the method for retrieving System.out.println(s + " " + n);
values of that type is getFloat. }
31 32
Details getXXX
String s = rs.getString("COF_NAME"); • JDBC offers two ways to identify the column from
• The method getString will retrieve (get) the value which a getXXX method gets a value.
stored in the column COF_NAME in the current row • One way is to give the column name, as was done in
of rs. The value that getString retrieves has been the example above.
converted from an SQL VARCHAR to a String in the • The second way is to give the column index (number
Java programming language, and it is assigned to the of the column), with 1 indicating the first column, 2 ,
String object s. the second, and so on:
• The situation is similar with the method getFloat String s = rs.getString(1);
except that it retrieves the value stored in the column float n = rs.getFloat(2);
PRICE, which is an SQL FLOAT, and converts it to a
Java float before assigning it to the variable n .
33 34
getXXX getXXX
• Using the column number is slightly more efficient, • JDBC allows a lot of latitude as far as which getXXX
and there are some cases where the column number methods you can use to retrieve the different SQL
is required. types.
• In general, though, supplying the column name is • For example, the method getInt can be used to
essentially equivalent to supplying the column retrieve any of the numeric or character types. The
number. data it retrieves will be converted to an int; that is, if
the SQL type is VARCHAR, JDBC will attempt to
parse an integer out of the VARCHAR.
• The method getInt is recommended for retrieving only
SQL INTEGER types, however, and it cannot be
used for the SQL types BINARY, VARBINARY,
LONGVARBINARY, DATE, TIME, or TIMESTAMP.
35 36
getXXX Updating Tables
• Although the method getString is recommended for • Suppose that after a successful first week, the owner
retrieving the SQL types CHAR and VARCHAR , it is of The Coffee Break wants to update the SALES
possible to retrieve any of the basic SQL types with it. column in the table COFFEES by entering the
• For instance, if it is used to retrieve a numeric type, number of pounds sold for each type of coffee. The
getString will convert the numeric value to a Java SQL statement to update one row might look like this:
String object.
37 38
String updateString = "UPDATE COFFEES " + String query = "SELECT COF_NAME, SALES FROM”+
"SET SALES = 75 " + “COFFEES WHERE COF_NAME LIKE 'Colombian'";
"WHERE COF_NAME LIKE 'Colombian'"; ResultSet rs = stmt.executeQuery(query);
• Using the Statement object stmt , this JDBC code while (rs.next()) {
executes the SQL statement contained in String s = rs.getString("COF_NAME");
updateString : int n = rs.getInt("SALES");
stmt.executeUpdate(updateString); System.out.println(n + " pounds of " + s +
" sold this week.");
}
39 40
Seeing the Results Updating the TOTAL
43 44
Supplying Values for PreparedStatement
Parameters
Executing a Prepared Statement
• Once a parameter has been set with a value, it will updateSales.setInt(1, 100);
retain that value until it is reset to another value or updateSales.setString(2, "French_Roast");
the method clearParameters is called updateSales.executeUpdate();
// changes SALES column of French Roast row to 100
updateSales.setString(2, "Espresso");
updateSales.executeUpdate();
// changes SALES column of Espresso row to 100 (the
// first parameter stayed 100, and the second
// parameter was set to "Espresso")
47 48
Return Values for the Method
Using a Loop to Set Values executeUpdate
PreparedStatement updateSales; • The return value for executeUpdate is an int that
String updateString = "update COFFEES " + indicates how many rows of a table were updated.
"set SALES = ? where COF_NAME like ?";
updateSales = con.prepareStatement(updateString);
updateSales.setInt(1, 50);
int [] salesForWeek = {175, 150, 60, 155, 90}; updateSales.setString(2, "Espresso");
String [] coffees = {"Colombian", "French_Roast", "Espresso", int n = updateSales.executeUpdate();
"Colombian_Decaf", "French_Roast_Decaf"};
// n = 1 because one row had a change in it
int len = coffees.length;
for(int i = 0; i < len; i++) { • When the method executeUpdate is used to execute
updateSales.setInt(1, salesForWeek[i]); a DDL statement, such as in creating a table, it
updateSales.setString(2, coffees[i]); returns the int 0.
updateSales.executeUpdate(); int n = executeUpdate(createTableCoffees); // n = 0
}
49 50
• When the return value for executeUpdate is 0, it can • We need to create the table SUPPLIERS and
mean one of two things: populate it with values.
1. the statement executed was an update statement String createSUPPLIERS = "create table SUPPLIERS "+
that affected zero rows, "(SUP_ID INTEGER, SUP_NAME VARCHAR(40), " +
"STREET VARCHAR(40), CITY VARCHAR(20), " +
2. the statement executed was a DDL statement.
"STATE CHAR(2), ZIP CHAR(5))";
stmt.executeUpdate(createSUPPLIERS);
51 52
Populating SUPPLIERS with Values Query with a Join
stmt.executeUpdate("insert into SUPPLIERS values (101, " + String query = "SELECT COFFEES.COF_NAME " +
"'Acme, Inc.', '99 Market Street', 'Groundsville', " + "FROM COFFEES, SUPPLIERS " +
"'CA', '95199'"); "WHERE SUPPLIERS.SUP_NAME LIKE 'Acme, Inc.' " +
stmt.executeUpdate("Insert into SUPPLIERS values (49," + "and SUPPLIERS.SUP_ID = COFFEES.SUP_ID";
ResultSet rs = stmt.executeQuery(query);
"'Superior Coffee', '1 Party Place', 'Mendocino', 'CA', '95460'");
System.out.println("Coffees bought from Acme, Inc.: ");
stmt.executeUpdate("Insert into SUPPLIERS values (150, " +
while (rs.next()) {
"'The High Ground', '100 Coffee Lane', 'Meadows', 'CA', " +
String coffeeName = rs.getString("COF_NAME");
"'93966'"); System.out.println(" " + coffeeName);
ResultSet rs = stmt.executeQuery("select * from SUPPLIERS"); }
SUP_ID SUP_NAME STREET CITY STATE ZIP
Transactions Transactions
55 56
Isolation Levels Isolation Levels
• Five constants defined in the Connection interface: • Even though JDBC allows you to set a transaction
– TRANSACTION_NONE isolation level, doing so will have no effect unless the
– TRANSACTION_READ_UNCOMMITTED driver and DBMS you are using support it.
– TRANSACTION_READ_COMMITTED
– TRANSACTION_REPEATABLE_READ
– TRANSACTION_SERIALIZABLE
• Example
con.setTransactionIsolation(
Connection.TRANSACTION_READ_COMMITTED);
57 58
Example Example
String updateString=“UPDATE COFFEES SET SALES = ? int len = coffees.length;
WHERE “+
COF_NAME = ?”; con.setAutoCommit(false);
String updateStatement=“UPDATE COFFEES SET TOTAL = for (int i = 0; i < len; i++) {
TOTAL + ? WHERE “+
COF_NAME = ?”;
updateSales.setInt(1, salesForWeek[i]);
String query = "select COF_NAME, SALES, TOTAL from updateSales.setString(2, coffees[i]);
COFFEES"; updateSales.executeUpdate();
try {
con = DriverManager.getConnection(url,"myLogin", updateTotal.setInt(1, salesForWeek[i]);
"myPassword"); updateTotal.setString(2, coffees[i]);
updateSales = con.prepareStatement(updateString);
updateTotal = con.prepareStatement(updateStatement);
updateTotal.executeUpdate();
int [] salesForWeek = {175, 150, 60, 155, 90}; con.commit();
String [] coffees = {"Colombian", "French_Roast", "Espresso", }
"Colombian_Decaf","French_Roast_Decaf"};
59 60
Example Example
con.setAutoCommit(true); catch(SQLException ex) {
updateSales.close(); updateTotal.close(); System.err.println("SQLException: " + ex.getMessage());
stmt = con.createStatement(); if (con != null) {
ResultSet rs = stmt.executeQuery(query); try {
while (rs.next()) { System.err.print("Transaction is being ");
String c = rs.getString("COF_NAME"); System.err.println("rolled back");
int s = rs.getInt("SALES"); con.rollback();
int t = rs.getInt("TOTAL"); }
System.out.println(c + " " + s + " " + t); catch(SQLException excep) {
} System.err.print("SQLException: ");
stmt.close(); System.err.println(excep.getMessage());
con.close(); }
} }
61 62
63 64
Calling a Stored Procedure from JDBC Escape Syntax
• The first step is to create a CallableStatement object. • {call SHOW_SUPPLIERS} is the escape syntax for
• As with Statement and PreparedStatement objects, stored procedures.
this is done with an open Connection object. • When the driver encounters "{call
• A CallableStatement object contains a call to a stored SHOW_SUPPLIERS}" , it will translate this escape
procedure; it does not contain the stored procedure syntax into the native SQL used by the database to
itself. call the stored procedure named
CallableStatement cs = con.prepareCall( SHOW_SUPPLIERS .
"{call SHOW_SUPPLIERS}");
ResultSet rs = cs.executeQuery();
65 66
67 68
Exceptions Exceptions
try { try {
Class.forName("myDriverClassName"); // Code that could generate an exception goes here.
} catch(java.lang.ClassNotFoundException e) { // If an exception is generated, the catch block below
System.err.print("ClassNotFoundException: "); // will print out information about it.
System.err.println(e.getMessage()); } catch(SQLException ex) {
} System.err.println("SQLException: " +
ex.getMessage());
}
69 70
Exceptions Exceptions
• If you were to run CreateCOFFEES.java twice, you • The SQLException object contains three parts:
would get an error message similar to this: – the message (a string that describes the error),
SQLException: There is already an object named – the SQL state (a string identifying the error
'COFFEES' in the database. according to the X/Open SQLState conventions),
Severity 16, State 1, Line 1 – the vendor error code (a number that is the driver
• This example illustrates printing out the message vendor's error code number)
component of an SQLException object, which is
sufficient for most situations.
71 72
Example Example
try {// Code that could generate an exception goes here. • If you try to create the table COFFEES twice, you would get the
// If an exception is generated, the catch block below following printout:
--- SQLException caught ---
// will print out information about it.
Message: There is already an object named 'COFFEES'
} catch(SQLException ex) {
in the database. Severity 16, State 1, Line 1
System.out.println("\n--- SQLException caught ---\n"); SQLState: 42501
while (ex != null) { ErrorCode: 2714
System.out.println("Message: "+ ex.getMessage ()); • SQLState is a code defined in X/Open and ANSI-92 that
System.out.println("SQLState: "+ ex.getSQLState ()); identifies the exception. Two examples of SQLState code
numbers and their meanings follow:
System.out.println("ErrorCode: "+ ex.getErrorCode ());
– 08001 -- No suitable driver
ex = ex.getNextException();
– HY011 -- Operation invalid at this time
System.out.println(""); • The vendor error code is specific to each driver, so you need to
} check your driver documentation for a list of error codes and
} what they mean.
73 74
75 76
Scrollable ResultSet TYPE_FORWARD_ONLY
• Two arguments to the method createStatement. • Specifying the constant TYPE_FORWARD_ONLY
– The first argument is one of three constants added to the creates a nonscrollable result set, that is, one in
ResultSet API to indicate the type of a ResultSet object: which the cursor moves only forward.
TYPE_FORWARD_ONLY , TYPE_SCROLL_INSENSITIVE
, and TYPE_SCROLL_SENSITIVE . • If you do not specify any constants for the type and
– The second argument is one of two ResultSet constants for updatability of a ResultSet object, you will
specifying whether a result set is read-only or updatable: automatically get one that is
CONCUR_READ_ONLY and CONCUR_UPDATABLE . TYPE_FORWARD_ONLY and
• If you specify a type, you must also specify whether it is read- CONCUR_READ_ONLY (as is the case when you
only or updatable. are using only the JDBC 1.0 API).
• Also, you must specify the type first, and because both
parameters are of type int , the compiler will not complain if you
switch the order.
77 78
TYPE_SCROLL_INSENSITIVE or
TYPE_SCROLL_SENSITIVE
Scrollable ResultSet
• You will get a scrollable ResultSet object if you specify one of • Once you have a scrollable ResultSet object, srs in
the following ResultSet constants:
TYPE_SCROLL_INSENSITIVE or TYPE_SCROLL_SENSITIVE the previous example, you can use it to move the
The difference between the two has to do with whether a result cursor around in the result set.
set reflects changes that are made to it while it is open and
whether certain methods can be called to detect these changes.
• Even when a result set is scrollable, the cursor is
• Generally speaking, initially positioned before the first row.
– a result set that is TYPE_SCROLL_INSENSITIVE does not
reflect changes made by others while it is still open and
– one that is TYPE_SCROLL_SENSITIVE does.
• All three types of result sets will make changes visible if they are
closed and then reopened.
• No matter what type of result set you specify, you are always
limited by what your DBMS and driver actually provide
79 80
next and previous Using previous
81 82
• The methods first , last , beforeFirst , and afterLast • The following line of code moves the cursor to the
move the cursor to the row indicated in their names. fourth row of srs :
• The method absolute will move the cursor to the row srs.absolute(4);
number indicated in the argument passed to it. • If srs has 500 rows, the following line of code will
– If the number is positive, the cursor moves the move the cursor to row 497:
given number from the beginning, so calling srs.absolute(-4);
absolute(1) puts the cursor on the first row.
– If the number is negative, the cursor moves the
given number from the end, so calling absolute(-1)
puts the cursor on the last row.
83 84
Relative Moves relative Example
• Three methods move the cursor to a position relative srs.absolute(4); // cursor is on the fourth row
to its current position. ...
– next srs.relative(-3); // cursor is on the first row
– previous ...
– relative: you can specify how many rows to move srs.relative(2); // cursor is on the third row
from the current row. A positive number moves the
cursor forward the given number of rows; a
negative number moves the cursor backward the
given number of rows.
85 86
• The method getRow lets you check the number of the • Four additional methods let you verify whether the
row where the cursor is positioned. cursor is at a particular position.
srs.absolute(4); • The position is stated in their names: isFirst , isLast ,
int rowNum = srs.getRow(); // rowNum should be 4 isBeforeFirst , isAfterLast .
srs.relative(-3); • These methods all return a boolean and can
int rowNum = srs.getRow(); // rowNum should be 1 therefore be used in a conditional statement.
srs.relative(2);
int rowNum = srs.getRow(); // rowNum should be 3
87 88
isAfterLast Example Making Updates to Updatable Result Sets
89 90
91 92
Notes Notes
• Just specifying that a result set be updatable does • The following line of code checks whether the
not guarantee that the result set you get is updatable. ResultSet object uprs is updatable.
• If a driver does not support updatable result sets, it • int concurrency = uprs.getConcurrency();
will return one that is readonly. • The variable concurrency will be one of the following:
• The query you send can also make a difference. In – 1007 to indicate
order to get an updatable result set, the query must ResultSet.CONCUR_READ_ONLY
generally specify the primary key as one of the – 1008 to indicate
columns selected, and it should select columns from ResultSet.CONCUR_UPDATABLE
only one table.
93 94
95 96
Update Operations Update Operations
• Update operations in the JDBC 2.0 API affect column • At this point, the price in uprs for French Roast Decaf
values in the row where the cursor is positioned, will be 10.99, but the price in the table COFFEES in
• All of the update methods you call will operate on that the database will still be 9.99.
row until you move the cursor to another row. • To make the update take effect in the database, we
• The ResultSet.updateXXX methods generally take must call the ResultSet method updateRow.
two parameters:
uprs.updateRow();
– the column to update, either by column name or
by column number. • Note that you must call the method updateRow
– the new value to put in that column. before moving the cursor. If you move the cursor to
• There is a different updateXXX method for updating another row before calling updateRow, the updates
each data type (updateString, updateBigDecimal, are lost, that is, the row will revert to its previous
updateInt, and so on) column values.
97 98
• Suppose that you realize that the update you made is • If you want to update the price for Colombian_Decaf,
incorrect. you have to move the cursor to the row containing
• You can restore the previous value by calling the that variety of coffee.
cancelRowUpdates method if you call it before you • Because the row for Colombian_Decaf immediately
have called the method updateRow. precedes the row for French_Roast_Decaf, you can
• Once you have called updateRow, the method call the method previous to position the cursor on the
cancelRowUpdates will no longer work. row for Colombian_Decaf.
uprs.last(); uprs.previous();
uprs.updateFloat("PRICE", 10.99f); uprs.updateFloat("PRICE", 9.79f);
... uprs.updateRow();
uprs.cancelRowUpdates();
99 100
Inserting and Deleting Rows
Notes Programmatically
• All cursor movements refer to rows in a ResultSet • With the JDBC 1.0 API
object, not rows in the underlying database. stmt.executeUpdate("INSERT INTO COFFEES " +
• The ordering of the rows in the result set has nothing "VALUES ('Kona', 150, 10.99, 0, 0)");
at all to do with the order of the rows in the base
table.
• In fact, the order of the rows in a database table is
indeterminate. The driver keeps track of which rows
were selected, and it makes updates to the proper
rows, but they may be located anywhere in the table.
101 102
103 104
Example Example (Alternative Solution)
uprs.moveToInsertRow(); uprs.moveToInsertRow();
uprs.updateString("COF_NAME", "Kona"); uprs.updateString(1, "Kona");
uprs.updateInt("SUP_ID", 150); uprs.updateInt(2, 150);
uprs.updateFloat("PRICE", 10.99f); uprs.updateFloat(3, 10.99f);
uprs.updateInt("SALES", 0); uprs.updateInt(4, 0);
uprs.updateInt("TOTAL", 0); uprs.updateInt(5, 0);
uprs.insertRow(); uprs.insertRow();
105 106
updateXXX Inserting
• In both updates and insertions, calling an updateXXX • What happens if you insert a row without supplying a value for
method does not affect the underlying database every column in the row?
table. • If a column has a default value or accepts SQL NULL values,
you can get by with not supplying a value.
• The method updateRow must be called to have • If a column does not have a default value and does not accept
updates occur in the database. NULL, you will get an SQLException if you fail to set a value for
• For insertions, the method insertRow inserts the new it.
row into the result set and the database at the same • You will also get an SQLException if a required table column is
missing in your ResultSet object.
time.
• In the example above, the query was SELECT * FROM
COFFEES, which produced a result set with all the columns of
all the rows. When you want to insert one or more rows, your
query does not have to select all rows, but you should generally
select all columns.
107 108
Inserting Moving from the Insert Row
• After you have called the method insertRow, you can • When you call the method moveToInsertRow, the
start building another row to be inserted, result set keeps track of which row the cursor is
• Note that you if you move the cursor from the insert sitting on, which is, by definition, the current row.
row before calling the method insertRow, you will • The method moveToCurrentRow, which you can
lose all of the values you have added to the insert invoke only when the cursor is on the insert row,
row. moves the cursor from the insert row back to the row
that was previously the current row.
• To move the cursor from the insert row back to the
result set, you can also invoke any of the methods
that move the cursor: first, last, beforeFirst, afterLast,
absolute, previous, relative.
109 110
• You simply move the cursor to the row you want to • With some JDBC drivers, a deleted row is removed
delete and then call the method deleteRow. and is no longer visible in a result set.
• Example: • Some JDBC drivers use a blank row as a placeholder
(a "hole") where the deleted row used to be.
uprs.absolute(4);
• If there is a blank row in place of the deleted row, you
uprs.deleteRow(); can use the method absolute with the original row
• These two lines of code remove the fourth row from positions to move the cursor because the row
uprs and also from the database. numbers in the result set are not changed by the
deletion.
• You can use methods in the DatabaseMetaData
interface to discover the exact behavior of your
driver.
111 112
Seeing Changes in Result Sets Seeing Changes in Result Sets
• Result sets vary greatly in their ability to reflect • So when can you see visible changes you or others made while
changes made in their underlying data. the ResultSet object is still open? (Generally, you will be most
interested in the changes made by others because you know
• If you modify data in a ResultSet object, the change what changes you made yourself.)
will always be visible if you close it and then reopen it • The answer depends on the type of ResultSet object you have.
during a transaction. • With a ResultSet object that is TYPE_SCROLL_SENSITIVE,
• You will also see changes made by others when you you can always see visible updates made by you and others to
existing column values. You may see inserted and deleted rows,
reopen a result set if your transaction isolation level
but the only way to be sure is to use DatabaseMetaData
makes them visible. methods that return this information.
113 114
115 116
Getting the Most Recent Data Getting the Most Recent Data
• You can do this using the method refreshRow, which • Note that the result set should be sensitive; if you use
gets the latest values for a row straight from the the method refreshRow with a ResultSet object that
database. is TYPE_SCROLL_INSENSITIVE, refreshRow does
• This method can be relatively expensive, especially if nothing.
the DBMS returns multiple rows each time you call
refreshRow. Nevertheless, its use can be valuable if
it is critical to have the latest data.
• Even when a result set is sensitive and changes are
visible, an application may not always see the very
latest changes that have been made to a row if the
driver retrieves several rows at a time and caches
them.
117 118
119 120
Using Statement Objects for Batch Updates Using Statement Objects for Batch Updates
• Statement, PreparedStatement and • The list, which is associated with a Statement object
CallableStatement objects have a list of commands at its creation, is initially empty.
that is associated with them.
• You can add SQL commands to this list with the
• This list may contain statements for updating, method addBatch and empty it with the method
inserting, or deleting a row; and it may also contain
DDL statements such as CREATE TABLE and clearBatch.
DROP TABLE. • When you have finished adding statements to the list,
• It cannot, however, contain a statement that would you call the method executeBatch to send them all to
produce a ResultSet object, such as a SELECT the database to be executed as a unit, or batch.
statement.
• In other words, the list can contain only statements
that produce an update count.
121 122
Example Notes
con.setAutoCommit(false); • To allow for correct error handling, you should always
Statement stmt = con.createStatement(); disable auto-commit mode before beginning a batch
stmt.addBatch("INSERT INTO COFFEES " + update.
"VALUES('Amaretto', 49, 9.99, 0, 0)"); • executeBatch: the DBMS will execute the commands
stmt.addBatch("INSERT INTO COFFEES " + in the order in which they were added to the list of
"VALUES('Hazelnut', 49, 9.99, 0, 0)"); commands.
stmt.addBatch("INSERT INTO COFFEES " +
• If all four commands execute successfully, the DBMS
"VALUES('Amaretto_decaf', 49, 10.99, 0, 0)");
will return an update count for each command in the
stmt.addBatch("INSERT INTO COFFEES " +
order in which it was executed.
"VALUES('Hazelnut_decaf', 49, 10.99, 0, 0)");
int [] updateCounts = stmt.executeBatch();
• The update counts, int values indicating how many
con.commit();
rows were affected by each command, are stored in
con.setAutoCommit(true);
the array updateCounts.
123 124
Parameterized Batch Update Batch Update Exceptions
con.setAutoCommit(false);
• You will get a BatchUpdateException when you call
PreparedStatement pstmt = con.prepareStatement(
"INSERT INTO COFFEES VALUES(?, ?, ?, ?, ?)"); the method executeBatch if
pstmt.setString(1, "Amaretto"); pstmt.setInt(2, 49); 1. one of the SQL statements you added to the
pstmt.setFloat(3, 9.99); pstmt.setInt(4, 0);
pstmt.setInt(5, 0); batch produces a result set (usually a query) or
pstmt.addBatch(); 2. one of the SQL statements in the batch does not
pstmt.setString(1, "Hazelnut"); pstmt.setInt(2, 49); execute successfully for some other reason.
pstmt.setFloat(3, 9.99); pstmt.setInt(4, 0);
pstmt.setInt(5, 0);
pstmt.addBatch();
125 126
127 128
Example SQL-99 Data Types
try { • The JDBC 2.0 API provides interfaces that represent
// make some updates
} catch(BatchUpdateException b) {
the mapping of the new SQL3 (SQL-99) data types
System.err.println("----BatchUpdateException----"); into the Java programming language.
System.err.println("SQLState: " + b.getSQLState()); • With these new interfaces, you can work with SQL3
System.err.println("Message: " + b.getMessage()); data types the same way you do other data types.
System.err.println("Vendor: " + b.getErrorCode());
System.err.print("Update counts: ");
int [] updateCounts = b.getUpdateCounts();
for (int i = 0; i < updateCounts.length; i++) {
System.err.print(updateCounts[i] + " ");
}
System.err.println("");
}
129 130
131 132
DataSource Advantages DataSource Advantages
• A DataSource object is a better alternative than the – DataSource properties make maintaining code
DriverManager facility for getting a connection. much simpler. If there is a change, the system
– Programmers no longer have to hard code the administrator can simply update the data source's
driver name or JDBC URL in their applications, properties, and you don't have to worry about
which makes them more portable. changing every application that makes a
connection to the data source. For example, if the
data source was moved to a different server, all
the system administrator would need to do is set
the serverName property to the new server name.
– Pooled connections.
– Distributed transaction.
133 134
135 136
Example Example
137 138
Example Example
while (rs.next()) { getPrice = con.prepareStatement(query);
String cof = rs.getString("COF_NAME"); updatePrice = con.prepareStatement(update);
float oldPrice = rs.getFloat("PRICE");
getPrice.setInt(1, 8000);
float newPrice = oldPrice + (oldPrice * .05f);
updatePrice.setFloat(1, newPrice); rs = getPrice.executeQuery();
updatePrice.setString(2, cof); System.out.println();
updatePrice.executeUpdate(); Savepoint save2 = con.setSavepoint();
System.out.println("New price of " + cof + " is " + newPrice);
if (newPrice > 11.99) {
con.rollback(save1);
}
}
139 140
Example Example
while (rs.next()) { con.commit();
String cof = rs.getString("COF_NAME"); Statement stmt = con.createStatement();
float oldPrice = rs.getFloat("PRICE"); rs = stmt.executeQuery("SELECT COF_NAME, " +
float newPrice = oldPrice + (oldPrice * .05f); "PRICE FROM COFFEES");
updatePrice.setFloat(1, newPrice);
System.out.println();
updatePrice.setString(2, cof);
while (rs.next()) {
updatePrice.executeUpdate();
String name = rs.getString("COF_NAME");
System.out.println("New price of " + cof + " is " +
newPrice); float price = rs.getFloat("PRICE");
if (newPrice > 11.99) { System.out.println("Current price of " + name +
con.rollback(save2); " is " + price);
} }
} con.close();
141 142
• Some DBMS automatically generate a key for a row • If your driver supports them and you want to use
that is inserted in a table. them, you have to tell the Statement object to do it
• If you later want to update that row, you can use this stmt.executeUpdate(sqlstring,
key to identify the row Statement.RETURN_GENERATED_KEYS);
• You can find out whether your driver supports • For a prepared statement
automatically generated keys with pstmt=con.prepareStatement(sqlString,
DatabaseMetaData dbmd=con.getMetaData(); Statement.RETURN_GENERATED_KEYS);
Boolean b = dbmd.supportsGetGeneratedKeys();
143 144
Getting Automatically Generated Keys Getting Automatically Generated Keys
• After executing the statement, you retrieve the • Another way to signal the driver that it should prepare
generated keys with for returning generated keys is to pass it an array
ResultSet keys=stmt.getGeneratedKeys(); with the column names
• Each key will be a row in keys. • In this case
• It is possible for a key to be more than one column, String [] keyArray={“KEY”};
so the row will have as many columns as the key Stmt.executeUpdate(sqlString,keyArray);
145 146
Metadata Rowsets
• A DatabaseMetaData object provides information • A RowSet object is similar to a ResultSet object but it
about a database or a DBMS allows to work on the data also if the computer is
• The developers of the driver implemented the disconnected from the database
DatabaseMetaData interface so that its method • Example:
return information about the driver and the database – The user retrieves the data on a portable pc
• A ResultSetMetaData object provides information – The user disconnects from the network
about the columns in a particular ResultSet instance – The user works on the data
• A ParameterMetaData object provides information – When the user reconnects to the network, the data
about the parameters in a PreparedStatement object is synchronized with the data on the DBMS
• Rowsets optimize the sending of data through a
network
147 148
Alternative Approaches SQLJ
151