• Tidak ada hasil yang ditemukan

Simple Database Access

Java Database Connectivity (JDBC)

7.4 Simple Database Access

In what follows, reference will be made to Connection , Statement and ResultSet objects. These three names actually refer to interfaces , rather than classes. Each JDBC driver must implement these three interfaces and the implementation classes may then be used to create objects that may conveniently be referred to as Connection , Statement and ResultSet objects respectively. Similar comments apply to interfaces ResultSetMetaData and DatabaseMetaData in Sect. 7.7 . From now on, such terminology will be used freely and this point will not be laboured any further.

Using JDBC 4 to access a database requires several steps, as described below.

1. Establish a connection to the database.

2. Use the connection to create a Statement object and store a reference to this object.

3. Use the above Statement reference to run a specifi c query or update statement and accept the result(s).

4. Manipulate and display the results (if a query) or check/show number of database rows affected (for an update).

5. Repeat steps 4 and 5 as many times as required for further queries/updates.

6. Close the connection.

[If using an earlier version of JDBC, the following additional step is required before those above: Load the database driver. ]

For purposes of illustration, we shall assume the existence of an MS Access database called Finances.accdb that holds a single table called Accounts . The structure of this simple table is as shown below.

Field name MS access type Java type

acctNum Number int

surname Text String

fi rstNames Text String balance Currency fl oat

We shall further assume that the DSN given to the database is Finances . Let’s take each of the above seven steps in turn for this database…

1. Establish a Connection to the Database

We declare a Connection reference and call static method getConnection of class DriverManager to return a Connection object for this reference. Method get- Connection takes three String arguments:

• a URL-style address for the database;

• a user name;

• a password.

The JDBC API specifi cation recommends that the database address have the following format:

jdbc:<sub-protocol>:<data-source>

Here, <sub-protocol> specifi es a database connection service (i.e., a driver ) and <data-source> provides all the information needed by the service to locate the database (typically, the URL path to the database). For a local ODBC database with data source name Finances , the sub-protocol is odbc and the fi nal part of the address is simply the name of the data source:

jdbc:odbc:Finances

Assuming that our Finances database is indeed local and that we did not set a user name or password for this database, the line required to open a connection to the database would be similar to this:

Connection connection =

DriverManager.getConnection(

"jdbc:odbc:Finances", "", "");

If this same database were remote, then the above line would look something like this:

Connection connection =

DriverManager.getConnection(

"jdbc:odbc://AnyServer.SomethingElse.com/Finances", "", "");

However, the API-specifi ed syntax is only a recommendation and database vendors are free to ignore this if they wish. Consequently, some drivers may specify sub-protocols and data sources with syntax that is different from that shown above.

It is up to the DriverManager to query each loaded driver in turn to determine whether the driver recognises the type of database that is being addressed.

2. Create a Statement Object and Store Its Reference

A Statement object is created by calling the createStatement method of our Connection object (whose reference was saved in variable link in the previous step).

The address of the object returned by this call to createStatement is saved in a Statement reference. In the line below, this reference is simply called statement .

Statement statement = connection.createStatement();

3. Run a Query or Update and Accept the Result(s)

DML (Data Manipulation Language) statements in SQL may be divided into two categories: those that retrieve data from a database (i.e., SELECT statements) and those that change the contents of the database in some way (viz., INSERT, DELETE and UPDATE statements). Class Statement has methods executeQuery and execute- Update that are used to execute these two categories respectively. The former method returns a ResultSet object, while the latter returns an integer that indicates the number of database rows that have been affected by the updating operation.

(We shall postpone consideration of method executeUpdate until the next section.) It is common practice to store the SQL query in a String variable and then invoke executeQuery with this string as an argument, in order to avoid a rather cumbersome invocation line. This practice has been followed in the examples below.

Examples

(i) String selectAll = "SELECT * FROM Accounts";

ResultSet results =

statement.executeQuery(selectAll);

(ii) String selectFields =

"SELECT acctNum, balance FROM Accounts";

ResultSet results =

statement.executeQuery(selectFields);

(iii) String selectRange = "SELECT * FROM Accounts"

+ " WHERE balance >= 0"

+ " AND balance <= 1000"

+ " ORDER BY balance DESC";

ResultSet results =

statement.executeQuery(selectRange);

(iv) String selectNames =

"SELECT * FROM Accounts WHERE surname < Jones'";

ResultSet results =

statement.executeQuery(selectNames);

Note the need for inverted commas around any string literals! (Speech marks cannot be used, of course, since the opening of speech marks for a string within an SQL query would be interpreted by the compiler as the closing of the query.) Inverted commas are not required for numbers, but no error is generated if they are used.

4. Manipulate/Display/Check Result(s)

The ResultSet object returned in response to a call of executeQuery contains the database rows that satisfy the query’s search criteria. The ResultSet interface contains a very large number of methods for manipulating these rows, but the majority of these will not be discussed here. [see Sect. 7.9 for coverage of some of the other methods.] The only method that we need to make use of at present is next , which moves the ResultSet cursor/pointer to the next row in the set of rows referred to by that object.

Having moved to the particular row of interest via any of the above methods, we can retrieve data via either the fi eld name or the fi eld position. In doing so, we must use the appropriate getXXX method (where ‘XXX’ is replaced by the appropriate Java type).

Examples

• int getInt(String <columnName>)

• int getInt(int <columnIndex>)

• String getString(String <columnName>)

• String getString(int <columnIndex>)

Similar methods exist for the other types, in particular getFloat , getLong and getDate . Note that the last of these is a method of class java.sql.Date, not of class java.util.Date . The latter is, in fact, a subclass of the former. Note also that the number of a fi eld is its position within a ResultSet row , not its position within a database row. Of course, if all fi elds of the database table have been selected by the query, then these two will be the same. However, if only a subset of the fi elds has been selected, they will not necessarily be the same!

Initially, the ResultSet cursor/pointer is positioned before the fi rst row of the query results, so method next must be called before attempting to access the results.

Such rows are commonly processed via a while loop that checks the Boolean return value of this method fi rst (to determine whether there is any data at the selected position).

Example

String select = "SELECT * FROM Accounts";

ResultSet results =

statement.executeQuery(select);

while (results.next()) {

System.out.println("Account no."

+ results.getInt(1));

System.out.println("Account holder: "

+ results.getString(3) + " "

+ results.getString(2));

System.out.println("Balance: "

+ results.getFloat(4));

System.out.println ();

}

N.B. Column/fi eld numbers start at 1 , not 0!

Alternatively, column/fi eld names can be used. For example:

System.out.println("Account no."

+ results.getInt("acctNum");

5. Repeat Steps 3 and 4, as Required

The Statement reference may be used to execute other queries (and updates).

6. Close the Connection

This is achieved by calling method close of our Connection object and should be carried out as soon as the processing of the database has fi nished. For example:

connection.close();

Statement objects may also be closed explicitly via the identically-named method of our Statement object. For example:

statement.close();

[Note: If using a version of JDBC that precedes version 4, then it will be necessary to load the JDBC driver explicitly before any of the six steps above are executed.

This is done via static method forName of class Class (!):

E.g., Class.forName("<Driver name>"); ]

We are now almost ready to write our fi rst database access program in Java.

Before we do, though, there is one last issue to consider: exception-handling.

Any of our SQL statements may generate an SQLException , which is a checked exception, so we must either handle such an exception or throw it.

Now let’s bring everything together into a program that simply accesses our Finances database and displays the full contents of the Accounts table. In order to make use of JDBC (without cumbersome package references), of course, our program should import java.sql . In what follows, the lines corresponding to the above six steps have been commented to indicate the relevant step numbers.

Example

import java.sql.*;

public class JDBCSelect {

public static void main(String[] args) {

Connection connection = null;

Statement statement = null;

ResultSet results = null;

try {

//Step 1…

connection = DriverManager.getConnection(

"jdbc:odbc:Finances","","");

}

//For any of a number of reasons, it may not be //possible to establish a connection…

catch(SQLException sqlEx) {

System.out.println(

"* Cannot connect to database! *");

System.exit(1);

} try {

//Step 2…

statement = connection.createStatement();

String select = "SELECT * FROM Accounts";

//Step 3…

results = statement.executeQuery(select);

}

catch(SQLException sqlEx) {

System.out.println(

"* Cannot execute query! *");

sqlEx.printStackTrace();

System.exit(1);

}