1. Trang chủ
  2. » Công Nghệ Thông Tin

Prepared Statements

25 288 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

updateBfile(String columnName, BFILE x) updateBFILE(int columnIndex, BFILE x) updateBFILE(String columnName, BFILE x) updateBlob(int columnIndex, Blob x) updateBlob(String columnName, Blob x) updateBLOB(int columnIndex, BLOB x) updateBLOB(String columnName, BLOB x) updateCHAR(int columnIndex, CHAR x) updateCHAR(String columnName, CHAR x) updateClob(int columnIndex, Clob x) updateClob(String columnName, Clob x) updateCLOB(int columnIndex, CLOB x) updateCLOB(String columnName, CLOB x) updateCustomDatum(int columnIndex, CustomDatum x) updateCustomDatum(String columnName, CustomDatum x) updateDATE(int columnIndex, DATE x) updateDATE(String columnName, DATE x) updateNUMBER(int columnIndex, NUMBER x) updateNUMBER(String columnName, NUMBER x) updateOracleObject(int columnIndex, Datum x) updateOracleObject(String columnName, Datum x) updateRAW(int columnIndex, RAW x) updateRAW(String columnName, RAW x) updateRef(int columnIndex, Ref x) updateRef(String columnName, Ref x) updateREF(int columnIndex, REF x) updateREF(String columnName, REF x) updateROWID(int columnIndex, ROWID x) updateROWID(String columnName, ROWID x) updateSTRUCT(int columnIndex, STRUCT x) updateSTRUCT(String columnName, STRUCT x) You may have noticed that up to this point, we have not taken a look at large objects (LOBs) or object data types. As I stated earlier, we'll cover objects in Part III. As for large data types, we need to cover another type of statement object, a PreparedStatement, to have a complete discussion about the large object data types: BFILE, BLOB, CLOB, LONG, and LONG RAW. So let's continue our discussion of JDBC with prepared statements in Chapter 11. Chapter 11. Prepared Statements Similar to their statement counterparts, prepared statements can be used to insert, update, delete, or select data. However, prepared statements are precompiled statements that can be reused to execute identical SQL statements with different values more efficiently. They make only one trip to the database for metadata, whereas statements make a round trip with each execution. In addition, since bind variables are used, the database compiles and caches the prepared SQL statement and reuses it on subsequent executions to improve the database's performance. Prepared statements are also useful because some types of values, such as BLOBs, objects, collections, REFs, etc., are not representable as SQL text. To support this added functionality, you use a question mark as a placeholder within the text of a SQL statement for values that you wish to specify when you execute that statement. You can then replace that question mark with an appropriate value using one of the many available setXXX( ) accessor methods. setXXX( ) methods are available for setting every data type, just as getXXX( ) methods are available for getting the values for any data type from a result set. In this chapter, we'll discuss the benefits of using a prepared statement versus a statement, how to format SQL statements for use with a PreparedStatement object, how to use the various setXXX( ) methods, String data type limitations when using a PreparedStatement object, and batching. Let's start by discussing the pros and cons of using a prepared statement. 11.1 A Prepared Statement Versus a Statement It's a popular belief that using a PreparedStatement object to execute a SQL statement is faster than using a Statement object. That's because a PreparedStatement object makes only one round trip to the database to get its data type information when it is first prepared, while a Statement object must make an extra round trip to the database to get its metadata each time it is executed. So the simple conclusion is that on the second and subsequent executions of a prepared statement, it is 50% faster than a statement. However, according to my tests in Chapter 19, due to the overhead of using a PreparedStatement object, it takes at least 65 executions before a PreparedStatement object is faster than a Statement object. For a small number of executions, a PreparedStatement object is not faster than a Statement object. However, that doesn't mean you shouldn't use a PreparedStatement. On the contrary, if you use the batch capabilities of a PreparedStatement object to execute the same SQL statement many times, it is significantly faster than a Statement object. Oracle's implementation of JDBC implements batching only for PreparedStatement objects, not for Statement objects. Prepared statements are less dynamic than their statement counterparts; you can build a SQL statement dynamically at runtime, but doing so using a prepared statement requires more coding, and the code required is fairly specific to the task. Prepared statements can, however, greatly simplify formulating your SQL statements, because you don't have to worry about date formats, number formats, or tick characters in strings. And prepared statements allow you to insert or update streaming data types. The advantages of using prepared statements are that they allow you to improve efficiency by batching, utilize the SQL statement cache in the database to increase its efficiency, simplify your coding, and allow you to insert or update streaming data types, which we'll cover in Chapter 12. 11.2 Formulating SQL Statements When you write a prepared statement, you use a question mark character (?) as a placeholder that will later be replaced by a value you specify using a setXXX( ) method. These placeholders can be used only for values that need to be specified in a SQL statement and not in place of SQL keywords; they can't be used to implement a type of macro language. When building SQL statements, you must abide by certain rules. For an INSERT statement, you can use placeholders only in the VALUES list. For example: insert into person_identifier_type ( code, description, inactive_date ) values ( ?, ?, ? ) In this example, the first placeholder, or question mark (?), represents the value for the code column; the second represents the description column, and the third represents the inactive_date column. For an UPDATE statement, you can use placeholders only in the SET VALUES list and in the WHERE clause. For example: update person_identifier_type set description = ? where code = ? In this example, the first placeholder represents the new value for the description column, while the second represents a value for the code column in the WHERE clause. For a DELETE statement, you can use the placeholder only in the WHERE clause. For example: delete person_identifier_type where code = ? Finally, for a SELECT statement, you can use the placeholder in the SELECT list, WHERE clause, GROUP BY clause, and ORDER BY clause. For example: select ?, code, description from person_identifier_type where code = ? order by ? Important! The question-mark placeholder used in the select list represents a value to be supplied, not a column name. Did you notice that in these examples, there are no ticks around placeholders that represent character columns? That's because the PreparedStatement object takes care of properly formatting the data. It's important for you to understand that the placeholders allow you to provide actual values before you execute a SQL statement, and once a prepared statement is compiled (i.e., prepared), it can be executed repeatedly with different values supplied for each execution. Now that you can properly formulate a SQL statement for a PreparedStatement, let's look at the setXXX( ) methods used to set the values for the placeholders. 11.2.1 Accessor Methods There is a setXXX( ) method for each of the Java data types listed in the righthand column of Table 10-1. Of course, as with the getXXX( ) methods, you must use the appropriate setXXX( ) method for a given SQL type. The setXXX( ) methods generally have the following signature: setdataType (int parameterIndex, dataType x) which breaks down as: parameterIndex The number of the placeholder in the SQL statement, counting from left to right and starting with 1. dataType A class name from Table 10-1, except for data types with both a primitive data type and a wrapper class, in which case the second parameter is the primitive data type. For example, with setDouble( ), the parameter x would be of type double. Let's take a look at two examples. In the first, dataType is not a wrapper class. If the column last_name in the person table is a VARCHAR2(30) and is the second parameter in a prepared SQL statement, then an appropriate setXXX( ) method would be setString( ): String lastName = "O'Reilly" pstmt.setString(2, lastName); In this case, the set suffix, String, and the parameter data type, String, are both the class name, i.e., initial letter capitalized. However, if you need to update a numeric database column, say person_id in the person table (person_id is a NUMBER), and you're using a Java long data type, which is a primitive, then an appropriate setXXX( ) method would be setLong( ): long personId = 1; pstmt.setLong(1, personId); This time, the set suffix, Long, is capitalized like the wrapper class name for a long. The second parameter, however, is a long data type, the Java primitive data type. The general rule is that you pass class types for everything except the Java primitive data types that represent numbers; those are the primitive data types. 11.2.1.1 SQL type constants Since JDBC acts as an interface between Java and a particular vendor's database, JDBC has a standard set of SQL type codes that Java and JDBC drivers use to identify SQL data types. These JDBC type codes, which are integer constants defined in the java.sql.Types class, are used by the various PreparedStatement and CallableStatement accessor methods to map the database's SQL data types to Java data types, and vice versa. Table 11-1 lists the standard Oracle SQL type to Java data type mappings, and Table 11-2 lists the proprietary Oracle SQL type to Java type mappings. Table 11-1. Standard Oracle SQL type to Java data type mappings Oracle SQL data types JDBC types constants (java.sql.Types.) Standard Java data types Oracle Java data types (oracle.sql.) CHAR CHAR java.lang.String CHAR VARCHAR2 VARCHAR java.lang.String CHAR LONG LONGVARCHAR java.lang.String CHAR NUMBER NUMERIC java.math.BigDecimal NUMBER NUMBER DECIMAL java.math.BigDecimal NUMBER NUMBER BIT boolean NUMBER NUMBER TINYINT byte NUMBER NUMBER SMALLINT short NUMBER NUMBER INTEGER int NUMBER NUMBER BIGINT long NUMBER NUMBER REAL float NUMBER NUMBER FLOAT double NUMBER NUMBER DOUBLE double NUMBER RAW BINARY byte[] RAW RAW VARBINARY byte[] RAW LONG RAW LONGVARBINARY byte[] RAW DATE DATE java.sql.Date DATE DATE TIME java.sql.Time DATE DATE TIMESTAMP java.sql.Timestamp DATE BLOB BLOB java.sql.Blob BLOB CLOB CLOB java.sql.Clob CLOB user-defined object STRUCT java.sql.Struct STRUCT user-defined reference REF java.sql.Ref REF user-defined collection ARRAY java.sql.Array ARRAY The first column in Table 11-1 lists the Oracle SQL data types. The second column lists the java.sql.Types constants that can be associated with each type. These are primarily used with the PreparedStatement object's setObject( ) and with the CallableStatement object's registerOutParameter( ) methods to specify data type conversions between Java and SQL. (We'll cover the CallableStatement object's registerOutParameter( ) in Chapter 13.) However, the setXXX( ) methods are usually self-specifying. For example, when you use the setLong( ) method to set a Java long, you implicitly specify that the Java data type long will be converted to a SQL data type NUMBER. The third column in the table lists the corresponding Java data type for a given java.sql.Types constant. The fourth column lists the corresponding Oracle Java data type for a given java.sql.Types constant. Table 11-2. Proprietary Oracle SQL type to Oracle Java data type mappings Oracle SQL data types Oracle types (oracle.jdbc.driver. OracleTypes.) Standard Java data types Oracle Java data types BFILE BFILE n/a oracle.sql.BFILE ROWID ROWID n/a oracle.sql.ROWID REF CURSOR fCURSOR java.sql.ResultSet OracleResultSet Similar to Table 11-1, the first column in Table 11-2 lists Oracle SQL data types, but these data types are proprietary to Oracle. Accordingly, the second column lists the proprietary Oracle oracle.jdbc.driver.OracleTypes constants. The third column lists the corresponding Java data types, and the last column lists the proprietary Oracle Java data types. 11.2.1.2 NULL values If you wish to set a parameter in a SQL statement to NULL values, then you must use the setNull( ) method with the following signature: setNull(int parameterIndex, int sqlType) which breaks down as: parameterIndex The position of the placeholder in the SQL statement, counting from left to right and starting with 1 sqlType A java.lang.Types constant, which you can find in Table 11-1 For example, here I set the middle_name column to NULL values before inserting it into the database: String insert = "insert into person " + "( person_id, last_name, first_name, " + "middle_name, birth_date, mothers_maiden_name ) " + "values " + "( ?, ?, ?, ?, ?, ? )"; try { pstmt = conn.prepareStatement(insert); pstmt.setLong(1, 999999999); pstmt.setString(2, "Krishnamurti"); pstmt.setString(3, "Jiddu"); pstmt.setNull(4, Types.VARCHAR); pstmt.setDate(5, Date.valueOf("1895-05-12")); pstmt.setString(6, "Unknown"); rows = pstmt.executeUpdate( ); } 11.2.1.3 Dynamic input Dynamic input refers to formulating and preparing a SQL statement at runtime. Because you don't know the SQL statement when you write your code, you don't know how many parameters it will have, nor do you know their types. Consequently, you don't know which, or how many, setXXX( ) methods to use, and you need a more general method for setting parameter values. In such a case, you can use the setObject( ) method, which works with the default mappings shown in Tables Table 11-1 and Table 11-2. setObject( ) has the following three overloaded signatures: setObject( int parameterIndex, Object x) setObject( int parameterIndex, Object x, int targetSqlType) setObject( int parameterIndex, Object x, int targetSqlType, int scale) which break down as: parameterIndex The number of the placeholder in the SQL statement, counting from left to right and starting with 1 Object A Java object reference targetSqlType A java.lang.Types constant scale The number of digits to the right of the decimal point for numeric SQL data types All three methods can throw a SQLException. The first form of setObject( ) assumes the standard mappings shown in Tables Table 11-1 and Table 11-2. With the second form of setObject( ), use a java.lang.Types constant to specify the SQL type of the parameter you are setting. The third form of setObject( ) is designed for use with numeric input and enables you to truncate the number of significant digits to the right of the decimal point. For the most part, you'll need only the first form. Here's my earlier example rewritten to use setObject( ): String insert = "insert into person " + "( person_id, last_name, first_name, " + "middle_name, birth_date, mothers_maiden_name ) " + "values " + "( ?, ?, ?, ?, ?, ? )"; try { pstmt = conn.prepareStatement(insert); pstmt.setObject(1, new Long(999999999)); pstmt.setObject(2, "Krishnamurti"); pstmt.setObject(3, "Jiddu"); pstmt.setNull(4, Types.VARCHAR); pstmt.setObject(5, Date.valueOf("1895-05-12")); pstmt.setObject(6, "Unknown"); rows = pstmt.executeUpdate( ); } In this case, because I used setObject( ), the driver must take an extra step to determine the data type being passed to it. Consequently, it's more efficient to use the specific setXXX( ) methods whenever possible. Notice how I used new Long(999999999) to specify a value for the person_id column. I did this because you can't pass a Java primitive when using the setObject( ) methods. Instead, you need to use a wrapper class around the Java primitive numeric data types (also called integrals in the JDK API documentation). 11.2.1.4 Dynamic input using the Oracle data types If you wish to work with the Oracle data types in oracle.sql.*, then you need to cast your PreparedStatement object to an OraclePreparedStatement object and use its setOracleObject( ) method: String insert = "insert into person " + "( person_id, last_name, first_name, " + "middle_name, birth_date, mothers_maiden_name ) " + "values " + "( ?, ?, ?, ?, ?, ? )"; try { pstmt = conn.prepareStatement(insert); ((OraclePreparedStatement)pstmt).setOracleObject( 1, new NUMBER(999999999)); ((OraclePreparedStatement)pstmt).setOracleObject( 2, new CHAR("Krishnamurti", CHAR.DEFAULT_CHARSET)); ((OraclePreparedStatement)pstmt).setOracleObject( 3, new CHAR("Jiddu", CHAR.DEFAULT_CHARSET)); ((OraclePreparedStatement)pstmt).setNull( 4, Types.VARCHAR); ((OraclePreparedStatement)pstmt).setOracleObject( 5, new DATE(Date.valueOf("1895-01-01"))); ((OraclePreparedStatement)pstmt).setOracleObject( 6, new CHAR("Unknown", CHAR.DEFAULT_CHARSET)); rows = ((OraclePreparedStatement)pstmt).executeUpdate( ); } 11.2.1.5 Fixed-length CHAR columns There is one proprietary setXXX( ) method you need to be aware of. It is the OraclePreparedStatement object's setFixedCHAR( ). You need to use this if the column you are setting in a WHERE clause is an Oracle CHAR data type, which is fixed-length and right- padded with spaces. setFixedCHAR( ) sets the column's value and adds any right padding as necessary. To use it, you need to cast your PreparedStatement object to an OraclePreparedStatement object, as in the following example: PreparedStatement pstmt = conn.prepareStatement( ); ((OraclePreparedStatement)pstmt).setFixedCHAR(1, code); Of course, as I have already stated several times in this book, I would never use a CHAR database type. 11.2.1.6 A prepared statement example Example 11-1 demonstrates the use of placeholders and the setXXX( ) methods for all four types of DML statements. Example 11-1. Test placeholders and setter methods import java.io.*; import java.sql.*; import java.text.*; public class TestPlaceHolder { Connection conn; public TestPlaceHolder( ) { try { DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver( )); conn = DriverManager.getConnection( "jdbc:oracle:thin:@dssw2k01:1521:orcl", "scott", "tiger"); } catch (SQLException e) { System.err.println(e.getMessage( )); e.printStackTrace( ); } } public static void main(String[] args) throws Exception, IOException { new TestPlaceHolder().process( ); } public void process( ) throws IOException, SQLException { int rows = 0; ResultSet rslt = null; PreparedStatement pstmt = null; String insert = "insert into person_identifier_type " + "( code, description, inactive_date ) " + "values " + "( ?, ?, ? )"; String update = "update person_identifier_type " + "set description = ? " + "where code = ?"; String delete = "delete person_identifier_type " + "where code = ?"; String select = "select ?, code, description " + "from person_identifier_type " + "where code = ? " + "order by ?"; try { System.out.println(insert); pstmt = conn.prepareStatement(insert); pstmt.setString( 1, "SID" ); pstmt.setString( 2, "Student Id" ); pstmt.setNull( 3, Types.TIMESTAMP ); rows = pstmt.executeUpdate( ); pstmt.close( ); pstmt = null; System.out.println(rows + " rows inserted"); System.out.println(""); } catch (SQLException e) { System.err.println(e.getMessage( )); } finally { if (pstmt != null) try { pstmt.close( ); } catch (SQLException ignore) { } } try { System.out.println(update); pstmt = conn.prepareStatement(update); pstmt.setString( 1, "Student ID" ); pstmt.setString( 2, "SID" ); rows = pstmt.executeUpdate( ); pstmt.close( ); pstmt = null; System.out.println(rows + " rows updated"); System.out.println(""); } catch (SQLException e) { System.err.println(e.getMessage( )); } finally { if (pstmt != null) try { pstmt.close( ); } catch (SQLException ignore) { } } try { System.out.println(select); pstmt = conn.prepareStatement(select); pstmt.setString( 1, "A CONSTANT" ); pstmt.setString( 2, "SID" ); pstmt.setString( 3, "A" ); rslt = pstmt.executeQuery( ); rows = 0; while (rslt.next( )) { rows++; System.out.print(rslt.getString(1) + " "); System.out.print(rslt.getString(2) + " "); System.out.println(rslt.getString(3)); } pstmt.close( ); pstmt = null; System.out.println(rows + " rows selected"); System.out.println(""); } catch (SQLException e) { System.err.println(e.getMessage( )); } finally { if (rslt != null) try { rslt.close( ); } catch (SQLException ignore) { } if (pstmt != null) try { pstmt.close( ); } catch (SQLException ignore) { } } try { System.out.println(delete); pstmt = conn.prepareStatement(delete); pstmt.setString( 1, "SID" ); rows = pstmt.executeUpdate( ); pstmt.close( ); pstmt = null; System.out.println(rows + " rows deleted"); } catch (SQLException e) { System.err.println(e.getMessage( )); [...]... SQL statements in a batch is greater than 30 Now that you've seen both implementations at work, let's move on to our last topic in this chapter, a summary of the relationship between PreparedStatement and OraclePreparedStatement 11.4 PreparedStatement Is an OraclePreparedStatement The PreparedStatement object is an interface, java.sql.PreparedStatement, implemented by the oracle.jdbc.driver.OraclePreparedStatement... for prepared statements Although it does provide the methods for batching statements and callable statements, it does not actually support batching for them So if you want to receive any benefit from batching, you must use prepared statements 11.3.1 Standard Batching Implementation Taking a look at the big picture, standard batching works as follows First, you turn off autocommit and create a prepared. .. "execute" a statement, call the PreparedStatement object's addBatch( ) method instead of the executeUpdate( ) method This will add your prepared statement to a batch of SQL statements, which will then be sent to the database for processing when you call the second method, executeBatch( ) 11.3.1.2 Executing a batch The second method, executeBatch( ), sends any batched SQL statements to the database for... "jdbc:oracle:thin:@dssw2k01:1521:orcl", info ); However, you set the default value; doing so for a Connection object affects all subsequent PreparedStatement objects 11.3.2.2 Setting a batch size for a specific statement If you want to set a different batch size for each prepared statement, cast your PreparedStatement object to an OraclePreparedStatement object, then call its setExecuteBatch( ) method The setExecuteBatch( ) method has the... a PreparedStatement to 30: ((OraclePreparedStatement)pstmt).setExecuteBatch(30); 11.3.2.3 Forcing batch execution You can force an OraclePreparedStatement to send its current batch to the database by calling the sendBatch( ) method This method has the following signature: int sendBatch( ) Whenever you call the sendBatch( ) method, it returns the total number of rows affected by all the batched SQL statements. .. Batching Batching allows you to gather multiple SQL statements for the same PreparedStatement into a batch The statements in that batch are in turn sent to the database together instead of sent one statement at a time This reduces the consumption of network bandwidth by eliminating the overhead of redundant packet headers in small packets Instead, the statements are transmitted in one or more larger packets... batching, turn off auto-commit and create a prepared statement Next, set an execute batch size using one of three methods I'll cover shortly This batch size is used by Oracle batching to determine when to send a batch to the database When the number of batched SQL statements reaches the specified batch size, the Oracle driver automatically sends the SQL statements to the database So instead of calling... getConnection( ) method • Use the PreparedStatement object's setExecuteBatch( ) method to specify a batch size for a specific statement The first two methods set a default batch size for all statements created by a connection The third method sets a batch size for a specific statement 11.3.2.1 Setting a default batch size for a connection You can set the default batch size for all statements created by a connection... statement to a batch Repeat the process of setting values and adding to a batch until you are ready to send the SQL statements to the database Then, when you are ready to send batched SQL statements to the database, call the executeBatch( ) method The executeBatch( ) method in turn sends the SQL statements in the batch to the database all at once Finally, commit your database changes by calling Connection.commit(... = null; PreparedStatement pstmt = null; String insert = "insert into person_identifier_type " + "( code, description, inactive_date ) " + "values " + "( ?, ?, ? )"; String delete = "delete person_identifier_type " + "where code = ?"; try { System.out.println(insert); pstmt = conn.prepareStatement(insert); ((OraclePreparedStatement)pstmt).defineParameterType( 1, Types.VARCHAR, 30); ((OraclePreparedStatement)pstmt).defineParameterType( . discussion of JDBC with prepared statements in Chapter 11. Chapter 11. Prepared Statements Similar to their statement counterparts, prepared statements can be. delete, or select data. However, prepared statements are precompiled statements that can be reused to execute identical SQL statements with different values

Ngày đăng: 29/09/2013, 09:20

Xem thêm: Prepared Statements

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN