Using Prepared Statements
Sometimes it is more convenient to use aPreparedStatement
object for sending SQL statements to the database. This special type of statement is derived from the more general class,Statement
, that you already know.
If you want to execute aStatement
object many times, it usually reduces execution time to use aPreparedStatement
object instead.
The main feature of aPreparedStatement
object is that, unlike aStatement
object, it is given a SQL statement when it is created. The advantage to this is that in most cases, this SQL statement is sent to the DBMS right away, where it is compiled. As a result, thePreparedStatement
object contains not just a SQL statement, but a SQL statement that has been precompiled. This means that when thePreparedStatement
is executed, the DBMS can just run thePreparedStatement
SQL statement without having to compile it first.
AlthoughPreparedStatement
objects can be used for SQL statements with no parameters, you probably use them most often for SQL statements that take parameters. The advantage of using SQL statements that take parameters is that you can use the same statement and supply it with different values each time you execute it. Examples of this are in the following sections.
The following method,CoffeesTable.updateCoffeeSales
, stores the number of pounds of coffee sold in the current week in theSALES
column for each type of coffee, and updates the total number of pounds of coffee sold in theTOTAL
column for each type of coffee:
public void updateCoffeeSales(HashMap<String, Integer> salesForWeek) throws SQLException { PreparedStatement updateSales = null; PreparedStatement updateTotal = null; String updateString = "update " + dbName + ".COFFEES " + "set SALES = ? where COF_NAME = ?"; String updateStatement = "update " + dbName + ".COFFEES " + "set TOTAL = TOTAL + ? where COF_NAME = ?"; try { con.setAutoCommit(false); updateSales = con.prepareStatement(updateString); updateTotal = con.prepareStatement(updateStatement); for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) { updateSales.setInt(1, e.getValue().intValue()); updateSales.setString(2, e.getKey()); updateSales.executeUpdate(); updateTotal.setInt(1, e.getValue().intValue()); updateTotal.setString(2, e.getKey()); updateTotal.executeUpdate(); con.commit(); } } catch (SQLException e ) { JDBCTutorialUtilities.printSQLException(e); if (con != null) { try { System.err.print("Transaction is being rolled back"); con.rollback(); } catch(SQLException excep) { JDBCTutorialUtilities.printSQLException(excep); } } } finally { updateSales.close(); updateTotal.close(); con.setAutoCommit(true); } }Creating a PreparedStatement Object
The following creates aPreparedStatement
object that takes two input parameters:
String updateString = "update " + dbName + ".COFFEES " + "set SALES = ? where COF_NAME = ?"; updateSales = con.prepareStatement(updateString);Supplying Values for PreparedStatement Parameters
You must supply values in place of the question mark placeholders (if there are any) before you can execute aPreparedStatement
object. Do this by calling one of the setter methods defined in thePreparedStatement
class. The following statements supply the two question mark placeholders in thePreparedStatement
namedupdateSales
:
updateSales.setInt(1, e.getValue().intValue()); updateSales.setString(2, e.getKey());The first argument for each of these setter methods specifies the question mark placeholder. In this example,setInt
specifies the first placeholder andsetString
specifies the second placeholder.
After a parameter has been set with a value, it retains that value until it is reset to another value, or the methodclearParameters
is called. Using thePreparedStatement
objectupdateSales
, the following code fragment illustrates reusing a prepared statement after resetting the value of one of its parameters and leaving the other one the same:
// changes SALES column of French Roast row to 100 updateSales.setInt(1, 100); updateSales.setString(2, "French_Roast"); updateSales.executeUpdate(); // changes SALES column of Espresso row to 100 (the first // parameter stayed 100, and the second parameter was reset // to "Espresso") updateSales.setString(2, "Espresso"); updateSales.executeUpdate();Using Loops to Set Values
You can often make coding easier by using afor
loop or awhile
loop to set values for input parameters.
TheCoffeesTable.updateCoffeeSales
method uses a for-each loop to repeatedly set values in thePreparedStatement
objectsupdateSales
andupdateTotal
:
for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) { updateSales.setInt(1, e.getValue().intValue()); updateSales.setString(2, e.getKey()); // ... }The methodCoffeesTable.updateCoffeeSales
takes one argument,HashMap
. Each element in theHashMap
argument contains the name of one type of coffee and the number of pounds of that type of coffee sold during the current week. The for-each loop iterates through each element of theHashMap
argument and sets the appropriate question mark placeholders inupdateSales
andupdateTotal
.
Executing PreparedStatement Objects
As withStatement
objects, to execute aPreparedStatement
object, call an execute statement:executeQuery
if the query returns only oneResultSet
(such as aSELECT
SQL statement),executeUpdate
if the query does not return aResultSet
(such as anUPDATE
SQL statement), orexecute
if the query might return more than oneResultSet
object. BothPreparedStatement
objects inCoffeesTable.updateCoffeeSales
containUPDATE
SQL statements, so both are executed by callingexecuteUpdate
:
updateSales.setInt(1, e.getValue().intValue()); updateSales.setString(2, e.getKey()); updateSales.executeUpdate(); updateTotal.setInt(1, e.getValue().intValue()); updateTotal.setString(2, e.getKey());No arguments are supplied toupdateTotal.executeUpdate();
con.commit();executeUpdate
when they are used to executeupdateSales
andupdateTotals
; bothPreparedStatement
objects already contain the SQL statement to be executed.
Note: At the beginning ofCoffeesTable.updateCoffeeSales
, the auto-commit mode is set to false:
con.setAutoCommit(false);Consequently, no SQL statements are committed until the methodcommit
is called. For more information about the auto-commit mode, see #usemacro AUTOMATICLINK ( LINKFILE transactions.html ) .
Return Values for the executeUpdate Method
WhereasexecuteQuery
returns aResultSet
object containing the results of the query sent to the DBMS, the return value forexecuteUpdate
is anint
value that indicates how many rows of a table were updated. For instance, the following code shows the return value ofexecuteUpdate
being assigned to the variablen
:
updateSales.setInt(1, 50); updateSales.setString(2, "Espresso"); int n = updateSales.executeUpdate(); // n = 1 because one row had a change in itThe tableCOFFEES
is updated; the value 50 replaces the value in the columnSALES
in the row forEspresso
. That update affects one row in the table, son
is equal to 1.
When the methodexecuteUpdate
is used to execute a DDL (data definition language) statement, such as in creating a table, it returns theint
value of 0. Consequently, in the following code fragment, which executes the DDL statement used to create the tableCOFFEES
,n
is assigned a value of 0:
int n = executeUpdate(createTableCoffees); // n = 0Note that when the return value forexecuteUpdate
is 0, it can mean one of two things:
- The statement executed was an update statement that affected zero rows.
- The statement executed was a DDL statement.
No comments:
Post a Comment