Introduction to JDBCkhalid/atij/atij-jdbc-web/atij-jdbc-I.pdf · JFPS3U 10: Introduction to JDBC:...

34
JFPS3U 10: Introduction to JDBC: 10-1/34 Introduction to JDBC: Java Database Connectivity (Part I) Advanced Topics in Java Khalid Azim Mughal [email protected] http://www.ii.uib.no/~khalid/atij/ Based on notes by Yngve Lamo. Version date: 26/12/06

Transcript of Introduction to JDBCkhalid/atij/atij-jdbc-web/atij-jdbc-I.pdf · JFPS3U 10: Introduction to JDBC:...

JFPS3U 10: Introduction to JDBC: 10-1/34

Introduction to JDBC: Java Database Connectivity

(Part I)

Advanced Topics in Java

Khalid Azim [email protected]

http://www.ii.uib.no/~khalid/atij/

Based on notes by Yngve Lamo.

Version date: 26/12/06

JFPS3U 10: Introduction to JDBC: 10-2/34

Overview• Role of the JDBC API.

• Creating the JDBC Driver Instance.

• Defining the Database URL.

• Establishing Connection using DriverManager.

• Executing Dynamic SQL Statements.

• Handling Query Results.

• Mapping between SQL Types and Java Types

• Precompiling Queries with Prepared SQL Statements

• Running Transactions

• Reading Metadata

JFPS3U 10: Introduction to JDBC: 10-3/34

The Role of JDBC• JDBC defines an Application Programming Interface (API) between Java programs

and relational databases:

• Mapping:

Java Objects <==> Relational Tables

• JDBC provides connectivity to a set of data sources:– Java programs can send SQL queries to the relational database system and receive

results as Java objects.

• Application development independent of platform and DBMS.– JDBC provides a Java API for SQL access and a driver manager to connect to a DBMS.– Database specific behaviour is factored into a vendor-specific JDBC driver.– Only need to change the vendor-specific JDBC driver for the DBMS.

JFPS3U 10: Introduction to JDBC: 10-4/34

JDBC: Java Database Connectivity

JavaApplication

JDBC JDBC

Middle Tierwith

Business Logic

Application Server

HTTP

DBMS

DBMS propriety protocol

Database Server

HTML browser

JFPS3U 10: Introduction to JDBC: 10-5/34

JDBC Resources• Sun’s official site: https://java.sun.com/javase/technologies/database/index.jsp

• See the JDBC API documentation: java.sql package

Postgresql 8.2 + JDBC Driver• Official site: http://jdbc.postgresql.org/

• Installation of PostgreSQL Database System as a service under Windows.

• Installation of GUI-based pgAdmin III 1.6.1 tool.

• Installation of the driver for web applications in TOMCAT_HOME\common\lib:postgresql-8.2-504.jdbc3.jar

• Installation of the driver for other applications in JAVA_HOME\jre1.6.0\lib\ext:postgresql-8.2-504.jdbc3.jar

JFPS3U 10: Introduction to JDBC: 10-6/34

JDBC packages• API documentation for JDBC can be found here:

http://java.sun.com/javase/6/docs/api/index.html

• Package java.sql offers:– Connections to DB from Java programs– Execution of queries from Java programs– Execution of stored procedures from Java programs– Execution of transactions from Java programs

• Package javax.sql in addition offers:– Connections from a pool using a DataSource.

JFPS3U 10: Introduction to JDBC: 10-7/34

JDBC Usage• Usage pattern:

1. Establish a connection to a data source, i.e. a relational database.2. Send SQL queries to the data source.3. Process the results from the data source as Java objects.4. Close the connection after use.

JFPS3U 10: Introduction to JDBC: 10-8/34

PostgreSQL Database Example: Horoscope

See the files in the horoDB-data.sql and horoDB-schema.sql.

• Database name: horodb

• Relational table: horotable(sign, horoscope)

• Username: javauser

• Password: javadude

JFPS3U 10: Introduction to JDBC: 10-9/34

Basic JDBC Programming• Creating the JDBC Driver Instance:

org.postgresql.Driver

• Defining the Database URL:

jdbc:postgresql://<domain-name>:<port>/<database-name>

• Establishing Connection using DriverManager:

java.sql.Connection

• Executing Dynamic SQL Statements:

java.sql.Statement

• Handling Query Results:

java.sql.ResultSet

• Mapping between SQL Types and Java Types

• Precompiling Queries with Prepared SQL Statements

• Running Transactions

• Reading Metadata

JFPS3U 10: Introduction to JDBC: 10-10/34

Advanced Topics• Using a pool of DB connections (improving DB connection handling):

javax.sql.DataSource

• Hibernate Framework (eliminating JDBC):http://www.hibernate.org/

JFPS3U 10: Introduction to JDBC: 10-11/34

Use the DB functionality• A DBMS provides effective storage and manipulation of data.

• Take advantage of the functionality that is implemented in the DBMS.– Use DB-constraints, such as:

• Primary Key• Foreign Keys• Triggers

• Let the Java program catch the java.sql.SQLException that is thrown when a constraints is violated.

JFPS3U 10: Introduction to JDBC: 10-12/34

JDBC Drivers• A JDBC driver is an implementation of the JDBC specification that translates JDBC

statements to a DB protocol.– A JDBC driver is propriety and vendor-specific.

• Type of drivers:– Type 1:

JDBC-ODBC (Open DataBase Connectivity) bridge =>Vendor DB library --> Database Sever

– Type 2: Native API - partly Java driver => Middle Server --> Database Sever

– Type 3: Net-protocol pure-Java driver --> Vendor DB library --> Database Sever

– Type 4: Net-protocol due-Java driver --> Database Sever

• Type 3 JDBC driver for PostgreSQL:org.postgresql.Driver

JFPS3U 10: Introduction to JDBC: 10-13/34

JDBC URL• URL of the database:

final static String DB_URL = "jdbc:postgresql://localhost/horodb";

• jdbc is the protocol

• postgresql is the subprotocol which specify the type of DB driver.

• localhost is the domain name to find the DBMS.

• horodb is the name of the DB.

• Port (default: 5432) can be specified after the domain name.

JFPS3U 10: Introduction to JDBC: 10-14/34

Class java.sql.DriverManager• Class that registers the drivers and establishes connection between drivers and the

DB.

• A program has only one DriverManager.

final static String DRIVER = "org.postgresql.Driver";...

try { // Create instance of the driver class.

Class.forName(DRIVER).newInstance(); System.out.println("Db-driver created.");

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

JFPS3U 10: Introduction to JDBC: 10-15/34

Interface java.sql.Connection• A Connection object represents the connection to the DB.

final static String DB_URL = "jdbc:postgresql://localhost/horodb";

final static String DB_USER = "javauser";

final static String DB_PASSWORD = "javadude";

...

Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);

• A connection must be explicitly closed when no longer needed as not doing so can degrade performance:

conn.close();

• Methods of the Connection interface throw the checked SQLException.

JFPS3U 10: Introduction to JDBC: 10-16/34

Statements• Statement objects are used to send SQL queries to the DB.

• 3 kinds of SQL Statement objects:– java.sql.Statement that is used to send a query as a string to the DB.– java.sql.PreparedStatement that is used to send precompiled SQL queries with input

parameters.– java.sql.CallableStatment that is used to call stored procedures in the DB.

• The Connection object provides the methods to create an appropriate kind of statement.– createStatment(...) – prepareStatment(...)– prepareCall(...)

• Example:

Connection conn = …

Statement stmt = conn.createStatement();

JFPS3U 10: Introduction to JDBC: 10-17/34

The ResultSet• Queries are sent to the DB as parameters to one of the execute methods in the

Statement object.

• Example:

final static String DB_TABLE = "horotable";

...

String sign = ...

...

ResultSet rs = stmt.executeQuery("SELECT * FROM " + DB_TABLE + " WHERE SIGN ='" + sign + "'");

• ResultSet objects represents the result of a query (i.e. a table with rows/records).

JFPS3U 10: Introduction to JDBC: 10-18/34

Execution of Statements• The method executeQuery() is used when the result is a single ResultSet object, e.g.

when using SELECT.

• The method executeUpdate() is used for INSERT, UPDATE, DELETE, CREATE TABLE, ALTER TABLE and DROP TABLE.– returns the row count for SQL DML statements, and 0 for other statements.

JFPS3U 10: Introduction to JDBC: 10-19/34

Use of ResultSet• ResultSet objects has a cursor that is positioned before the current row in the ResultSet.

• There are several methods to move the cursor in a ResultSet object.– next() moves the cursor to the next row.– previous() moves the cursor to previous row.– first() moves the cursor to first row.– last() moves the cursor to last row.

• The getter methods in the ResultSet are used to get the data from the current row.

JFPS3U 10: Introduction to JDBC: 10-20/34

Examples using ResultSet

• Example 1: Only one row.

ResultSet rs = stmt.executeQuery("SELECT * FROM " + DB_TABLE

+ " WHERE SIGN ='" + sign + "'");

if (rs.next()) horoStr = rs.getString(2); // horoscope column...

• Example 2: Several rows.

...

ResultSet rs = stmt.executeQuery("SELECT * FROM horotable");

int i = 0;

while (rs.next()){ // Prints the data in current row.

String sign = rs.getString("sign"); String horoscope = rs.getString("horoscope"); System.out.printf("ROW = %2d: %12s %s%n", i++, sign, horoscope);

}

JFPS3U 10: Introduction to JDBC: 10-21/34

Different types of ResultSets• Following constants can be used in the Connection.createStatement() method to

specify the different types of ResultSets.

• Flexible ResultSets are computation intensive.

java.SQL.ResultSet

TYPE_FORWARD_ONLY The next() method is used to move the cursor downward in the ResultSet, this is default behaviour.

TYPE_SCROLL_INSENSITIVE Cursor can be moved forward and backward, the ResultSet is not dynamically changed when the underlying DB is changed.

TYPE-SCROLL_SENSITIVE Cursor can be moved forward and backward, the ResultSet is dynamically changed when the underlying DB is changed.

CONCUR_READ_ONLY ResultSet cannot be updated concurrently

CONCUR_UPDATABLE ResultSet can be updated concurrently

JFPS3U 10: Introduction to JDBC: 10-22/34

Methods to retrieve and modify data in the ResultSet• Use getType() methods to retrieve data from the current row in the ResultSet:

Type getType(String columnName)

Type getType(int columnNumber)

• Use updateType() methods to update information in the current row in the ResultSet.

void updateType(String columnName, Type value)

void updateType(int columnName, Type value)

– These methods can throw SQLException.

• The updateType() methods only updates the ResultSet, and not the underlying DB.

• The updateRow() or InsertRow() methods in the ResultSet must be called to update the DB.

JFPS3U 10: Introduction to JDBC: 10-23/34

Method to retrieve Data from the Current Row in the ResultSetgetString() CHAR, VARCHAR and LONGVARCHAR

getBytes() BINARY, VARBINARY and LONGVARBINARY; i.e. for SQL binary value types

getBoolean() BIT

getShort() TYNYINT and SMALLINT

getInt() INTEGER,

getFloat() REAL

getDouble() DOUBLE and FLOAT

getDate() DATE:- day, month and year

getTime() TIME:- hour, minute and second

getTimestamp() TIMESTAMP:- DATE + TIME + field for nanosecond, the type is subclasses of java.util.Date.

JFPS3U 10: Introduction to JDBC: 10-24/34

Mapping between DB Concepts and Java Objects• Table -> Class

• Row -> Object instant

• Column -> Object attribute

• Other DB concepts do not have corresponding concepts in the object model (primary key, foreign key, referential integrity, constraints, triggers).

JFPS3U 10: Introduction to JDBC: 10-25/34

SQL Types and Java Types

SQL data type Java data type

CHARACTER String

VARCHAR String

LONGVARCHAR String

NUMERICjava.math.BigDecimal

DECIMALjava.math.BigDecimal

BIT boolean

TINYINT byte

SMALLINT short

INTEGER int

BIGINT long

REAL float

FLOAT double

DOUBLE PRECISION double

JFPS3U 10: Introduction to JDBC: 10-26/34

BINARY byte[]

VARBINARY byte[]

LONGVARBINARY byte[]

DATE java.sql.Date

TIME java.sql.Time

TIMESTAMP java.sql.Timestamp

SQL data type Java data type

JFPS3U 10: Introduction to JDBC: 10-27/34

Prepared Statements• A prepared statement is a precompiled SQL query that takes actual values for zero or

more input parameters.

• A PreparedStatement is a subinterface of Statement.

• A PreparedStatment is used for a query that is used frequently.

• Best practice: use PreparedStatments for update queries.

• The DB caches queries, i.e. some of the effect of PreparedStatements is implicitly supported by the DBMS.

JFPS3U 10: Introduction to JDBC: 10-28/34

Example of PreparedStatement

... // Create a prepared statement PreparedStatement pstmt = conn.prepareStatement( "SELECT * FROM " + DB_TABLE + " WHERE SIGN = ?" // Only one input parameter );

// Pass the value of the sign pstmt.setString(1, sign);

// Executing the query ResultSet rs = pstmt.executeQuery(); ...

JFPS3U 10: Introduction to JDBC: 10-29/34

Transactions• Transactions are used when a collection of DB operations should be performed as one

atomic operation:– The DB operations are dependent on each other and where the next DB operation is

only executed if the previous DB operation went well.– If all DB operations go well, the transaction is committed, otherwise the transaction

is rolled back as if none of the DB operation had executed.

• The DB operations in a transaction use the same DB connection.

• Typical usage: a use case that involves several dependent DB operations.

• Applications that use some form of a shopping cart.– Example: a website for buying tickets, where a seat is sold only if the ticket is paid

for.try {

q1; q2; q3; // Sequence of queries

conn.commit();} catch (SQLException sqle) {

conn.rollback();}

JFPS3U 10: Introduction to JDBC: 10-30/34

More on transactions

java.sql.Connection

void setAutoCommit(boolean value) Set the auto-commit mode of this Connection object. The value true (default) means a transaction is a single statement and will auto-commit if executed successfully. The value false means statements are grouped into transactions terminated by either commit() or rollback() calls.

boolean getAutoCommit() Returns the current auto-commit mode for the current Connection object.

void commit() When auto-commit is false, makes changes permanent since the previous commit/rollback.

void rollback() Undo all changes in the present transaction.

JFPS3U 10: Introduction to JDBC: 10-31/34

Example: Transaction try { ... status = conn.getAutoCommit(); conn.setAutoCommit(false); Statement stmt = conn.createStatement(); // Executing a sequence of queries int rc1 = stmt.executeUpdate("UPDATE horotable SET " + "horoscope='Count your blessings. It might be too late.'" + "WHERE sign = 'taurus'"); int rc2 = stmt.executeUpdate("UPDATE horotable SET " + "horoscope='Sell your shares ASAP!'" + "WHERE sign = 'leo'"); // Should fail as sign is primary key. stmt.executeUpdate("INSERT INTO horotable VALUES ('pisces','Whatever')"); conn.commit(); } catch (SQLException e) { conn.rollback(); System.out.println("Transaction rolled back."); } finally { if (conn != null) { conn.setAutoCommit(status); conn.close(); } }

JFPS3U 10: Introduction to JDBC: 10-32/34

ACID principle• All or nothing, all or none of the DB operations are executed.

• Consistence, same input same result, no side effects.

• Isolation, a transaction is independent of other transactions.

• Durable, all changes made by a transaction are permanent.

JFPS3U 10: Introduction to JDBC: 10-33/34

Metadata• DatabaseMetaData provides information about a database.

// Create a DatabaseMetaData object from the Connection.

DatabaseMetaData meta = conn.getMetaData(); // Get info about all tables

ResultSet mrs = meta.getTables(null, null, null, new String[]{"TABLE"}); // Each row contains info about a table.

while (mrs.next()){

System.out.println(mrs.getString(3)); // 3rd column: table name }

JFPS3U 10: Introduction to JDBC: 10-34/34

• ResultSetMetaData provides information about a ResultSet.

// Executing the query

ResultSet rs = stmt.executeQuery("SELECT * FROM " + DB_TABLE);

// Get ResultSetMetaData object for the ResultSet

ResultSetMetaData rsMeta = rs.getMetaData(); // Print the column names and save the names in an array.

String[] columnNames = new String[rsMeta.getColumnCount()];

System.out.printf("%8c", ' ');

for (int i = 0; i < rsMeta.getColumnCount(); i++){ String columnName = rsMeta.getColumnLabel(i+1); columnNames[i] = columnName;

System.out.printf("%s ", columnName);

}