You are on page 1of 4

Access to DBMS from programs

• All the current programming languages have facilities for databases

• Of course, using a DBMS is usually much better than using files


Master in Information – for exactly the reasons pointed-out by ANSI-SPARC
Technology
• The program
– is insulated from knowing how and where the data is stored
ICT - 209
– and can use a simple and convenient data model
– and can get SQL to do all the hard work
Database Applications
• In most cases the application can be (almost) insulated from knowing the
brand of RDBMS (Oracle, MySQL, ... ) being used
Connecting to MySQL in Java
• We shall look at the Java facilities

Prog - 1 Prog - 2

Persistent storage via insulating layers JDBC

• “A Java API for executing SQL statements … a trademarked name and


Java application not an acronym … but often thought of as standing for ‘Java Database
JDBC Connectivity’” (Hamilton, Cattell & Fisher)

DBMS independence
• It comes as part of the J2SDK
– so we don’t need a special element in classpath
DBMS User User User – but we do need
Views Views Views
• import java.sql.* ;
External/Conceptual Logical data
mapping independence
Conceptual
View • We can call JDBC from a free-standing application, an applet, or a servlet
Conceptual/Internal Physical data
– the structure of the calling code is the same
mapping independence
Internal
View

Prog - 3 Prog - 4

JDBC Classes Loading the JDBC driver

• There are lots of classes in the API: but the most important ones are • Each DBMS has (at least one) Java “driver”
– Connection deals with the link to the DBMS – we load it using an incantation
– Statement deals with a single SQL statement – with its own try/catch block
– ResultSet deals with the rows returned when we execute an SQL try {
Class.forName("com.mysql.jdbc.Driver") ; }
SELECT. It has a “cursor” that moves through the rows catch(Exception e) {
System.out.println("Failed to load driver "
+ e.getMessage()) ;
• The steps that we go through: return ; }
– dynamically load a driver for the DB that we wish to use
– get that driver to establish a connection – there are different strings for different types of database, e.g.
sun.jdbc.odbc.JdbcOdbcDriver
– set up a statement and execute it
oracle.jdbc.driver.OracleDriver
– (if appropriate) loop through the result set
– when finished, close the statement and the connection
• The file containing the driver must be in the run-time classpath (e.g. in the
..\jre\lib\ext folder of the J2SDK)

Prog - 5 Prog - 6

1
What to Import SQLException

• You will need at least the first two, and probably the rest • The rest of the methods all throw SQLException
• So we wrap the rest of the JDBC code in a try/catch block
import java.sql.Connection; import
java.sql.DriverManager; import try {
java.sql.PreparedStatement; import // make the connection
java.sql.ResultSet; // set-up the statement & execute it
// loop through the result-set
import java.sql.SQLException;
}
import java.sql.Statement; catch(SQLException e) {
System.out.println("SQLException: "
+ e.getMessage()) ;
}
finally {
// release any DBMS resources
}

Prog - 7 Prog - 8

Making the connection Setting up the statement and executing it

• Making the connection involves identifying ourselves to the • Now we have an object (con) of class Connection, we can proceed
particular DB we wish to use – suppose our SQL statement is a SELECT

• Need to specify Database URL, username and password


Statement stmt = con.createStatement() ;
Connection con; String query = "SELECT This, That FROM MyTab" ;
ResultSet rs = stmt.executeQuery(query) ;
con = DriverManager.getConnection(String url);
con = DriverManager.getConnection(String url, String
user, String pwd); • The object rs can now be used to access all the rows retrieved by the
query
– we can traverse those rows once (only) in a loop
E.G – before we start, the result set's implied cursor is before the first row
– the method next() moves the cursor to the next row (if any), returning a
boolean indicating whether there actually was a next row
DriverManager.getConnection(“\\localhost\mydb”,”kms”,”pwd
”);

Prog - 9 Prog - 10

Looping through the rows More about the getXXX methods

• The so-called getXXX methods will retrieve values from the current row of • Each getXXX method has two forms: we can specify either the column
the result set position or the column name
– in the example on the previous slide – in the previous example, the following would be equivalent:
SELECT This, That FROM MyTab rs.getInt(1)
– suppose the column This has the data type INT and the column rs.getInt("This")
That has the data type CHAR(10)

• The stock of getXXX methods is large


while (rs.next()) {
– obviously, you use one that is appropriate for the type of the column in
System.out.println("\"This\" has the value "
the database
+ rs.getInt(1)
+"<br>" – we have all the usual types like short, int, float, double,
+"\"That\" has the value " String etc
+ rs.getString(2) – and more exotic ones like Date (the version in java.sql extends the
+"<br>") ; one in java.util) or AsciiStream
}
Prog - 11 Prog - 12

2
An example all on one slide (once the driver's loaded) Releasing resources

Connection con = null ;


Statement stmt = null ; • The arrangement of the try/catch/finally makes sure that database
try { resources (particularly the Connection) are always released
DriverManager.getConnection(“\\localhost\mydb”,”kms”,”pwd”);
stmt = con.createStatement() ;
ResultSet rs = stmt.executeQuery(
"SELECT DISTINCT Season, Title FROM rb1.Panto") ; • ResultSets are reasonably safe
while (rs.next()) { – we can assume that they are garbage-collected when they go out of
String year = rs.getString(1) ;
String panto = rs.getString(2) ; scope
System.out.println("In "+year+" the panto was "+panto) ;
}}
catch(Exception e) { • But Connections and Statements should always be explicitly closed
System.err.println("Exception: " + e.getMessage()) ; } – there may be resources within the DBMS that won't be released by
finally {
try { Java garbage-collection
if (stmt!=null) stmt.close() ;
if (con!=null) con.close() ; }
catch (java.sql.SQLException ignore){}}

Prog - 13 Prog - 14

Executing a non-query SQL statement Miscellaneous points

• The previous example was an SQL SELECT


• If we wanted to use INSERT, UPDATE or DELETE • Some gotchas
– we would use executeUpdate instead of executeQuery – if you break a string across two lines, remember the space: this is
wrong
stmt.executeUpdate("INSERT INTO Coffees "
+"VALUES('Espresso',9.99)"); stmt.executeUpdate("INSERT INTO Coffees"
+"VALUES('Espresso',9.99)");
– executeUpdate returns an integer, the number of rows affected (here, just
one) – remember to quote SQL character strings, e.g. 'Espresso'
– don't add semicolons
• Of course, we wouldn't usually write a Java program to insert constant values
– we'd be entering values generated/captured by the program • In our example we open and close our own connection to the DB
– you can either convert the values to strings and build them into an INSERT INTO – there are other techniques: e.g. borrowing an existing connection from
string a managed “pool” of connections
– or use PreparedStatement (later) – we shan’t cover this

Prog - 15 Prog - 16

Miscellaneous points, continued Prepared statements

• The above example exposes the username/password • On slide 9 we had a Statement object that was used on only two lines
kms,pwd stmt = con.createStatement() ;
ResultSet rs = stmt.executeQuery("SELECT ...") ;
– this is not good
• One approach is to have a dummy user e.g. scott/tiger
• The statement object seems to be on-stage very briefly …
• The user rb1 then gives limited access to the dummy user
• But under some circumstances it may be useful (or essential) to work in
GRANT SELECT ON MyTab TO scott ;
three stages
– prepare a statement using placeholders
– and then rewrites the code so that the user is scott/tiger
– fill in the blanks
getConnection(“\\localhost\mydb”,”scott”,”tiger”); – execute the statement

• If the connection is obtained from a pool (previous slide) then the • The class is now PreparedStatement (not Statement): we declare (say)
username/password are hidden anyhow pstmt in the same place (Slide 9)

Prog - 17 Prog - 18

3
Prepared statements, continued Prepared statements, continued

• Example of SQL with placeholders • Execute the statement:


SELECT Price FROM Coffees ResultSet rs = pstmt.executeQuery() ;
WHERE CoffeeName = ? UPDATE
Coffees SET Price = ? • The second example would be:
WHERE CoffeeName = ?
String query = "UPDATE Coffees SET Price = ? "
+" WHERE CoffeeName = ? " ;
• Preparing the statement: pstmt = con.prepareStatement(query) ;
String query = "SELECT Sales FROM Coffees " pstmt.setInt(1,12.99) ;
+" WHERE CoffeeName = ? " ; pstmt.setString(2,"Blue Mountain") ;
pstmt = con.prepareStatement(query) ; int nrows = pstmt.executeUpdate() ;

• Fill in the blank(s): • There is a whole family of setXXX methods, one for each type
pstmt.setString(1,"Blue Mountain") ;
• But why would we want to use prepared statements?
Placeholder value
Placeholder number
– there are two main circumstances ...

Prog - 19 Prog - 20

Motivation for prepared statements Prepared statement: Dates and a file

• If the SQL is executed repeatedly, it may be more efficient


• A sketch of this (the full details are rather intricate)
– the preparation can be done outside the loop, once
– most of the work is just casting between Java classes
– (some DBMSs may do nothing)
• Suppose we have a table to hold plain ASCII files, like this

• It can make it easier to manage the transition from Java to SQL CREATE TABLE FileArchive (
– e.g. we no longer need to know how to quote strings in SQL Name VARCHAR2(40),
FDate DATE,
FStoreDate DATE,
Ftext LONG) ;
• It would be unfeasibly hard to turn these into literals in an ordinary INSERT INTO
– (these dates will actually be date-and-time)
• .. and we want to write a program to store a named file in this table
– the Name is easy (just a string)
– the Dates aren’t: we decide to use java.sql.Timestamp
– the file is quite hard!

Prog - 21 Prog - 22

Dates and a file, continued

• ... assume we already have a Connection, con, as before


– here’s the outline (missing some try/catch blocks)

File f = new File("c:\etc\...") ;


String fileName = f.getName() ;
long fileTime = f.lastModified() ;
int fileLength = (int)f.length() ;
FileInputStream fstr = new FileInputStream(f) ;
String s = "INSERT INTO FileArchive VALUES
('“ + fileName + "',?,?,?)" ;
PreparedStatement pstmt = con.prepareStatement(s) ;
java.sql.Timestamp fileModDate = new
java.sql.Timestamp(fileTime) ;
java.sql.Timestamp fileStoreDate = new
java.sql.Timestamp(System.currentTimeMillis()) ;
pstmt.setTimestamp(1,fileModDate) ;
pstmt.setTimestamp(2,fileStoreDate) ;
pstmt.setAsciiStream(3,fstr,fileLength) ;
pstmt.executeUpdate() ;

Prog - 23

You might also like