PART II Building Three-Tier Client–Server Applications 555 Chapter 8 Developing Java Web Applications to Access Databases 557
3.3 HOW DOES JDBC WORK?
As we mentioned in the last section, the JDBC API has three functions: (1) setup a con- nection between your Java application and your database; (2) build and execute SQL statements; and (3) process results. We will discuss these functions in more details in this section based on the JDBC architecture shown in Figure 3.1 .
3.3.1 Establish a Connection
JDBC Driver class contains six methods, and one of the most important methods is the
connect() method, which is used to connect to the database. When using this Driver class, a point to be noted is that most methods defi ned in the Driver class never be called directly; instead, they should be called via the DriverManager class methods.
3.3.1.1 Using D river M anager to Establish a Connection
The DriverManager class is a set of utility functions that work with the Driver methods together and manage multiple JDBC drivers by keeping them as a list of drivers loaded.
Although loading a driver and registering a driver are two steps, only one method call is necessary to perform these two operations. The operational sequence of loading and registering a JDBC driver is:
1. Call class methods in the DriverManager class to load the driver into the Java interpreter.
2. Register the driver using the registerDriver() method.
When loaded, the driver will execute the DriverManager.registerDriver() method to register itself. The above two operations will never be performed until a method in the DriverManager is executed, which means that even both operations have been coded in an application; however, the driver cannot be loaded and registered until a method such as connect() is fi rst executed.
To load and register a JDBC driver, two popular methods can be used:
1. Use Class.forName() method:
Class.forName(“com.microsoft.sqlserver.jdbc.SQLServerDriver”);
2. Create a new instance of the Driver class: Driver sqlDriver = new com.microsoft.
sqlserver.jdbc.SQLServerDriver;
Relatively speaking, the fi rst method is more professional, since the driver is both loaded and registered when a valid method in the DriverManager class is executed. The second method cannot guarantee that the driver has been registered by using the DriverManager.
3.3.1.2 Using D ata S ource Object to Establish a Connection
Another and better way to establish a connection is to use the DataSouce object.
The DataSource interface, introduced in the JDBC 2.0 Standard Extension API, is a better way to connect to a data source to perform data actions. In JDBC, a data source is a class that implements the interface javax.sql.DataSource to connect to more than one desired databases. The getConnection() method is always used to setup this connection.
A DataSource object is normally registered with a JNDI naming service. This means that an application can retrieve a DataSource object by name from the naming service independently of the system confi guration.
Perform the following three operations to deploy a DataSource object:
1. Create an instance of the DataSource class 2. Set its properties using setter methods 3. Register it with a JNDI naming service
After a valid connection has been setup using the DataSource object, one can use any data query methods listed in Tables 3.3 and 3.4 to perform data actions against the desired database.
Table 3.3. The function of three SQL statements execution methods
Method Function
executeQuery() This method performs data query and returns a ResultSet object that contains the queried results
executeUpdate() This method does not perform data query, instead it only performs either a data updating, insertion, or deleting action against the database and returns an integer that equals to the number of rows that have been successfully updated, inserted, or deleted
execute() This method is a special method, and it can be used either way. All different data actions can be performed by using this method, such as data query, data insertion, data updating, and data deleting. The most important difference between the execute() method and two above methods is that this method can be used to execute some SQL statements that are unknown at the compile time or return multiple results from stored procedures. Another difference is that the execute() method does not return any result itself, and one needs to use getResultSet() or
getUpdateCount() method to pick up the results. Both methods belong to the Statement class
c03.indd 93
c03.indd 93 7/20/2011 2:11:49 PM7/20/2011 2:11:49 PM
www.traintelco.com
3.3.2 Build and Execute SQL Statements
Once a valid connection is established and a Connection object is created, the JDBC driver is responsible for ensuring that an application has consistent and uniform access to any database. It is also responsible for ensuring that any requests made the application are presented to the database in a way that can be recognized by the database.
To build a SQL statement, one needs to call the method createStatement() that belongs to the Connection class to create a new Statement object. Regularly, there are three type of Statement objects widely implemented in the JDBC API: Statement, PreparedStatement, and CallableStatement. The relationship among these three classes is: the PreparedStatement and CallableStatement classes are the subclasses of the Statement class.
To execute a SQL statement, one of the following three methods can be called:
1. executeQuery() 2. executeUpdate() 3. execute()
All of these methods belong to the Statement and the PreparedStatement classes and used to access database to perform different data actions.
The differences between these three methods are dependents on the different data operations and actions. Table 3.3 lists the function for each method and the situation under which the appropriate method should be utilized. Mode - detailed discussion about these three methods and their implementations can be found in Section 6.4.2.3 in Chapter 6 .
3.3.3 Process Results
After the desired SQL statement is executed, you need to retrieve the execution results.
Depends on the different execution methods you called, you need to use the different methods to pick up the results.
Table 3.4 lists some necessary methods used to pick up the appropriate results based on the different execution methods utilized.
Table 3.4. The desired method used to pick up the SQL execution results
Execution Method Picking up Method
executeQuery() getResultSet(), getXXX(), where XXX equals to the desired data type of returned result
executeUpdate() getUpdateCount()
This method will returns an integer that equals to the number of rows that have been successfully updated, inserted, or deleted
execute() getResultSet(), getUpdateCount()
This method does not return any result itself, and one needs to use getResultSet() or getUpdateCount() method to pick up the results. Both methods belong to the Statement class
3.3.3.1 Using R esult S et Object
A ResultSet object will be created after the executeQuery() method is executed or a
getResultSet() method is executed. A ResultSet object is a data structure that pres- ents rows and columns returned by a valid query. It maintains a cursor pointing to its current row of data. Initially, the cursor is positioned before the fi rst row. One can use the next() method to move the cursor to the next row, and continue this moving one can scan the entire ResultSet. With a loop, one can use the appropriate getXXX() method of the ResultSet class to pick up each row in the ResultSet object. The XXX indicates the corresponding Java data type of the selected row. A more detailed discussion about these methods will be provided in Chapter 4 .
3.3.3.2 Using R ow S et Object
A RowSet object contains a set of rows from a result set or some other source of tabular data, like a fi le or spreadsheet. Because a RowSet object follows the JavaBeans model for properties and event notifi cation, it is a JavaBeans component that can be combined with other components in an application. As is compatible with other Beans, application developers can probably use a development tool to create a RowSet object and set its properties.
RowSets may have many different implementations to fi ll different needs. These implementations fall into two broad categories, connected and disconnected:
1. A connected RowSet is equivalent to a ResultSet, and it maintains a connection to a data source as long as the RowSet is in use.
2. A disconnected RowSet works as a DataSet in Visual Studio.NET, and it can connect to a data source to perform the data updating periodically. Most time, it is disconnected with the data source and uses a mapping memory space as a mapped database.
While a RowSet is disconnected, it does not need a JDBC driver or the full JDBC API, so its footprint is very small. Thus, a RowSet is an ideal format for sending data over a network to a thin client.
Because it is not continually connected to its data source, a disconnected RowSet stores its data in memory. It needs to maintain metadata about the columns it contains and information about its internal state. It also needs a facility for making connections, for executing commands, and for reading and writing data to and from the data source.
A connected RowSet, by contrast, opens a connection and keeps it open for as long as the RowSet is being used.
A more detailed discussion about the RowSet object and its implementation will be given in Sections 6.4.6.1 and 6.4.6.2 in Chapter 6 .
Since the JDBC driver is a core for entire JDBC API, we will have a more detailed discussion about this component in the next section.