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 [Link].* ;
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 {
[Link]("[Link]") ; }
SELECT. It has a “cursor” that moves through the rows catch(Exception e) {
[Link]("Failed to load driver "
+ [Link]()) ;
• 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.
[Link]
– set up a statement and execute it
[Link]
– (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 [Link]; import
[Link]; import try {
[Link]; import // make the connection
[Link]; // set-up the statement & execute it
// loop through the result-set
import [Link];
}
import [Link]; catch(SQLException e) {
[Link]("SQLException: "
+ [Link]()) ;
}
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 = [Link]() ;
Connection con; String query = "SELECT This, That FROM MyTab" ;
ResultSet rs = [Link](query) ;
con = [Link](String url);
con = [Link](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
[Link](“\\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 [Link](1)
– suppose the column This has the data type INT and the column [Link]("This")
That has the data type CHAR(10)
• The stock of getXXX methods is large
while ([Link]()) {
– obviously, you use one that is appropriate for the type of the column in
[Link]("\"This\" has the value "
the database
+ [Link](1)
+"<br>" – we have all the usual types like short, int, float, double,
+"\"That\" has the value " String etc
+ [Link](2) – and more exotic ones like Date (the version in [Link] extends the
+"<br>") ; one in [Link]) 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
[Link](“\\localhost\mydb”,”kms”,”pwd”);
stmt = [Link]() ;
ResultSet rs = [Link](
"SELECT DISTINCT Season, Title FROM [Link]") ; • ResultSets are reasonably safe
while ([Link]()) { – we can assume that they are garbage-collected when they go out of
String year = [Link](1) ;
String panto = [Link](2) ; scope
[Link]("In "+year+" the panto was "+panto) ;
}}
catch(Exception e) { • But Connections and Statements should always be explicitly closed
[Link]("Exception: " + [Link]()) ; } – there may be resources within the DBMS that won't be released by
finally {
try { Java garbage-collection
if (stmt!=null) [Link]() ;
if (con!=null) [Link]() ; }
catch ([Link] 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
[Link]("INSERT INTO Coffees "
+"VALUES('Espresso',9.99)"); [Link]("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 = [Link]() ;
ResultSet rs = [Link]("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 = [Link]() ;
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 = [Link](query) ;
String query = "SELECT Sales FROM Coffees " [Link](1,12.99) ;
+" WHERE CoffeeName = ? " ; [Link](2,"Blue Mountain") ;
pstmt = [Link](query) ; int nrows = [Link]() ;
• Fill in the blank(s): • There is a whole family of setXXX methods, one for each type
[Link](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 [Link]
– 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 = [Link]() ;
long fileTime = [Link]() ;
int fileLength = (int)[Link]() ;
FileInputStream fstr = new FileInputStream(f) ;
String s = "INSERT INTO FileArchive VALUES
('“ + fileName + "',?,?,?)" ;
PreparedStatement pstmt = [Link](s) ;
[Link] fileModDate = new
[Link](fileTime) ;
[Link] fileStoreDate = new
[Link]([Link]()) ;
[Link](1,fileModDate) ;
[Link](2,fileStoreDate) ;
[Link](3,fstr,fileLength) ;
[Link]() ;
Prog - 23