JDBC TALKING TO DATABASE (Unit-VI) K.Phani Sirisha What Is JDBC? • Java database connectivity or JDBC is an interface used to connect to relational databases from the Java program. • JDBC is a Java API which consists of a set of classes and interfaces written in the Java programming language. • JDBC provides a standard API tool for database developers and makes it possible to write database applications using a pure Java API. • With the help of JDBC API developers can query database, add data, update data and even delete the data from database very easily. What does JDBC Do ? With the help of JDBC, it is possible to do the following three things • to establish a connection with a database • to send SQL statements • to process the resullts The following code fragment gives a basic example of these three steps: Connection con = DriverManager.getConnection ( "jdbc:odbc:wombat", "login", "password"); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); while (rs.next()) { int x = getInt("a"); String s = getString("b"); float f = getFloat("c"); } JDBC Vs. ODBC and other APIs Microsoft's ODBC (Open DataBase Connectivity) API is probably the most widely used programming interface for accessing relational databases. It offers the ability to connect to almost all databases on almost all platforms. So why not just use ODBC from Java? "Why do you need JDBC?" • ODBC is not appropriate for direct use from Java because it uses a C interface. Calls from Java to native C code have a number of drawbacks in the security, implementation, robustness, and automatic portability of applications. • A literal translation of the ODBC C API into a Java API would not be desirable. For example, Java has no pointers, and ODBC makes copious use of them. • ODBC is hard to learn. It mixes simple and advanced features together, and it has complex options even for simple queries. JDBC, on the other hand, was designed to keep simple things simple while allowing more advanced capabilities where required. • When ODBC is used, the ODBC driver manager and drivers must be manually installed on every client machine. When the JDBC driver is written completely in Java, however, JDBC code is automatically installable, portable, and secure on all Java platforms from network computers to mainframes. Two-tier and Three-tier Models • The JDBC API supports both two-tier and three-tier models for database access. • In a two-tier model, a Java application/applet communicates directly with the database, via the JDBC driver. The Java application/applet and the database can be on the same machine, or the database can be on a server and the Java application/applet can be on a client machine using any network protocol. • In the three-tier model, commands are sent to a "middle tier" of services, which then send SQL statements to the database. The database processes the SQL statements and sends the results back to the middle tier, which then sends them to the user. Another advantage is that when there is a middle tier, the user can employ an easy-to-use higher-level API which is translated by the middle tier into the appropriate low-level calls. • In a three-tier model, a Java application/applet communicates with a middle tier component that functions as an application server. The application server talks to a given database using JDBC. The JDBC Package • The java.sql and javax.sql are the primary packages for JDBC 4.0 JDBC API is contained in 2 packages. java.sql - which contains java data objects that provide the basics for connecting to the DBMS and interacting with data stored in the DBMS. This package is a part of J2SE. javax.sql – which extends java.sql and is in J2EE. This includes the data objects that manage connection pooling, JNDI , and other advanced JDBC features. Components of JDBC Component Description DriverManager It loads database drivers and manages the connection between the application and the driver Driver It translates API calls into operation for a specific data source Connection It is a session between an application and a database It is an SQL statement to perform a query or update operation It gives information about returned data, the database, and the driver It is the logical set of columns and rows of data returned by executing a statement Statement MetaData ResultSet Types of JDBC Drivers The JDBC drivers that we are aware of at this time fit into one of four categories: • JDBC-ODBC bridge driver: Which provides JDBC access via ODBC drivers. Note that ODBC binary code, and in many cases database client code, must be loaded on each client machine that uses this driver. As a result, this kind of driver is most appropriate on a corporate network where client installations are not a major problem, or appropriate for application server code written in Java in a three-tier architecture. • Native-API partly-Java driver: This kind of driver converts JDBC calls into calls on the client API for Oracle, Sybase, Informix, DB2, or other DBMS. Note that, like the bridge driver, this style of driver requires that some binary code be loaded on each client machine. • JDBC-Net pure Java driver: This driver translates JDBC calls into a DBMS- independent net protocol which is then translated to a DBMS protocol by a server. This net server middleware is able to connect its pure Java clients to many different databases. The specific protocol used depends on the vendor. In general, this is the most flexible JDBC alternative. • Native-protocol pure Java driver: This kind of driver converts JDBC calls into the network protocol used by DBMSs directly. This allows a direct call from the client machine to the DBMS server and is a practical solution for Intranet access. Note: To access database using the JDBC API, driver categories 3 and 4 are the most preferable. JavaSoft Framework JavaSoft provides three JDBC product components as part of the Java Development Kit (JDK): • The JDBC driver manager, • The JDBC driver test suite, and • The JDBC-ODBC bridge. The JDBC driver manager is the backbone of the JDBC architecture. Its primary function is to connect Java applications to the correct JDBC driver The JDBC driver test suite provides some confidence that JDBC drivers will run your program. Only drivers that pass the JDBC driver test suite can be designated JDBC COMPLIANT The JDBC-ODBC bridge allows ODBC drivers to be used as JDBC drivers. It will provide a way to access some of the less popular DBMSs if JDBC drivers are not implemented for them. Driver Interface and DriverManager Class • To create Connection objects is the primary use of the Driver interface. • All drivers supply a class that implements the Driver interface. • DriverManager keeps track of the drivers that are available and establishing a connection between a database and the appropriate driver. • With the help of DriverManager class drivers are loaded for any given connection request • When a Driver class is loaded, it creates an instance of itself and registers it with the DriverManager class. • A user can load and register a driver by calling Class.forName(“URL”) • The DriverManager class will attempt to load the driver classes referenced in the Url by calling getConnection and getDrivers methods. Connection Interface • A Connection object is instantiated to make a connection to a specific database using a specific driver. • Connection interface can be used for the maintenance and monitoring the status of database sessions • A connection session includes the SQL statements that are executed and the results that are returned over that connection. • A single application can have one or more connections with a single database, or it can have connections with many different databases. Statement Interface • A Statement object is used to send SQL statements to a database. • There are actually three kinds of Statement objects, all of which act as containers for executing SQL statements on a given connection: Statement, PreparedStatement, which inherits from Statement, and CallableStatement, which inherits from PreparedStatement. • They are specialized for sending particular types of SQL statements • A Statement object is used to execute a simple SQL statement • A PreparedStatement object is used to execute a precompiled SQL statement • A CallableStatement object is used to execute a call to a database stored procedure. PreparedStatement Interface • The PreparedStatement interface is a subclass of Statement interface. It is used to execute precompiled SQL statements. • For faster and efficient statement execution, pre-compilation is allowed. ResultSet Interface • A ResultSet is actually a container for the result of a query. i.e which contains all of the rows which satisfied the conditions in an SQL statement • ResultSet provides the methods for the retrieval of data which is returned by the database. • It also contains methods for conversion of data types between SQL and Java. ResultSetMetaData Interface • Through ResultSetMetaData interface, the user can get information about the types and properties of the columns in a ResultSet object • This is useful to collect data that has the same semantics, but stored in different database sources in different formats. DatabaseMetaData Interface • The DatabaseMetaData interface provides information regarding the database itself. • For example, it gives information about its version , table names, columns of these tables and their types and supported functions. • It has also methods for discovering database information specific to the current connection, such as available tables, schemas, and catalogs. The Essential JDBC Program Basic steps to writing an application that uses JDBC API 1. Import the java.sql package Any application that uses JDBC API must import the java.sql package import java.sql.*; 2. Load a JDBC Driver • JDBC driver must be loaded before the J2EE component can connect the DBMS. • When a driver class is first loaded, it registers itself with the DriverManager. • Class.forName() method can be used to load the JDBC driver. • We should pass the name of the driver to this method and this method throws ClassNotFoundException if an error occurs when loading the driver String driver = “sun.jdbc.odbc.JdbcOdbcDriver”; Class.forName(driver); OR Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); 3. Establishing a Connection • Once the driver is loaded, the J2EE component must connect the DBMS using the DriverManager class and Connection interface. • getConnection() method of DriverManager class is used to establishing a connection to the database • DriverManager Connects to given JDBC URL with given user name and password. • A Connection object is returned by the getConnection() if access is granted; else getConnection() throws an SQLException. • If username & password is required then those information need to be supplied to access the database. Connection con = DriverManager.getConnection(url,username,password) ; 4. Create a Statement • Once the Connection is established, a Statement object is needed to execute the SQL statements • So, to create a Statement object, we can use createStatement() method of Connection interface by using Connection object. Statement st = con.createStatement(); 5.Execute the Statement • The executeQuery() method of Statement interface is used to execute queries to the database and it throws an SQLException if it found anything wrong in the query. • This method returns the object of ResultSet that can be used to get all the records of a table. ResultSet rs = st.executeQuery(“Select * from Customers”); 6. Process the ResultSet • After executing the query, the results received from DBMS are assigned to ResultSet object. • Only one ResultSet per Statement can be open at once. • The ResultSet consists of tuples and returns one tuple at a time when the next() function is paplied • We can say that the ResultSet acts like an iterator. • A ResultSet maintains a cursor pointing to its current row of data. • The next() method moves the cursor to the next row. • getString() method of ResultSet object is used to get the value of a specified column in the current row of the ResultSet. while(rs.next()) { FirstName = rs.getString(1); LastName = rs.getString(2); Salary = rs.getInt(3); System.out.println(Firstname+” “+LastName+” “+salary); } 7. Close the Satement • It is appropriate to close a statement when it is no longer in need st.close(); 8. Close the Connection • Once the J2EE component is finished accessing the DBMS, it is necessary to disconnect from the database • The connection to the DBMS is terminated by using the close() method of the Connection interface. • commit() function is executed to commit all transactions that have been made through the connection • By closing connection object statement and ResultSet will be closed automatically. con.commit(); con.close(); JDBC URL Syntax: jdbc : <subprotocol> : <subname> • URL consists of 3 parts Jdbc – This indicates that the jdbc protocol is to be used to read the URL. <subprotocol> - which is the JDBC driver name <subname> - which is the name of the database • Each driver has its own subprotocol • Each subprotocol has its own syntax for the source Ex: jdbc : odbc : CustomerInfo Statement Object contains 3 methods: execute() (used for DDL commands like, Create, Alter, Drop) executeUpdate() (Used for DML commands like, Insert, Update, Delete) exceuteQuery() (Used for Select command) • The execute() method is used during execution of DDL commands and also used when there may be multiple results returned. • The executeUpdate() executes INSERT, UPDATE, DELETE, and returns an integer value specifying the number of rows affected or 0 if zero rows selected. • The executeQuery() method, which passes the query as an argument. The query is then transmitted to the DBMS for processing. • The executeQuery()method executes a simple select query and returns a ResultSet object. • All the 3 methods throws an SQLException when error occurs. Example-1: Statement st = con.createStatement(); ResultSet rs = st.executeQuery(“select * from employee”); Example-2: Statement st = con.createStatement(); int r=st.executeUpdate(“insert into employee values(10,"skr”,98453421)”); int s= st.executeUpdate(“update employee set Mobile=89706454 where Mobile=98453421” ); int n=st.executeUpdate(“delete from employee where eno=10”); Example-3: Statement st = con.createStatement(); st.execute(“Drop table Employee”); st.execute(“Create table Employee (eno number,name varhcar(10), age Number(3))”); st.execute(“alter table employee add primary key(eno)”); PreparedStatement • The PreparedStatement object allows you to execute parameterized queries. • PreparedStatement interface is used to represent a precompiled query, which can be executed multiple times without compiling it again and again. • It improves the performance of an application and performs faster execution by avoiding compilation of multiple queries. • A SQL query can be precompiled and executed by using the PreparedStatement object. Ex: Select * from employee where eno=? • Here a query is created as usual, but a question mark is used as a placeholder for a value that is inserted into the query after the query is compiled. • The prepareStatement() method of Connection object is called to return the PreparedStatement object. • The setxxx() method of the PreparedStatement object is used to replace the question mark with the value passed to the setxxx() method. • The setxxx() requires 2 parameters. The first parameter is an integer that identifies the position of the question mark placeholder and the second parameter is the value that replaces the question mark placeholder. • PreparedStatement's execute methods have no parameters Code snippet: try{ PreparedStatement pst; String query=“select * from customer where custNumber=?”; pst = con.prepareStatement(query); pst.setInt(1,1234); ResultSet rs=pst.executeQuery(); pst.close(); } catch (Exception e) { } executeUpdate • executeUpdate method can be used to execute both the Statement and the PreparedStatement objects. • No argument is supplied to the execueUpdate when it is used with PreparedStatement because the PreparedStatement’s object already contains the query • Once a parameter has been set with a value, it will retain that value until it is reset to another value or the method clearParameters is called String query = “update coffees set sales=? where cof_name like ? “; PreparedStatement updateSales = con.prepareStatement(query); updateSales.setInt(1,75); updateSales.setString(2,”colombian”); updatesales.executeUpdate(); • executeUpdate() method can also return an integer value that indicates howmany rows of a table were updated int n = updatesales.executeUpdate(); Using a Loop to Set Values The following code fragment demonstrates using a for loop to set values for parameters in the preparedStatement object updateSales. String query = “update coffees set sales=? where cof_name like ? “; PreparedStatement updateSales = con.prepareStatement(query); int [] sales = {175,150,60}; String [] coffees = {“colombian”,”French_Roast”, “Espresso”}; for(int i=0;i<coffees.length;i++) { updateSales.setInt(1,sales[i]); updateSales.setString(2,coffees[i]); updatesales.executeUpdate(); } ResultSet • The ResultSet interface is used to represent the data in tabular form, which is generated by executing an SQL query. • The ResultSet object contains methods that are used to copy data from the ResultSet into a Java collection object or variable for further processing. • Data in a ResultSet object is logically organized into a virtual table consisting of rows and columns. • The ResultSet uses a virtual cursor to point to a row of the virtual table. • The virtual cursor is positioned above the first row of data when the ResultSet is returned by the executeQuery(). This means the virtual cursor must be moved to the first row using the next() method. • The next() method returns a boolean true if the row contains data, otherwise a boolean false is returned. • Once the virtual cursor points to a row, the getxxx() method is used to copy data from the row to a collection, object or variable. • The data type of the getxxx() method must be same data type as the column in the ResultSet. • getxxx() method requires one parameter, which is an integer that represents the number of the column that contains the data. • For example, getString(1) copies the data from the first column of the ResultSet. • We can also retrieve the data from ResultSet object by passing column name as argument to the getxxx() method. i.e rs.getString(“FirstName”); Reading the ResultSet try { String query = "SELECT FirstName,LastName FROM Customers"; Statement st; ResultSet rs; st = con.createStatement(); rs = st.executeQuery (query); while(rs.next()) { System.out.println(rs.getString(1) +”\t”+ rs. getString (2)); } st.close(); } catch ( Exception e ){ } Scrollable ResultSets • The Scrollable Resultset is the first area of new functionality. • It is possible with the method next to move through the rows of a ResultSet, which is started at the first row and going to the last row. (i.e only forward) • But by using this scrollable ResultSet that is scrollable, you can move a ResultSet’s cursor wherever you want and also check on where it is currently positioned. • you can move back one row at any time or start at the last row and iterate through a Resultset’s rows backwards with the method previous. • There are also methods for moving to the nth row or moving a specified number of rows from the current row. • It can also move the cursor to the first row, the last row, the position before the first row, and the position after the last row. Code Snippet: ResultSet rs = st. executeQuery(“select * from committees”); While(rs.next()) { } rs.absolute(5); rs.relative(-2); rs.relative(4); rs.previous(); int rowNumber = rs.getRow(); rs.moveAfterLast(); while(previous()) { } Batch Updates • Batch Processing allows you to group related SQL statements into a batch and submit them with one call to the database. • When you send several SQL statements to the database at once, you reduce the amount of communication overhead, thereby improving performance. • You should use the DatabaseMetaData.supportsBatchUpdates() method to determine if the target database supports batch update processing. The method returns true if your JDBC driver supports this feature. • The addBatch() method of Statement, PreparedStatement, and CallableStatement is used to add individual statements to the batch. • The executeBatch() is used to start the execution of all the statements grouped together. • The executeBatch() returns an array of integers, and each element of the array represents the update count for the respective update statement. • Just as you can add statements to a batch for processing, you can remove them with the clearBatch() method. This method removes all the statements you added with the addBatch() method. However, you cannot selectively choose which statement to remove. Code Snippet: con.setAutoCommit(false); Statement st = con.creatSatement(); st.addBatch(“Insert into emploee values(1000, ‘Joe Jones’)”); st.addBatch(“Insert into departments values(260, ‘Shoe’)”); st.addBatch(“Insert into emp_dept values(1000, ‘260’)”); int [] updateCounts = st.executeBatch(); con.commit(); • • • Programmatic Updates ( Updatable Resultset) Using the JDBC API, you can modify column values and insert or delete a row instead of SQL statements. To change the address and amount columns in the fourth row, then use the following code fragment rs.absolute(4); rs.updateString(“address”,”321 kasten”); rs.updateFloat(“amount”,10101.0f); rs.updateRow(); To insert a new row, you have to follow certain steps. Firstly, you move the cursor to a special row, called the insert row to build the new row. Secondly, you send the new row to the database, and finally move the cursor back to the ResultSet. rs.moveToInsertRow(); rs.updateObject(1,myArray); rs.updateInt(2,3856); rs.udateString(3,”Mysteries”); rs.insertRow(); rs.first(); You move the cursor to the row you want to delete ad call the method deleteRow to delete a row rs.first(); rs.deleteRow(); Data Types and JDBC • Since SQL data types and Java data types are not identical, there needs to be some mechanism for reading and writing data between an application using Java types and a database using SQL types. • JDBC data types are the bridge data types between java data type and underlying database software. • The JDBC driver converts the Java data type to the appropriate JDBC type before sending it to the database. It uses a default mapping for most data types. • These JDBC data types are JDBC driver independent • The OUT parameter contains the value returned by the stored procedures. The OUT parameter must be registered using the registerOutParameter() method, and then later retrieved by using the getxxx() method. • The INOUT parameter is a single parameter that is used to pass information to the stored procedure and retrieve information from the stored procedure. • Each parameter is denoted by “?” (question mark placeholder for each parameter) , and we will set the value for the parameters by using the setxxx() methods Code snippet: CallableStatement cstmt = con.prepareCall( “{call getMonthDate(?,?)}); cstmt.setInt(1,6); cstmt.setInt(2,1999); ResultSet rs = cstmt.executeQuery(); Callable Statement (Calling Stored Procedures) • A CallableStatement object provides a way to call stored procedures in a standard way for all DBMSs. • A stored procedure is stored in a database and it is a block of code which is identified by a unique name. • The stored procedure is executed by invoking the name of the stored procedure. • The syntax for a stored procedure with no parameters would look like this: { call procedure_name } • CallableStatement objects are created with the Connection method prepareCall. CallableStatement cstmt = con.prepareCall( "{call procedureName}”); • The CallableStatement object uses 3 types of parameters IN, OUT and INOUT when calling a stored procedure. • The IN parameter contains any data that needs to be passed to the stored procedure and whose value is assigned using the setxxx() method. • Procedures can also have parameters for returning a resultreferred to as OUT parameters • The syntax for a procedure that returns a result parameter is: {? = call procedure_name[(?, ?, ...)]} • The placeholder for an OUT parameter is also ? • For each OUT parameter, you must identify the type of the output value as one of the types defined in the java.sql.Types class by calling the registerOutParameter() method for the CallableStatement obejct. cstmt.registerOutParameter(2,Types.INTEGER); • Once the OUT parameter has been registered, you can execute the procedure and get the value from the CallableStatement int value = cstmt.getInt(2); Mapping Relational Data onto Java Objects • Because data types in SQL and data types in the Java programming language are not identical, there needs to be some mechanism for transferring data between an application using Java types and a database using SQL types • In order to transfer data between a database and an application written in the Java programming language, the JDBC API provides three sets of methods: Methods on the ResultSet class for retrieving SQL SELECT results as Java types Methods on the PreparedStatement class for sending Java types as SQL statement parameters Methods on the CallableStatement class for retrieving SQL OUT parameters as Java types Mapping SQL Data Types to Java Types • When the programmers use SQL type names to create a table using CREATE TABLE statement then they must take care to use SQL type names that are supported by their target database. • If you want to write portable JDBC programs that can create tables on a variety of different databases, you have two main choices. First, you can use SQL type names such as INTEGER, NUMERIC, or VARCHAR, which are likely to work for all databases. Or second, you can use the DatabaseMetaData.getTypeInfo method to discover which SQL types are actually supported by a given database and select a database-specific SQL type name that matches a given JDBC type. • JDBC defines a standard mapping from the JDBC database types to Java types. For example, a JDBC INTEGER is normally mapped to a Java int. Basic JDBC Data Types • The following list defines different JDBC data types which are supported by JDBC 4.0 API and how they are related to standard SQL types and to Java types CHAR, VARCHAR, and LONGVARCHAR • CHAR represents a small, fixed-length character string, VARCHAR represents a small, variable- length character string, and LONGVARCHAR represents a large, variable-length character string. • The SQL CHAR type and SQL VARCHAR type are mapped to JDBC CHAR and JDBC VARCHAR types and supported by all the major databases • There is no consistent SQL mapping for the JDBC LONGVARCHAR type. All the major databases support some kind of very large variable-length string supporting up to at least a gigabyte of data, but the SQL type names vary. • The recommended Java mapping is String and the recommended method is Resultset.getString BINARY, VARBINARY, and LONGVARBINARY • BINARY represents a small, fixed-length binary value, VARBINARY represents a small, variable-length binary value, and LONGVARBINARY represents a large, variable-length binary value. • The use of these various BINARY types has not been standardized and support varies considerably among the major databases • BINARY, VARBINARY, and LONGVARBINARY can all be expressed identically as byte arrays in Java. • The method recommended for retrieving BINARY and VARBINARY values is ResultSet.getBytes • The method getBinaryStream is recommended if a column of type JDBC LONGVARBINARY stores a byte array that is many megabytes long BIT • The JDBC type BIT represents a single bit value that can be zero or one. • The recommended Java mapping for the JDBC BIT type is as a Java boolean. TINYINT • The JDBC type TINYINT represents an 8-bit unsigned integer value between 0 and 255. • The corresponding SQL type, TINYINT, is currently supported by only a subset of the major databases. • The recommended Java mapping for the JDBC TINYINT type is as either a Java byte or a Java short. SMALLINT • The JDBC type SMALLINT represents a 16-bit signed integer value between -32768 and 32767. • The corresponding SQL type, SMALLINT, is defined in SQL-92 and is supported by all the major databases • The recommended Java mapping for the JDBC SMALLINT type is as a Java short. INTEGER • The JDBC type INTEGER represents a a 32-bit signed integer value between 2147483648 and 2147483647. • The corresponding SQL type, INTEGER, is defined in SQL-92 and is widely supported by all the major databases. • The recommended Java mapping for the INTEGER type is as a Java int. BIGINT • The JDBC type BIGINT represents a 64-bit signed integer value between 9223372036854775808 and 9223372036854775807. • The corresponding SQL type BIGINT is a non-standard extension to SQL and not implemented by any of the major databases, and we recommend that its use should be avoided in portable code. • The recommended Java mapping for the BIGINT type is as a Java long. REAL • The JDBC type REAL represents a "single precision" floating point number which supports 7 digits of mantissa. • The corresponding SQL type REAL is defined in SQL-92 and is widely, though not universally, supported by the major databases. • The recommended Java mapping for the REAL type is as a Java float. DOUBLE • The JDBC type DOUBLE represents a "double precision" floating point number which supports 15 digits of mantissa. • The corresponding SQL type is DOUBLE PRECISION, which is defined in SQL- 92 and is widely supported by the major databases. • The recommended Java mapping for the DOUBLE type is as a Java double. FLOAT • The JDBC type FLOAT is basically equivalent to the JDBC type DOUBLE. • FLOAT represents a "double precision" floating point number that supports 15 digits of mantissa. • The corresponding SQL type FLOAT is defined in SQL-92. • The recommended Java mapping for the FLOAT type is as a Java double. DECIMAL and NUMERIC • The JDBC types DECIMAL and NUMERIC are very similar. • The method recommended for retrieving DECIMAL and NUMERIC values is ResultSet.getBigDecimal DATE, TIME, and TIMESTAMP • There are three JDBC types relating to time: • The JDBC DATE type represents a date consisting of day, month, and year. • The JDBC TIME type represents a time consisting of hours, minutes, and seconds. • The JDBC TIMESTAMP type represents DATE plus TIME plus a nanosecond field. • Because the standard Java class java.util.Date does not match any of these three JDBC date-time types exactly (it includes both DATE and TIME information but has no nanoseconds), JDBC defines three subclasses of java.util.Date to correspond to the SQL types. They are: • java.sql.Date for SQL DATE information. • java.sql.Time for SQL TIME information. java.sql.Timestamp for SQL TIMESTAMP information Advanced JDBC Data Types • The ISO (International Organization for Standardization) and IEC (the International Electrotechnical Commission) have defined new data types that are commonly referred to as SQL3 types. Of these new SQL3 data types, BLOB, CLOB, ARRAY, and REF are predefined types, whereas the SQL structured type and the DISTINCT type are userdefined types (UDTs). BLOB • The JDBC type BLOB represents an SQL3 BLOB (Binary Large Object). • A JDBC BLOB value is mapped to an instance of the Blob interface in the Java programming language. CLOB • The JDBC type CLOB represents the SQL3 type CLOB (Character Large Object). • A JDBC CLOB value is mapped to an instance of the Clob interface in the Java programming language. • The BLOB and CLOB data can be retrieved by using the method getBinaryStream() or getAsciiStream() ARRAY • The JDBC type ARRAY represents the SQL3 type ARRAY. • An ARRAY value is mapped to an instance of the Array interface in the Java programming language. STRUCT • The JDBC type STRUCT represents the SQL3 structured type. An SQL structured type, which is defined by a user with a CREATE TYPE statement, consists of one or more attributes. These attributes may be any SQL data type, built-in or userdefined. • The standard mapping for the SQL type STRUCT is to a Struct object in the Java programming language. A Struct object contains a value for each attribute of the STRUCT value it represents. DISTINCT • The JDBC type DISTINCT represents the SQL3 type DISTINCT. • The standard mapping for a DISTINCT type is to the Java type to which the base type of a DISTINCT object would be mapped. For example, a DISTINCT type based on a CHAR would be mapped to a String object, and a DISTINCT type based on an SQL INTEGER would be mapped to an int. REF • The JDBC type REF represents an SQL3 type REF<structured type>. An SQL REF references (logically points to) an instance of an SQL structured type and is a unique identifier In the Java programming language, the interface Ref represents an SQL REF. • A REF is reference to SQL structured type and It is persistently stored with the instance it references in a special table on the server. An application can select the REF value from its special table and use it in place of the structured type instance it identifies. JAVA_OBJECT • The JDBC type JAVA_OBJECT, added in the JDBC 2.0 core API, makes it easier to use objects in the Java programming language as values in a database. • JAVA_OBJECT is simply a type code for an instance of a class defined in the Java programming language that is stored as a database object. • For DBMSs that support them, values of type JAVA_OBJECT are stored in a database table using the method PreparedStatement.setObject. They are retrieved with the methods ResultSet.getObject or CallableStatement.getObject and updated with the ResultSet.updateObject method. Examples of Mapping • This section presents three different scenarios, describing the data mapping and conversion required in each. Simple SQL Statement • In the most common case, a user executes a simple SQL statement and gets back a ResultSet object with the results. • The value returned by the database and stored in a ResultSet column will have a JDBC data type. • A call to a ResultSet.getXXX method will retrieve that value as a Java data type. • For example, if a ResultSet column contains a JDBC FLOAT value, the method getDouble will retrieve that value as a Java double. (A user who does not know the type of a ResultSet column can get that information by calling the method ResultSet.getMetaData and then invoking the ResultSetMetaData methods getColumnType or getColu mnTypeName.) • The following code fragment demonstrates getting the column type names for the columns in a result set: String query = "select * from Table1"; ResultSet rs = stmt.executeQuery(query); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); for (int i = 1; i <= columnCount; i++) { String s = rsmd.getColumnTypeName(i); System.out.println ("Column " + i + " is type " + s); } SQL Statement with IN Parameters • In another possible scenario, the user sends an SQL statement which takes input parameters. • In this case, the user calls the PreparedStatement.setXXX methods to assign a value to each input parameter. • For example, PreparedStatement.setLong(1, 2345678) will assign the value 2345678 to the first parameter as a Java long. The driver will convert 2345678 to a JDBC BIGINT in order to send it to the database. SQL Statement with INOUT Parameters • In another scenario, a user wants to call a stored procedure, assign values to its INOUT parameters, retrieve values from the results, and retrieve values from the parameters. • In this scenario, the first thing to do is to assign values to the INOUT parameters using CallableStatement.setXXX methods. • Each out parameter must be registered with driver by using the method CallableStatement.registerOutParameter, which takes one of the JDBC types defined in the class Types. • A programmer retrieves the results returned to a ResultSet object with ResultSet.getXXX methods and retrieves the values stored in the output parameters with CallableStatement.getXXX methods. Custom Mapping • The driver will use the custom mapping instead of the standard mapping when it converts a UDT(user defined Types) from a JDBC type to a Java type or vice versa. • All custom mapping is done using the connection’s type map • A type map is an instance of the java.util.Map interface, is associated with every new connection when it is created • a custom mapping is to make an entry of UDT in a type map. • With the methods ResultSet.getObject and CallableStatement.getObject, UDTs are retrieved from the database, and with PreparedSatement.setObject UDTs are sent back to the database. • When an application calls a getObject method to retrieve a UDT, the driver will check to see if the type map associated with the connection has an entry for the UDT • If there is a matching entry, the driver will use that type map to custom map the UDT , other wise the driver will use the standard mapping. Handling Errors • Any JDBC object encounters an error , it halt the execution and throws an SQLException. Ex: database connection errors , malformed SQL statements and insufficient database privileges etc. • The SQLException class extends the normal java.lang.Exception class and defines some additional methods like getSQLState()and getErrorCode() to provide additional information about an error. try { } catch(SQLException e) { System.out.println(“SQL Exception occurred”); System.out.println(e.getMessage()); System.out.println(e.getSQLState()); System.out.println(e.getErrorCode()); } SQL Warning • JDBC classes have the option of generating a SQLWarnings when something is not right • A warning is generated if, for example, you try to connect to a database with the create attribute set to true if the database already exists. Aggregates like sum() also raise a warning if NULL values are encountered during the evaluation. • SQLWarnings are rare, but provide information about the database access warnings • The following objects can receive a warning: – Connection – Statement (also, PreparedStatement, CallableStatement) – ResultSet • Warnings are retrieved by using the getWarnings() method • Call getWarning to obtain the warning object, and getNextWarning (on the warning object) for any additional warnings SQLWarning connectionWarning = connection.getWarnings(); SQLWarning statementWarning = statement.getWarnings(); SQLWarning resultsetWarning = resultSet.getWarnings(); The Interactive SQL Tool • The interactive SQL tool is a means of entering and executing SQL statements. • It will be a simple front end to the JDBC API. • It will provide a means of entering and executing SQL statements and at the same time display areas for viewing results. • The requirement for the Interactive SQL tool class is: to enable the user to enter and execute an SQL command to display the ResultSet from an SQL query to display the error information where appropriate. • This can be implement as an application with a window based by using swing class JFrame and a swing component called JTable. • The JTable calss is defined in the javax.swing.table package • The ResultSet is generated as table of data values, so JTable component is ideal for displaying ResultSet. TableModel Interface • To display a rectangular array of data on the screen, we can use JTable component. • The TableModel interface declares methods that are used by a JTable object to access the data item to be displayed at each position in the table. • This interface is defined in the javax.swing.table package, along with the JTable class. • The class which encapsulating a ResultSet need to implement this interface. • The TableModel interface enables a Java Swing application to manage data in a JTable object. class ResultsModel extends AbstractTableModel { public void setResultSet(ResultSet rs){ } public int getColumnCount() {} pubic int getRowCount() { } public String getColumnName(int column){ } public String getValueAt(int row, int column) { } } public int getColumnCount() { return columns.length; } pubic int getRowcount() { return RowData == null ? 0 : RowData.size(); } public String getValueAt(int row,int column) { return RowData.elementAt(row)[column]; } public String getColumnName(int column) { return columns[column] = = null ? “No Name” : columns[column]; } Vector<String[]> RowData = new Vector<String[]>(); // To store the contents of a row as an array of string objects public void setResultset(ResultSet rs) { try { ResultSetMetaData rsmt = rs.getMetaData(); int cols = rsmt.getColumnCount(); columns = new String[cols]; for(int i=0; i<cols; i++) { columns[i]=rsmt.getColumnLabel(i+1); } RowData.clear(); while(rs.next()) { rowdata = new String[cols]; for(int i=0;i<cols;i++) { rowdata[i] = rs.getString(i+1); } RowData.addElement(rowdata); } fireTableChanged(null); /* It notifies all listeners for JTable object that the mode has changed, so that JTable object should redraw from the scratch */ } catch(SQLException e){ System.out.println(e); } }