CIS 6930-01 – Fall 2000

Post on 21-Jan-2016

46 views 0 download

description

Part 5: JDBC Tutorial. CIS 6930-01 – Fall 2000. http://aspen.csit.fsu.edu/it1fall00 Instructors: Geoffrey Fox , Bryan Carpenter Computational Science and Information Technology Florida State University Acknowledgements: Nancy McCracken Syracuse University. Introduction. - PowerPoint PPT Presentation

Transcript of CIS 6930-01 – Fall 2000

dbc@csit.fsu.edu 1

CIS 6930-01 – Fall 2000

http://aspen.csit.fsu.edu/it1fall00

Instructors: Geoffrey Fox , Bryan CarpenterComputational Science and Information

TechnologyFlorida State University

Acknowledgements: Nancy McCrackenSyracuse University

Part 5: JDBC Tutorial

dbc@csit.fsu.edu 2

Introduction

JDBC—usually interpreted as an acronym for Java Database Connectivity—was introduced in 1996, and revamped in 1998 for Java 2.

It is an API definition intended for implementation as a Java interface to an SQL database.

SQL (“sequel”) is the Structured Query Language, originally defined by IBM in the 70’s, standardized by ANSI/ISO in 1992.

SQL is in turn based on the relational database model. It is implemented (with much variation) by many vendors of RDBMS (Relational Database Management System) software.

First commercial implementation of SQL: Oracle, 1979.

dbc@csit.fsu.edu 3

SQL

dbc@csit.fsu.edu 4

Relations Mathematically, a relation is a subset of a product space.

Equivalently, it is a set of “tuples” with entries from some fixed domains.

In mathematics, the most important relations tend to be binary relations between entities of the same type:LessThan, on {0, 1, 2, 3} {0, 1, 2, 3}:

{ (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3) }

Contains, on {sunder, sun, sundry, dry} {sunder, sun, sundry, dry}:

{ (sunder, sunder), (sunder, sun), (sun, sun), (sundry, sundry), (sundry, sun), (sundry, dry), (dry,

dry) }

SameColor, on {tomato, cherry, banana} {tomato, cherry, banana}:

{ (tomato, tomato), (tomato, cherry), (cherry, tomato), (cherry, cherry), (banana, banana) }

Examples respectively of total order, partial order and equivalence relation.

dbc@csit.fsu.edu 5

General Relations

For databases, we are nearly always interested in n-ary relations between distinct domains, e.g. assume:

Login = {wcao, Flora, Fulay, zyr98210, jin0328}

LastName = {Cao, Flora, Fulay, Zhang} Dept = {CSIT, EE, CS}

then we may define the relation:

Students, on Login LastName Dept : { (wcao, Cao, CSIT), (Flora, Flora, EE ), (Fulay, Fulay, CS ), (zyr98210, Zhang, CS ), (jin0328, Zhang, CS ) }

dbc@csit.fsu.edu 6

SQL Tables

SQL is inspired by this mathematical model. Names are changed, and for pragmatic reasons

the SQL model does not try to be mathematically pure.

A relation is replaced by a table. The individual tuples in the relation are called

rows. The domain sets of the relation are replaced by

columns or attributes. Typing is not as strict as the mathematical

model suggests. We define the allowed values of a column in terms of a limited set of predefined types, rather than actual sets.

dbc@csit.fsu.edu 7

Creating a Table

A possible SQL command to create a table for our Students relation is: CREATE TABLE students ( login VARCHAR(10), lastname VARCHAR(20), dept VARCHAR(5) )

Things to note:– Case is not significant here. By convention we use

upper case for SQL keywords.– White-space, including line-breaks, is not significant.– The CREATE TABLE statement is syntactically like a

class definition, defining columns (c.f. fields) and their types.

– In this analogy, rows of the table would be like class instances.

dbc@csit.fsu.edu 8

Column Types

There are a limited set of types for column data.

Unfortunately (although there is supposed to be a standard) in practice the available types are completely dependent on the vendor.

In JDBC the types are standardized and include:

INTEGER Typically 32-bit integer.

FLOAT(N) Floating point with N bits of precision.

CHARACTER(N) Fixed length string, N characters.

VARCHAR(N) Variable length string, maximum N.

BLOB A large binary object.

dbc@csit.fsu.edu 9

SQL*Plus

To create a table using the Oracle SQL*Plus interpreter, type the sqlplus command and enter your Oracle account name and password, then:

SQL> create table students ( 2 login varchar(10), 3 lastname varchar(20), 4 dept varchar(5) 5 ) ; Table created

In this interpreter commands are terminated by a semicolon.

dbc@csit.fsu.edu 10

Inserting a Row

The SQL command for adding a row to a table is, e.g.:

INSERT INTO students VALUES (‘wcao’, ‘Cao’, ‘CSIT’)

In sqlplus I enter:

SQL> insert into students values ( 2 ‘wcao’, 3 ‘Cao’, 4 ‘CSIT’) ; 1 row created.

The following examples assume the other tuples from the Student relation are entered in the same way.

dbc@csit.fsu.edu 11

The SELECT command

To view the Students table I can use the SELECT command: SELECT * FROM students

The asterisk is a wildcard that causes all columns to be display.

In sqlplus:

SQL> select * from students ; LOGIN LASTNAME DEPT ----------------- ----------------------------- ------------ wcao Cao CSIT Flora Flora EE Fulay Fulay CS zyr98210 Zhang CS jin0328 Zhang CS 5 rows selected

dbc@csit.fsu.edu 12

Displaying Chosen Columns

To limit the set of columns printed, specify them in the SELECT command, e.g.: SELECT login, lastname FROM

students

In sqlplus:

SQL> select login, lastname from students ;

LOGIN LASTNAME ----------------- ----------------------------- wcao Cao Flora Flora Fulay Fulay zyr98210 Zhang jin0328 Zhang 5 rows selected

dbc@csit.fsu.edu 13

Displaying Chosen Rows

To limit the set of rows printed, I add a WHERE clause: SELECT * FROM students WHERE dept=‘CS’

Other kinds of tests that can appear in the WHERE clause will be described later.

In sqlplus:

SQL> select * from students where dept=‘CS’ ; LOGIN LASTNAME DEPT ----------------- ----------------------------- ------------ Fulay Fulay CS zyr98210 Zhang CS jin0328 Zhang CS 3 rows selected

dbc@csit.fsu.edu 14

A Second Table

The following examples assume I define a second table by: CREATE TABLE departments ( abbrev VARCHAR(5), name VARCHAR(50) )

and add the rows:

{ (‘CSIT’, ‘Computational Science and Information Technology’),

(‘EE’, ‘Electrical Engineering’), (‘CS’, ‘Computer Science’) }

dbc@csit.fsu.edu 15

Selecting from Multiple Tables A SELECT command can display data from more

than one tables: SELECT * FROM students, departments

By itself this just produces a mess. In sqlplus:SQL> select * from students, departments ;

LOGIN LASTNAME DEPT ABBRE----------------- ----------------------------- ------------

---------- NAME-------------------------------------------------------------------- wcao Cao CSIT CSITComputational Science and Information TechnologyFlora Flora EE

CSITComputational Science and Information TechnologyFulay Fulay CS CSITComputational Science and Information Technology. . .15 rows selected

dbc@csit.fsu.edu 16

Joins

The previous query returned 15 rows. It simply yielded a “Cartesian product” of the

two relations, with every row of students being combined with every row of departments.

In itself this is not a useful result. But is a basis from which to add a WHERE clause to select out some meaningful combinations of values from the two tables.

If two tables appearing in the same statement share some identical column names, can disambiguate by using qualified names, e.g.: students.login, students.lastname, students.dept,

etc.

dbc@csit.fsu.edu 17

References Between Tables

Here is a meaningful query involving the two tables: SELECT login, name FROM students, departments WHERE dept=abbrev

In sqlplus:

SQL> select login, name from students, departments 2 where dept=abbrev ;

LOGIN NAME-----------------

--------------------------------------------------------------------------Fulay Computer Sciencezyr98210 Computer Sciencejin0328 Computer Sciencewcao Computational Science and Information

TechnologyFlora Electrical Engineering5 rows selected

dbc@csit.fsu.edu 18

Primary Keys and Foreign Keys

This kind of cross-reference is so important that SQL provides syntax to allow automatic “integrity checks” and allow optimizations.

We can change the abbrev column to be a primary key of the departments table by the following SQL command:

ALTER TABLE departments ADD PRIMARY KEY (abbrev)

We add a constraint that any allowed value in the dept column of students must be a valid primary key in the departments table by the SQL command:

ALTER TABLE students ADD FOREIGN KEY (dept) REFERENCES departments (abbrev)

dbc@csit.fsu.edu 19

Integrity Checks

The system will now forbid addition of values to the dept column of students that do not correspond to values in the abbrev column of departments.

For example, I can try to change the dept column of the row describing wcao by the SQL UPDATE command: UPDATE students SET dept=‘IE’ WHERE login=‘wcao’

Because of the constraints, Oracle will refuse to make this update. In sqlplus:

SQL> update students set dept=‘IE’ where login=‘wcao’ ;ERROR at line 1 :ORA-02291: integrity constraint violated - parent key not

found.

Incidentally this example illustrates the use of UPDATE command, which changes attributes of existing rows.

dbc@csit.fsu.edu 20

Other Useful Commands

. . . in addition to CREATE, SELECT and UPDATE, which were illustrated earlier:DELETE FROM table_name WHERE conditionDeletes selected rows.

DROP TABLE table_nameRemoves a table.

DESCRIBE table_nameDescribes columns of a table.

COMMITSave changes made in this transaction.

ROLLBACKUndo changes made in this transaction.

dbc@csit.fsu.edu 21

Conditions

Conditions in WHERE clauses are Boolean expressions built from:– Comparision operators =, <>, <, <=, >, >=– Boolean operators AND, OR, NOT– The LIKE operator.

The LIKE operator compares a column value to a pattern.– In the pattern the wildcard % represents zero or more

characters.– The wildcard _ represents a single character.

dbc@csit.fsu.edu 22

JDBC

dbc@csit.fsu.edu 23

A Simple Exampleimport java.sql.* ;public class ShowStudents { public static void main(String args[]) throws Exception { System.setProperty(“jdbc.drivers”, “oracle.jdbc.driver.OracleDriver”) ;

String url = “jdbc:oracle:thin:@sirah.csit.fsu.edu:1521:oralin” ;

Connection conn = DriverManager.getConnection(url, “dbc”, “ . . . ”) ;

Statement stat = conn.createStatement() ;

ResultSet rs = stat.executeQuery(“SELECT * FROM students”) ;

while(rs.next()) System.out.println(rs.getString(1) + “ ” + rs.getString(2) + “ ” +

rs.getString(3)) ; conn.close() ; }}

dbc@csit.fsu.edu 24

Remarks

To compile and run this example you must have the JDBC driver code on your class path.

On the course hosts, add /usr/oracle/jdbc/lib/classes111.zip

to your CLASSPATH. For example you might add the line export CLASSPATH=$CLASSPATH:\ $ORACLE_HOME/jdbc/lib/classes111.zip

to the end of you .bashrc file.

dbc@csit.fsu.edu 25

Running ShowStudents

If we run ShowStudents we may see something like: sirah$ java ShowStudents wcao Cao CSIT Flora Flora EE Fulay Fulay CS zyr98210 Zhang CS jin0328 Zhang CS

Effect is essentially like typing the command

select * from students ;

directly into the SQL*Plus interpreter.

dbc@csit.fsu.edu 26

Classes in the Example The example introduces the following classes and

interfaces from java.sql:DriverManager Manages a set of JDBC drivers.

Connection A connection or session with a specific database.

Context in which SQL statements are executed and results returned.

Statement Object used for executing an SQL statement.

ResultSet Provides access to a table of data generated by

executing a statement.

dbc@csit.fsu.edu 27

The Driver Manager

The driver manager sits between the JDBC application and one or more JDBC drivers.

A JDBC driver contains vendor-specific code to interface to a particular back-end database.

On initialization, the class DriverManager will try to load driver classes referenced in the jdbc.drivers property.

One can also load JDBC drivers explicitly, e.g.:

Class.forName(“oracle.jdbc.driver.OracleDriver”) ;

dbc@csit.fsu.edu 28

Making a Connection

There are several getConnection() methods on DriverManager with different argument lists. The one we will use is:

static Connection getConnection(String url, String

username, String

password)

Before you can use this method, you will, of course, need an account on the database concerned.– The username and password are associated with the

database (not your UNIX account!)

dbc@csit.fsu.edu 29

Database URLs

Ideally the syntax of the URL would follow the normal conventions for Internet URLs:

protocol // host : port / name

– protocol will be a sub-protocol of jdbc:, e.g.

jdbc:oracle:thin:– host and port are self-explanatory.– name is the name of the database on the host.

Oracle JDBC URLs follow this general pattern, but they use different separators.– @ and : in place of // and /.

dbc@csit.fsu.edu 30

The Connection Interface The Connection interface includes many

methods. Our first example only uses two simple ones:

Statement createStatement() Creates a Statement object for sending SQL

statements to the database.

void close() Releases database connection and associated JDBC

resources.

dbc@csit.fsu.edu 31

The Statement Interface Object used for executing an SQL statement. The most important methods for us will be:

ResultSet executeQuery(String sql) throws SQLException

Executes an SQL statement that returns a single result set. Typically sql will be a SELECT statement.

int executeUpdate(String sql) throws SQLException Executes an SQL statement that returns nothing.

Typically sql will be an INSERT, UPDATE or DELETE statement. Result is number rows modified.

Note only one ResultSet can exist per Statement. If you need to interleave queries, use multiple Statement objects.

Other useful methods:– addBatch(), executeBatch() to batch several SQL

commands.

dbc@csit.fsu.edu 32

The ResultSet Interface

A result set behaves something like an Enumeration or Iterator. This allows to iterate over the set of rows returned by a query.

The next() method is used to move to the first row, then all subsequent rows.

There is a large number of methods of the form: XXX getXXX(int columnIndex)

that extract the contents of a column in the current row.

The one we will use most is getString(), which interprets the column as a String.

Note columnIndex starts at 1, not zero. ResultSet has many other methods. Many were

added in JDBC 2.0.

dbc@csit.fsu.edu 33

Example: Web Front End to SQL

Will now go through a fairly substantial example that combines JDBC with servlets.

This Web application will allow a user to connect to an Oracle account on the server host, and submit arbitrary SQL commands and queries.

Besides introducing a couple of new JDBC features, it will illustrate (in more depth than the vending machine examples) the structure of a Web application involving multiple servlets.

dbc@csit.fsu.edu 34

A First Screen

The introductory screen to our application is a static HTML form, sqlconnect.html:<html><head> . . . </head><body><h1>Connect to Oracle database</h1><form method=post action=“/dbc/servlet/SQLConnect”> Oracle user name: <input type=text name=username

size=20> <p> Oracle password: <input type=password name=password

size=20> <p> <input type=submit value=“Connect to database”></form></body></html>

dbc@csit.fsu.edu 35

Remarks

The form prompts for Oracle user name and password.

These are sent using the POST method (for privacy) to the servlet SQLConnect.

Note the form of the action URL. This is a URL to a the servlet context /dbc in the same Web server.

dbc@csit.fsu.edu 36

The SQLConnect servletpublic class SQLConnect extends HttpServlet { . . . public void doPost(HttpServletRequest req, HttpServletResponse resp) throws . . . { try { String username = req.getParameter(“username”) ; String password = req.getParameter(“password”) ; HttpSession session = req.getSession(true) ; Connection conn = DriverManager.getConnection(url, username,

password) ; session.setAttribute(“connection”, conn) ; resp.sendRedirect(

resp.encodeRedirectURL(“/dbc/servlet/SQLCommand”)) ; } catch (SQLException e) { . . . make suitable sendError() call . . . } }}

dbc@csit.fsu.edu 37

Remarks

The essential code creates a servlet session, connects to the database, and stores the Connection object in the servlet session.

This done, the browser is redirected to the SQLCommand servlet.

encodeRedirectURL() is similar to encodeURL(), but specifically intended for use with a sendRedirect() .

We assume that the driver is loaded by a suitable init() method, e.g.:public void init() { Class.forName(“oracle.jdbc.driver.OracleDriver”) ;}

and the URL for the database is predefined in a static variable url.

dbc@csit.fsu.edu 38

The SQLCommand servletpublic class SQLCommand extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp)

throws . . . { HttpSession session = req.getSession(true) ; Connection conn = (Connection)

session.getAttribute(“connection”) ; if(conn == null) . . . session probably timed out: call sendError() . . . else { resp.setContentType(“text/html”) ; PrintWriter out = resp.getWriter() ; out.println(“<html><head></head><body>”) ; . . . print forms . . . out.println(“</body></html>”) ; } }}

dbc@csit.fsu.edu 39

Remarks

The connection is retrieved from the current session, if it exists.

Otherwise the servlet just prints three forms, for SQL queries, SQL action commands, and disconnecting, respectively. . .

dbc@csit.fsu.edu 40

Printing the Formsout.println("<form action=" + resp.encodeURL("/dbc/servlet/SQLQuery") + ">") ;out.println("<h1>SQL <em>query</em></h1>") ;out.println("<textarea name=query cols=60

rows=3></textarea><p>") ;out.println("<input type=submit value=\"Submit Query\">") ;out.println("</form>");

out.println("<form action=" + resp.encodeURL("/dbc/servlet/SQLUpdate") + ">") ;out.println("<h1>SQL <em>update</em></h1>") ;out.println("<textarea name=update cols=60

rows=3></textarea><p>") ;out.println("<input type=submit value=\"Submit Update\">") ;out.println("</form>");

out.println("<form action=" + resp.encodeURL("/dbc/servlet/SQLClose") + ">") ;out.println("Close Oracle Connection:") ;out.println("<input type=submit value=\"Close\">") ;out.println("</form>");

dbc@csit.fsu.edu 41

Handling Queries

The most complicated servlet in our application is SQLQuery.

This will execute an arbitrary SELECT command, and print out the results as an HTML table.

This presents some special problems because we don’t know in advance how many columns the result table will need, or what is the meaning of the entries.

We can cope with this kind of situation using result set metadata.

dbc@csit.fsu.edu 42

Result Set Metadata

The ResultSet class has a method: ResultSetMetaData getMetaData()

that returns a metadata object describing the results.

The only methods on ResultSetMetaData we will use here are:int getColumnCount() returns the number of columns in the result set.

String getColumnLabel(int columnIndex) returns a suggested label for use in printouts.

dbc@csit.fsu.edu 43

The SQLQuery servletpublic class SQLQuery extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp)

throws . . . { HttpSession session = req.getSession(true) ; Connection conn = (Connection)

session.getAttribute(“connection”) ; if(conn == null) . . . session probably timed out: call sendError() . . . else { String query = req.getParameter(“query”) ; try { Statement stat = conn.createStatement() ; ResultSet rs = stat.executeQuery(query) ; . . . generate response . . . } catch (SQLException e) { . . . make suitable sendError() call . . . } } }}

dbc@csit.fsu.edu 44

Remarks

This servlet gets the SQL query command from the form data, creates a Statement, and executes the query.

The non-trivial work is in generating the HTML response. . .

dbc@csit.fsu.edu 45

Generating the ResponseResultSetMetaData rsmd = rs.getMetaData() ;int cols = rsmd.getColumnCount() ;. . . set response content type, print HTML headers . . .out.println("<table border cellspacing=0 cellpadding=5>") ;

out.println("<tr bgcolor=lightblue>") ; // print column headers

for(int i = 1 ; i <= cols ; i++) out.println("<td>" + rsmd.getColumnLabel(i) + "</td>")

;out.println("</tr>") ;

while(rs.next()) { // print the rows out.println("<tr>") ; for(int i = 1 ; i <= cols ; i++) out.println("<td>" + rs.getString(i) + "</td>") ; out.println("</tr>") ; }out.println("</table>") ;. . . print HTML footers . . .

dbc@csit.fsu.edu 46

Remarks

The complete code generates a couple of form buttons at the end of the HTML page, giving the option to submit another command (go back to the SQLCommand servlet) or close the connection (go to the SQLClose servlet).

dbc@csit.fsu.edu 47

Action Statements

The last two servlets are relatively simple.

SQLUpdate has a similar structure to SQLQuery but it reads the update parameter, and executes the command by: String update = req.getParameter(“update”)

; try { Statement stat =

conn.createStatement() ; int rows = stat.executeUpdate(update) ; . . . generate response . . . } catch (. . .) { . . .}

SQLClose calls conn.close() then redirects the browser back to the sqlconnect.html page.

dbc@csit.fsu.edu 48

Submitting a Command

dbc@csit.fsu.edu 49

The Response

dbc@csit.fsu.edu 50

An Elementary “3-tier” Application

dbc@csit.fsu.edu 51

A Student Database The application is highly simplified, but it

illustrates a form-based interface to an Oracle database on a server, with a servlet “middle-tier”.

It is more developed than the preceding SQL front-end—it doesn’t require the client to actually type SQL commands and interpret the results!

It uses session tracking to implement an “undo” feature for updates.

It also illustrates a new feature of the servlet session-tracking API—session binding listeners.

Otherwise it is quite limited:– It doesn’t include features to add or delete records, only

to modify existing records.– The user interface is not very pretty.

dbc@csit.fsu.edu 52

Creating the Table

As a preliminary, we need to create the initial state for database table.

This is a management task for our Web application—not part of the online functionality.

Nevertheless it is quite convenient to write a Java program to create the table.

dbc@csit.fsu.edu 53

Java “Script” to Create Tableclass MakeTable implements DBConstants { public static void main(String args[]) throws Exception { . . . Load driver . . . Connection conn = DriverManager.getConnection(url, username,

password); Statement stat = conn.createStatement(); stat.executeUpdate( "CREATE TABLE " + table + " (" + "login VARCHAR(10)," + "lastname VARCHAR(20)," + "firstnames VARCHAR(20)," + "email VARCHAR(50)," + "dept VARCHAR(5)" + ")" ) ; . . . Add entries to table . . . conn.close(); }}

dbc@csit.fsu.edu 54

Adding the Entries

BufferedReader in = new BufferedReader(new FileReader(table)) ;

String login, lastname, firstnames, email, dept ;login = in.readLine() ;while(login != null) { lastname = in.readLine() ; firstnames = in.readLine() ; email = in.readLine() ; dept = in.readLine() ; stat.executeUpdate( "INSERT INTO " + table + " VALUES ('" + login + "', '" + lastname + "', '" +

firstnames + "', " + "'" + email + "', '" + dept + "')" ) ; in.readLine() ; // skip blank line ; login = in.readLine() ;}

dbc@csit.fsu.edu 55

Remarks

This assumes the initial data is stored in a file having the same name as the table to be created.

Various constants associated with the database account and table are stored in the DBConstants interface, e.g.:

public interface DBConstants { static final String url =

“jdbc:oracle:thin:@sirah.csit.fsu.edu:1521:oralin” ;

static final String username = “dbc” ; static final String password = “ . . . ” ; static final String table = “it1fall00” ; }

dbc@csit.fsu.edu 56

The Servlets

This particular application consists of several servlets and associated classes.

We will collect them together into a new context in our Web server, under the path /students.

In conf/server.xml we add the lines:<Context path=“/students”

docBase=“webapps/students” debug=“0” reloadable=“true”></Context>

and create the associated document directories (see the lecture on configuring the Tomcat server).

dbc@csit.fsu.edu 57

Selection Page

The “main” page of our application offers a list of “keys” to select from—in our case student login IDs.

This page is generated by a servlet called Select.

This servlet checks session data is in order and retrieves or creates an object of auxiliary class DBSession, which we use to manage the database connection.

It extracts to column of login IDs from the table. Finally it generates the HTML for the displayed

page.

dbc@csit.fsu.edu 58

Overview of Select servlet

public class Select extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)

throws . . . { try { DBSession dbs ; . . . Initialize session, and extract dbs.

ResultSet rs = dbs.stat.executeQuery( "SELECT login FROM " + DBConstants.table ) ; . . . Generate response . . . } catch (SQLException e) { response.sendError(HttpServletResponse.SC_OK, "SQL error: " +

e.getMessage()) ; } }}

dbc@csit.fsu.edu 59

Initializing the Session

HttpSession session = request.getSession(true) ; dbs = (DBSession) session.getAttribute("dbs") ; if(dbs == null) { // Session new or

timed out dbs = new DBSession() ; session.setAttribute("dbs", dbs) ; session.setMaxInactiveInterval(300) ; // 5

minutes. }

We don’t want to accumulate many idle database connections, so we explicitly set a relatively short time-out interval for the session.

The DBSession constructor creates a database connection. The object then stores the Connection object and a reusable Statement object.

dbc@csit.fsu.edu 60

The DBSession classpublic class DBSession implements HttpSessionBindingListener, DBConstants { static { Class.forName("oracle.jdbc.driver.OracleDriver") ; }

DBSession() throws SQLException { conn = DriverManager.getConnection(url, username,

password); stat = conn.createStatement(); } public void valueBound(HttpSessionBindingEvent evt) {}

public void valueUnbound(HttpSessionBindingEvent evt) { try { conn.close() ; } catch (SQLException e) {} // Not much to be done about

it. } public Connection conn ; public Statement stat ;}

dbc@csit.fsu.edu 61

Remarks

The most interesting feature of this class is that it implements HttpSessionBindingListener.

The event-handling method valueBound() is invoked whenever this object is bound to a session using setAttribute().

The method valueUnbound() is invoked whenever this object is unbound from a session, either by removeAttribute() or (more importantly) when the session is invalidated (e.g. when it times out).

This ensures that the database connection is closed promptly (and not left to the garbage collector).

The class also illustrates use of a static initialization clause.

dbc@csit.fsu.edu 62

Generating the Response

response.setContentType("text/html"); PrintWriter out = response.getWriter(); . . . print HTML headers . . .

out.println("<form action=" +

response.encodeURL("/students/servlet/View") + ">") ;

out.println("Select by ID:<br>") ; out.println("<select name=login size=15>") ; while(rs.next()) out.println("<option> " + rs.getString(1)) ; out.println("</select>") ;

out.println("View selected record: " + "<input type=submit value=\"View\">") ; out.println("</form>");

. . . print HTML footers . . .

dbc@csit.fsu.edu 63

Remarks

This mainly just prints a form containing big select element holding all the key values from the result set.

dbc@csit.fsu.edu 64

Viewing and Modifying Record

The viewing page displays all the fields in the selected record in a form that allows them to be modified, if desired.

This page is generated by a servlet called View. The session handling is similar to Select (at

this point if the session has timed out we simply create a new one).

The servlet extracts the row associated with the selected login ID.

For future reference, it saves the current value of the fields in the session object.

It generates the HTML for the displayed page.

dbc@csit.fsu.edu 65

Overview of the View servletpublic class View extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)

throws . . . { try { DBSession dbs ; . . . Initialize session, and extract dbs. String login, lastname, firstnames, email, dept ; login = request.getParameter("login") ; // Get the key

string if(login == null) { . . . Call sendError() . . . } . . . Query the database, and extract values lastname, etc. . .

. session.setAttribute("curr", new Student(login, lastname, firstnames, email,

dept)) ; . . . Generate updateable display of current record . . . } catch (SQLException e) { . . . Call sendError() . . . } }}

dbc@csit.fsu.edu 66

Remarks

The Student class defines a simple object that just holds 5 public fields.

dbc@csit.fsu.edu 67

Querying the Database

ResultSet rs = dbs.stat.executeQuery( "SELECT * FROM " +

DBConstants.table + " " + "WHERE login=’ " + login + “ ’ ” ) ;

if(rs.next()) { lastname = rs.getString(2) ; firstnames = rs.getString(3) ; email = rs.getString(4) ; dept = rs.getString(5) ; } else {

response.sendError(HttpServletResponse.SC_OK, "Record not found") ; return ; }

dbc@csit.fsu.edu 68

Generating the Responseresponse.setContentType("text/html");PrintWriter out = response.getWriter();. . . Print HTML headers . . .out.println("<form method=post action=" +

response.encodeURL("/students/servlet/Update") + ">") ; out.println("Login ID: " + "<input type=text size=10 name=login value=\"" + login + "\"><br>") ; out.println("Last Name: " + "<input type=text size=20 name=lastname

value=\"" + lastname +"\"><br>") ; . . . etc... Input elements for the other three fields . . . out.println("<br>Update this record: " + "<input type=submit value=Update>") ;out.println("</form>");. . . Print small alternate form to return to selection page . . .. . . Print HTML footers . . .

dbc@csit.fsu.edu 69

Updating the Database

This is handled by a servlet that normally generates no output. When it is finished it just redirects the browser back to the selection page.

The session handling is slightly different to Select. In this case if the servlet cannot find a current session it will report an error.

The servlet updates the row associated with the selected login ID.

dbc@csit.fsu.edu 70

Overview of the Update Servlet

public class Update extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response)

throws . . . { try { DBSession dbs ; Student curr ; . . . Extract dbs, curr from the session object . . . . . . Update row in database . . . . . . Build a command to undo the update, and save it . . . response.sendRedirect(

response.encodeRedirectURL("/students/servlet/Select"));

} catch (SQLException e) { . . . Call sendError() . . . } }}

dbc@csit.fsu.edu 71

Extracting Session Data

HttpSession session = request.getSession(true) ;

DBSession dbs = (DBSession) session.getAttribute("dbs") ;

Student curr = (Student) session.getAttribute("curr") ;

if(dbs == null || curr == null) {

response.sendError(HttpServletResponse.SC_OK, "Session timed out. Please resubmit

form.") ; return ; }

In this case it is difficult to proceed without the session data.

dbc@csit.fsu.edu 72

Updating the Row

String login = request.getParameter("login") ;String lastname =

request.getParameter("lastname") ;String firstnames =

request.getParameter("firstnames") ;String email = request.getParameter("email") ;String dept = request.getParameter("dept") ;

dbs.stat.executeUpdate( "UPDATE " + DBConstants.table + " SET "

+ "login=’ " + login + “', " + "lastname=’ " + lastname + “', " + "firstnames=’ " + firstnames + “', " + "email=’ " + email + “', " + "dept=’ " + dept + “' " + "WHERE login=’ " + curr.login + “'”) ;

dbc@csit.fsu.edu 73

Building an “Undo” Command

String sql = "UPDATE " + DBConstants.table + " SET " +

"login='" + curr.login + "', " + "lastname='" + curr.lastname + "', "

+ "firstnames='" + curr.firstnames + "',

" + ”email='" + curr.email + "', " + "dept='" + curr.dept + "' " + "WHERE login='" + login + "'" ;

Vector undoList = (Vector) session.getAttribute("undoList") ;

if(undoList == null) { undoList = new Vector() ; session.setAttribute("undoList", undoList) ; }

undoList.addElement(sql) ;

dbc@csit.fsu.edu 74

Remarks

The “undo” command will reverse the effect of the update.

It is not executed here: it is added to a stack held in the session.

dbc@csit.fsu.edu 75

An Undo Button To complete the application we generate the following

extra form in the Select servlet: Vector undoList = (Vector)

session.getAttribute("undoList") ; if (undoList != null && undoList.size() > 0) { out.println("<form action=" + response.encodeURL("/students/servlet/Undo")

+ ">") ;

out.println("Undo most recent change: " + "<input type=submit value=\"Undo\">") ;

out.println("</form>"); }

The Undo servlet just retrieves the undoList from the session and does: int last = undoList.size() - 1 ; dbs.stat.executeUpdate((String) undoList.remove(last))

;