Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
Java Fundamentals 4
JDBC
What is JDBC?
– Java Database Connectivity
– JDBC is a standard Java API implementing access to tabular data (especially relational databases)
Java Application
Driver Manager
JDBC Driver
Why use JDBC?
– JDBC provides standardized access todatabases
– JDBC allows you to change the databasewithout changing the Java code
– JDBC is an intermediary data access layer
– JDBC provides parametrized queries, usefulin batch operations and avoiding SQLinjection
JDBC vs. ODBC
– JDBC is not the first try at standardizeddata access
– ODBC (open database connectivity) isbased on native implementations
– JDBC is independent from the OSimplementation, unlike ODBC. When usingODBC support, you are dependent on OSfeatures
– The JDBC-ODBC bridge is a special driverfor ODBC access via JDBC
JDBC Drivers
– Drivers are implementations handlingactual communication to the database
– An application can load (register) multipledrivers
– Drivers are registered with DriverManager
– Only one instance of a driver is loaded
Types of JDBC Drivers
– Type 1 - JDBC-ODBC bridge
• translates queries into ODBC queries
– Type 2 - Native API driver
• uses the native database client
Types of JDBC Drivers
– Type 3 - Network protocol driver
• uses a middle tier
• requests are done through an applicationserver
– Type 4 - Native protocol driver
• pure java driver
• communicates with the database via it ownprotocol, usually via sockets
Typical JDBC application
Register a JDBC driver
Open a connection
Create a statement
Execute the
statement
Process results
Close the connection
Loading a driver
– Ways of loading a driver
• Through the command line
– Via a properties file
– Through Class.forName
• the driver is loaded via a static block in theclass
– Via an object of the driver class
Loading a driver - examples
1. //driver loaded from command line
2. java -Djdbc.drivers=com.mysql.jdbc.Driver Test
3. //driver loaded through a static block
4. Class.forName("com.mysql.jdbc.Driver");
5. //driver loaded through the driver manager
6. Driver driver = new com.mysql.jdbc.Driver();
7. DriverManager.registerDriver(driver);
Getting a connection
– DriverManager intermediates gettingconnections from the database
– Connections are requested via an URL
– If the connection requires a username andpassword, they can be supplied viaoverloaded implementations ofgetConnection
Getting a connection
1. String url = jdbc:mysql://localhost:3306/acmeinc";
2. String user = "root";
3. String password = "welcome123";
4. conn = DriverManager.getConnection(url, user, password);
Closing a connection
– Connections are rare resources and shouldbe closed
– Connections should be closed on finally
– Connection state can be verified with theisClosed method
Closing a connection
1. //close a connection if it was opened
2. finally{
3. if (conn!=null)
4. conn.close();
5. }
6. //verify if a connection is opened
7. if(!conn.isClosed()){
8. //use the connection
9. }
JDBC URL's
– General form:1. jdbc:<database_protocol>:<identifier>
– JDBC URL's are, however, not standard
– Subprotocol is the protocol used by thedatabase
– Identifier is usually a catalog identifier1. jdbc:mysql://localhost:3306/acmeinc
– Identifier can also contain databasespecific properties1. jdbc:odbc:testdb;UID=user;PWD=pass
Connection pools
– Connection pools allow for reuse ofconnections
– Connections are not closed manually
– Usually connection pools are implementedin application containers
Types of statements
– Statement objects execute simple SQL
• vulnerable to injection
• should only be used when no parameters arepassed
– PreparedStatement objects representparametrized statements
• forces parameter type
• avoids injection attacks
Types of statements
– CallableStatement objects are used forinteraction with stored procedures
• allows for retrieval of parameter values
• supports in, out and dual purpose parameters
• forces parameter type
Statements
– Statement objects execute a queryrepresented by a String
– If the String is parametrized as below, aseries of vulnerabilities emerge
• String query = "SELECT * FROMusers
• WHERE user = " + userString;
– Parametrized statements should bepreferred in all cases where a Statementexecutes a command containing user input
Using a Statement
– Creating a Statement1. Statement stmt = null;
2. stmt = conn.createStatement();
– Executing a query1. ResultSet rs =
2. stmt.executeQuery("SELECT * FROM users");
– Executing an update1. int result = stmt.executeUpdate("INSERT INTO
2. employees(idemployees, full_name, type)
3. VALUES (3,'Orr','mistery') ");
Prepared Statements
– Prepared statements representparametrized queries
– Prepared statements are usually compiledon the database server (though it dependson the actual driver implementation)
– Prepared statements are faster forrepeated query, but they carry someoverhead for single queries
Prepared Statements
– Prepared statements force parameter typeand make it impossible to executeparameter content
– In order to avoid injection attacks,prepared statements should always beused where parameters come directly orindirectly from an user
Using a PreparedStatement
– Creating a prepared statement1. PreparedStatement stmt = null;
2. stmt = conn.prepareStatement("UPDATE
3. employees SET type = ? WHERE idemployees
4. = ?");
– Setting parameter values is donepositionally (1 based)1. stmt.setString(1, "deserted");
2. stmt.setInt(2, 3);
Using a PreparedStatement
– Executing the statement(same types ofresults as Statement objects)1. int result = stmt.executeUpdate();
Returned values
– Statements and prepared statementsreturn either an integer value or a resultset
• Integer values usually have the significance of"number of rows affected"
• Result sets are obtained by executing a selectstatement
Query results
– Queries (Selects) return result sets
– Result sets are represented by ResultSetobjects
• ResultSets are not serializable because theycontain a reference to a Connection object
– RowSets are another way of retrievingresults
• RowSets do not have a standardimplementation
• RowSets are serializable
Result sets
– Results of selects are represented asResultSet objects
– ResultSet objects are iterable collections oftuples
Result sets
– Result sets do however have a lot morehidden complexity, as they actuallyrepresent cursors on the database
• one consequence is that, provided the driverpermits it, result sets can be accessedpositionally
• result sets can also be treated as updateable(updating the result updates the underlyingdata)
Retrieving results
– Getting a result set from a statement1. ResultSet rs =
2. stmt.executeQuery("SELECT * FROM
3. employees");
– Getting a result set from a preparedstatement1. ResultSet rs =
2. stmt.executeQuery("SELECT * FROM
3. employees");
Iterating through results
– Result sets have a next() method whichreturns
• false if no more results are available
• true if more results are available; in this situation, the method also advances to the next result
– Iterating through the result set1. while(rs.next()){
2. //process row
3. }
Retrieving simple types
– In order to retrieve values from a resultset, SQL types are mapped to data types
– Columns can be retrieved by position(1based) or name1. int id = rs.getInt(1);
2. String name = rs.getString("full_name");
Retrieving function results
– Function and their results are DBMSspecific
– Function results are retrieved in columns,just like regular columns
– While is still used as a check for the factthat the function returned 1 value(insteadon none) even if the function returns anaggregate value
Retrieving function results
– If the function is a map function (receivesa list of values and returns a list of values),there will be as many values as tuples
– While is still used as a check for the factthat the function returned 1 value(insteadon none)1. rs = stmt.executeQuery("SELECT COUNT(*) FROM
2. employees");
3. while(rs.next()){
4. int i = rs.getInt(1);
5. }
Retrieving function values
– If the function is a reduce function(afunction that receives a list of values andproduces one aggregate result), there willbe only one row, containing one value forthe function1. rs = stmt.executeQuery("SELECT
2. UPPER(full_name) FROM employees");
3. while(rs.next()){
4. System.out.println("Apparent name " +
5. rs.getString(1));
6. }
Callable statements
– Callable statement facilitate the interactionwith stored procedures
– Usually stored procedures return valuesreadable from variables defined in theDBMS itself
– Such values are not extractable from aresult set
– Callable statements support input, outputand dual purpose parameters
Using a callable statement
– Creating a callable statement1. CallableStatement stmt = null;
2. stmt = conn.prepareCall("CALL
3. test_proc(?,?,?)");
– Setting input parameters1. stmt.setInt(1, 10);
– Registering output parameters1. stmt.registerOutParameter(3, Types.INTEGER);
Using a callable statement
– Handling input/output parameters (INOUTparameters have to be both set andregistered )1. stmt.setInt(2, 20);
2. stmt.registerOutParameter(2, Types.INTEGER);
– Executing the callable statement1. stmt.execute();
Using a callable statement
– Retrieving results(results are retrievedfrom output and dual purpose parameters)1. int y = stmt.getInt("y");
2. int z = stmt.getInt("z");
Retrieving result metadata
– Sometimes the database schema must bediscovered at runtime
– ResultSetMetaData can be obtained from aResultSet1. ResultSet rs = null;
2. ResultSetMetaData rsmd = null;
3. //retrieve result set
4. rsmd = rs.getMetaData();
Retrieving result metadata
– Getting the number of columns1. int nrCol = rsmd.getColumnCount();
– Getting the name of a column(1 based)1. String colName = rsmd.getColumnName(1);
– Getting the type of a column (the typecorresponds to the enumerationjava.sql.Types)1. int type = rsmd.getColumnType(i);
Retrieving result metadata
– Getting the name of the catalog(database); can be applied to any column1. String catalog = rsmd.getCatalogName(1);
– Some drivers do not implement bothgetting the table and the schema of a table
– Getting the name of the schema (table);can be applied to any column1. String table = rsmd.getTableName(1);
2. String schema = rsmd.getSchemaName(1);
Handling large objects
– Databases usually support the storage oflarge objects
– The typical associated types are
• CLOB - character large objects with no Javaequivalent
• BLOB - binary large objects with no Javaequivalent
Handling large objects
– Two approaches are possible
• using streams
• using setXXX methods
• on MySql, setBinaryStream should be used
– Connection limits have to be taken intoaccount when dealing with multimegabytecontent
• in this situation streams are the only solution
Inserting a BLOB
1. stmt = conn.prepareStatement("INSERT INTO blobs
2. VALUES (?,?)");
3. stmt.setInt(1, 2);
4. File file = new File("test.jpeg");
5. FileInputStream input = new FileInputStream(file);
6. stmt.setBinaryStream(2, input,file.length());
7. int result = stmt.executeUpdate();
Recovering a BLOB
1. stmt = conn.prepareStatement("SELECT blobscol FROM
2. blobs");
3. ResultSet rs = stmt.executeQuery();
4. while (rs.next()){
5. file = new File("out.jpg");
6. FileOutputStream output = new
7. FileOutputStream(file);
8. InputStream reader = rs.getBinaryStream(1);
9. byte[] b = new byte[1];
10. while(reader.read(b)>0) output.write(b);
11. output.close();
12. }
Batch processing
– PreparedStatements are much moreefficient when reused
– Reuse is facilitated by a batchingmechanism
– Through batching, prepared statementswith the same template are grouped
– A batch of statements produces an array ofresults (one for each statement)
Using batches
– Preparing the statement1. stmt = conn.prepareStatement("INSERT INTO
2. simpletable VALUES (?,?)");
– Setting parameters and adding each batch1. stmt.setInt(1, 1);
2. stmt.setInt(2, 3);
3. stmt.addBatch();
4. stmt.setInt(1, 2);
5. stmt.setInt(2, 4);
6. stmt.addBatch();
Using batches
– Executing the batch1. int[] results = stmt.executeBatch();
– Accessing the results1. for (int i = 0; i < results.length; i++) {
2. int j = results[i];
3. }
Managing transactions
– Usually transactions are autocommited(each operation is a transaction)
– In order to avoid it, autocommit must beset to false1. conn.setAutoCommit(false);
Managing transactions
– In order to revert to the anterior state, theconnection can be rolled back1. conn.rollback();
– In any event for the data to be modified,the connection must be commited1. conn.commit();
More transactions
– More complex transactions can beimplemented by defining varioussavepoints1. Savepoint save = conn.setSavepoint();
– A connection can be rolled back to anydefined savepoint1. conn.rollback(save);
– After they are no longer needed,savepoints must be released1. conn.releaseSavepoint(save);
SQL escape syntax
– When writing SQL queries as simplestrings, the syntax must be that of theparticular DBMS
– JDBC has a mechanism through whichmore general, DBMS independent queriescan be written
– Sql escape syntax defines general functionswhich are then translated by the driver
– Escaped sequences are written between {}
Escape syntax examples
– Calling a procedure1. "{call my_stored_procedure ?, ?}"
– Defining a date1. "{d ‘2011-11-10'}"
– Calculating a function1. "{fn ucase('alfa')}"
Autogenerated keys
– Autogenerated keys are a common featureof DBMS's
– The reason is that it is impossible to get anunique key without multiple queries
– A few restrictions must be respected
• columns must be specified by name in theinsert statement
• the return generated keys option must be usedto configure the statement
Autogenerated keys
– Declaring a prepared statement capable ofretrieving keys1. stmt = conn.prepareStatement("INSERT INTO
2. simpleauto (content) VALUES
3. (?)",Statement.RETURN_GENERATED_KEYS);
– Retrieving the keys from a result set (eachkey is a row in the result set)1. ResultSet rs = stmt.getGeneratedKeys();
2. while (rs.next()) {
3. System.out.println(rs.getString(1));
4. }
Other topics
– Updateable results
– Result sets and cursors
– Retrieving database metadata
– Setting result set properties
– Setting connection properties
– Handling exceptions and warnings