MELJUN CORTES Jedi course notes web programming-lesson5-sql and jdbc


Published on

MELJUN CORTES Jedi course notes web programming-lesson5-sql and jdbc

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

MELJUN CORTES Jedi course notes web programming-lesson5-sql and jdbc

  1. 1. Database Connectivity: SQL and JDBC IntroductionMost web applications are connected to some form of external storage in order to driveits dynamic content. This storage often takes the form of a relational database, becauseof its simplicity and the ease by which users can extract related data.This extraction of data from a relational database is accomplished through the use ofSQL, or Structured Query Language. This language defines a syntax and severalkeywords which can be understood by the database system. Most relational databasesystems provide a client program through which SQL commands can be entered, and itsresults displayed to the user. However, web applications cannot interface to thedatabase using these programs.The JDBC API which comes as part of the J2EE platform provides developers a standard,programmatic way of interfacing with relational database systems. By making use of thisAPI, developers can issue SQL queries and make use of its results to generate dynamiccontent for the end client. Relational DatabasesRelational databases are the storage medium of choice for many web based applicationsthat require dynamic content. The basic syntax needed to retrieve and manipulate datathat it stores is easy to pick up. Currently, it also has widespread industry support, inthat there are plenty of options available, with little to no shortage of technical resourcesthat can be retrieved from the Internet.As implied by its name, relational databases store data as related sets of information.Relational groupings are expressed as tables. Each table contains columns that definethe properties of each data set stored within it.This concept can be visualized by the following example: userid name address contactnum 14627895 Duke California 0924562788 65248987 Kimi Finland 8687243217 Figure 1: Sample TableIn this example, we have a table that is used to store user information. The table definesfour columns: a userID column which stores an id that uniquely defines a user, a namecolumn, address, and contact number column. Each row in the table represents a singledata entry. This means that there is a user named Duke whose address is at SunMicrosystems with so-and-so userid and so-and-so contactnum.Actual tables in a database system are not as simple as the one above. Database tables
  2. 2. are usually designed with logical constraints so as to preserve the consistency of itsdata. One such constraint is the assignation of data types: each column is defined to beof a specific data type. The system automatically rejects the insertion of new data sets ifone or more of its column entries does not match the data type specified. For example,the userid column may be defined internally to be of an integer datatype. Inserting newrows which contains characters for its value for the userid column will cause the insertionto fail. Another constraint usually imposed on a table is that of uniqueness: if a column isdefined to be unique, the system will not allow the insertion of a new data set whichcontains a value already existing in the system.The mechanics of table design is beyond the scope of this discussion, and will be left formore comprehensive resources. This discussion will focus, instead, on the mechanics ofdata access and modification in a given database table. SQL StatementsAs previously mentioned, operations on relational databases are accomplished throughthe use of SQL. There are several types of SQL statements, though only two of these willbe covered in this chapter. Data RetrievalThis type of SQL statement focuses on reading data from one or more tables in thedatabase. Queries of this type can either be left open-ended to retrieve ALL data setswithin a specified table (or group of tables), or they can be parameterized such thatknown column values are supplied and data sets are retrieved such that they satisfy thegiven conditions.There is only one SQL statement that falls within this type: the SELECT statement. SELECT STATEMENTA SELECT statement is used to query the database about information which the databasereturns as a set of rows.The basic format of a SELECT statement is:SELECT column(s) FROM tablename WHERE condition(s)In the syntax above, SELECT, FROM, and WHERE are SQL keywords, while columns,tablename, and conditions are values supplied by the developer. • SELECT - marks the start of the SELECT statement • column(s) - the name of the column whose value will be retrieved. If more than one column is to be retrieved, the column names are separated by commas. If all available columns are to be retrieved, an asterisk (*) is used instead of actual column names. • Multiple column name values -> SELECT userid, name, address FROM ... • Retrieving all columns -> SELECT * FROM ... • FROM - an SQL keyword that is used to indicate the table from which the data is to be retrieved. A mechanism for retrieving data from multiple tables is included
  3. 3. within the language. This will later be discussed in more detail. • WHERE - an optional keyword that specifies conditions that must be fulfilled by data entries before they can be included as a result. More than one condition can be specified; in that case, each condition is separated by either an AND or OR keyword that performs the same as their logical equivalent. Other possible kinds of conditions allowed will be touched on later.The FROM clauseThe FROM clause in a SELECT statement defines the table(s) from which the data set willbe gathered. If the data comes from only one table, then that tables name is simplysupplied. However, if the data needed comes from more than one table, an operationknown as table join needs to be performed.Table joins can be performed several ways: User UserDownloadsuserid name address contactnum userid downloaditem downloaddate San Courseware14627895 Duke 0924562788 14627895 Dec. 19, 2005 Francisco Notes65248987 Kimi Finland 8687243217 36542036 Exercises Feb. 11, 200684321874 Dante San Jose 6365498428 84321874 Slides March 13, 2006 • By listing all the tables to join, separated by commas. While this is the simplest to do, it also ranks the lowest in terms of performance. What it does is perform a Cartesian product on the tables, resulting in a large, unwieldy table. • Example: Given two tables users, and userdownloads, join is performed by: ... FROM users, userdownloads [WHERE ...]If simple comma-delimitation was used, the following would be the result: userid name address contactnum userid downloaditem downloaddate San14627895 Duke 0924562788 14627895 Courseware Dec. 19, 2005 Francisco San14627895 Duke 0924562788 36542036 Exercises Feb. 11, 2006 Francisco San14627895 Duke 0924562788 84321874 Slides March 13, 2006 Francisco Courseware65248987 Kimi Finland 8687243217 14627895 Dec. 19, 2005 Notes65248987 Kimi Finland 8687243217 36542036 Exercises Feb. 11, 200665248987 Kimi Finland 8687243217 84321874 Slides March 13, 2006 Courseware84321874 Dante San Jose 6365498428 14627895 Dec. 19, 2005 Notes
  4. 4. 84321874 Dante San Jose 6365498428 36542036 Exercises Feb. 11, 200684321874 Dante San Jose 6365498428 84321874 Slides March 13, 2006 • By using one of several JOIN keywords. General syntax is table1 JOIN table2 on condition. Condition specifies which rows on both tables to join together. • LEFT JOIN - Performs similar to JOIN, except that all entries in table1 is applied to the join, even if some rows do not fit the condition.Using the LEFT JOIN on this tables, with the condition that User.userid =UserDownloads.userid:userid name address contactnum userid downloaditem downloaddate San14627895 Duke 0924562788 14627895 Courseware Dec. 19, 2005 Francisco65248987 Kimi Finland 868724321784321874 Dante San Jose 6365498428 84321874 Slides March 13, 2006 • RIGHT JOIN - Performs similar to JOIN, except that all entries in table2 is applied to the join, even if some rows dont fit the condition.Using the RIGHT JOIN on this table, with the same condition:userid name address contactnum userid downloaditem downloaddate San14627895 Duke 0924562788 14627895 Courseware Dec. 19, 2005 Francisco 36542036 Exercises Feb. 11, 200684321874 Dante San Jose 6365498428 84321874 Slides March 13, 2006 • INNER JOIN - Only entries in both tables that match the condition are considered for the join.Using INNER JOIN on this table, with the same condition:userid name address contactnum userid downloaditem downloaddate San14627895 Duke 0924562788 14627895 Courseware Dec. 19, 2005 Francisco84321874 Dante San Jose 6365498428 84321874 Slides March 13, 2006In most cases, an INNER JOIN yields the most relevant results for join operations.However, in cases where the entries of one table should appear no matter what, a LEFTJOIN or RIGHT JOIN is more appropriate. Avoid using the comma-delimited join as muchas possible. While it is simpler and more convenient to write, the performance hitincurred in its usage makes the time investment of writing a proper join worth it.The WHERE clause
  5. 5. The WHERE clause in a SELECT statement specifies a condition that must be matched byentries in the selected table in order for them to appear in the result. There are severaloperators that can be used to specify a condition: • = - Checks for equality between two given operands. • <=, < - Checks if the first operand is less than equal to, or less than the 2nd operand. • >=, > - Checks if the first operand is greater than equal to, or greater than the 2nd operand. • like - Performs a string comparison between two operands. Using this operation, two wildcard characters can be used to represent unknown values. • % - Matches any string of any length. Ex. A%s will match any string starting with A and ending in s. • _ - Matches any single character string. Ex. b_t will match bot, but, bit, bat, and bet.The following are simple examples on the use of SELECT statement. • In retrieving all available data on the users table: SELECT * from users; • In looking for the addresses of users with a name of Smith, the SQL statement would look like: SELECT address from users where name =Smith; • In retrieving entries for all users with a name starting with S, we could make use of the like operator: SELECT * from users where name like S%;SQL is not case-sensitive about the developers use of its keywords. However, it IS case-sensitive with regards to values it performs comparisons on. The following statement willreturn a different set of data compared to the one above: SELECT * from users where name =sMith; Data ManipulationStatements under this type are used to modify the state of data in the database. Thereare several such statements, each catering to a specific data manipulation need. . INSERT STATEMENTINSERT statements are used to insert new rows of information in existing databasetables.INSERT INTO table-name VALUES(value1, value2, ...)Above is the basic structure of an INSERT statement where table-name is the name ofthe table which will contain the new data row. The parameter given inside the VALUESkeyword is a comma-delimited list of values that will be added into the table. In caseslike this where only the table is specified, SQL associates the values given in thestatement with the fields inside the database based on the ordering the values weregiven and the ordering of the fields in the database table.
  6. 6. For example, a table called user, with fields userid, name, address (in that order), thefollowing line will add a new entry to the table:INSERT INTO users VALUES(199700651, Jedi Master, UP Ayala Technopark);It is important to note that any call to INSERT must follow the integrity rules as definedin the data table. That is, if a field in a database is defined to be non-null, any attemptto insert a null-value into that field will cause an error in the database. . UPDATE STATEMENTThe UPDATE statement simply updates existing rows in a table, as opposed to theINSERT statement that adds entirely new rows.UPDATE table-name set column-value(s) WHERE condition(s)Above is the basic format of the UPDATE statement where table-name is the name of thetable which contains the rows to update, and column-values is a comma-delimited list ofcolumn name and value pairs. Optionally, a comma-delimited list of conditions can beadded to specify which rows in the table are to be modified. If conditions are not given,the updates are applied to each row in the specified table.Any updates must conform to data integrity rules in the database. For example, settingto null a column defined to be NOT NULL will result in the non-execution of thestatement and an error message from the relational database. . DELETE STATEMENTThe DELETE statement removes a row from a specified table.DELETE FROM table-name WHERE condition(s)Above is how a basic DELETE statement looks like where table-name is the name of thetable containing the rows to be deleted. A comma-delimited list of conditions canoptionally be specified, as well. If no conditions are given, the statement will delete allrows in the specified table. JDBCJava provides a standard API for accessing databases called the Java DatabaseConnectivity (JDBC) API. Using this , developers can access databases no matter whothe vendor may be; the vendors provide the implementations to the abstract interfacesdefined in the API, providing the same set of functionality to the developer.The following are key classes in the JDBC API, all of which well cover in more detaillater: • java.sql.Connection – represents a connection with the database. Also, it abstracts the details of how to communicate with the database server. • java.sql.DriverManager – manages JDBC drivers used by the application. In conjunction with the proper driver URL and proper authentication, it can provide
  7. 7. applications with valid instances of Connection objects. • javax.sql.DataSource – abstracts the details (URL, authentication details) of how to obtain a connection to the database. It is newer and more preferred method of obtaining Connection objects. • java.sql.Statement – provides methods for the developer to execute SQL statements. • java.sql.ResultSet – represents the results of an SQL statement. These objects are usually returned from methods in the Statement object. java.sql.DriverManagerUsing this class, a developer can retrieve a Connection object which he then can use toperform database activities. There are two steps required: • First, the JDBC driver must first be registered with the DriverManager. This can be done by using the Class.forName method to load the drivers class definition into memory. • Second, use the getConnection method in the DriverManager supplying a JDBC URL, as well as the username and password authenticated for database access. The URL must follow the syntax required by the particular database implementation.Below is a sample of how to get a Connection from a PostgreSQL database. Again, theURL and driver is specific to the database implementation being used. For otherdatabases, check the documentation provided.String jdbcURL = "jdbc:postgresql://localhost:5432/jedi-db";String user = "jedi";String password = "j3d1master";Connection conn = null;try { Class.forName("org.postgresql.Driver"); conn = DriverManager.getConnection(url, user, password); ...} catch (SQLException e) {// perform error handling here}While this is a valid way of retrieving a Connection object, this method requires thedeveloper to keep track of such details as the driver class name, the URL required fordatabase access, and the username and password cleared for database usage. Thesedetails are the ones most likely to change per deployment of the application. Also,managing the URL and driver name in the code makes it harder for the application toswitch database implementations, if it becomes necessary. javax.sql.DataSourceDataSource is an interface defined in the JDBC API since version 2 of its specification.Nowadays, it is also the recommended way for a developer to get a Connection object.Retrieval of the Connection object is very straightforward: simply call the
  8. 8. getConnection() method in a valid instance of DataSource. It is obtaining an instance ofDataSource that can now pose a problem for some developers.Since DataSource is an interface, an instance cannot simply be created by the developerusing the new operator. It is recommended that the application server be left to managethe creation of DataSource objects. Doing so allows the application server to add usefulfunctionality such as connection pooling in a manner that is transparent to both thedeveloper and the end user. . Configuring DataSource in Sun Application Server 8.1Each server has its own procedure for configuring and managing DataSources. What wewill discuss would be the procedure for doing so in the container we have been using sofar for our examples: Sun Application Server 8.1.There are three steps in setting up the datasource for AppServer 8.1: • Registering the JAR file containing the JDBC driver with the container. • Creating a connection pool to the database • Registering a datasource that makes use of a connection pool.Registering the JAR fileThe first step would be to access the admin console for the server. By default, the adminconsole can be accessed by entering the URL, http://localhost:4848/, in the browseraddress bar.In case a different port number was configured for your admin console during installtime, simply replace 4848 with the port number.After supplying the security credentials needed to access the console, a new screen willappear. To proceed, click on Application Server in the left pane, then click on the JVMsettings tab on the pane to the right.In the screen that would appear next, select the Path Settings tab on the pane to theright. A screen similar to the one below will appear.Scroll down until you encounter a text area labeled Classpath suffix. Input the pathleading to the JAR file containing the JDBC drivers.Creating a connection poolTo start creating a connection pool, click on the JDBC link on the pane to the left, thenclick Connection Pools on the pane to the right.In the screen that will appear next, click on the New... button to bring up a displaysimilar to the one below:
  9. 9. Figure 2: Creating a Connection PoolUnder the Name field, enter the name by which this connection pool will be known.Under the Resource Type drop-down, select javax.sql.DataSource. Leave the DatabaseVendor drop-down blank, as PostgreSQL is not included in the list of vendors.Click Next, then when prompted for the datasource class name, enter:org.postgresql.jdbc3.Jdbc3PoolingDataSource. Click Next to continue.In the next screen, scroll down until you see the properties to be associated with thisconnection pool.The following parameters need to have values supplied: • Password • ServerName • PortNumber • DatabaseName • UserAfter supplying all of the above values, click on the Finish button.Registering the Datasource
  10. 10. To start registering a datasource, click on the JDBC link found on the left pane, then clickon JDBC Resources. In the screen that follows, click on New ...The fields are to be filled as follows: • JNDI Name – enter the logical name from which the application will retrieve the DataSource. It is recommended that this name have jdbc/ as its prefix to make it easier for future server administrators to identify this element as a JDBC resource. • Pool name – select the name of the connection pool created earlier. • Description – enter text describing the DataSource (optional).Click on OK to finish. . Retrieving the DataSourceRetrieving an instance of a DataSource from an application server is simple and can beaccomplished using only a few lines of code using a portion of the JNDI API. JavaNaming Directory Interface (JNDI) is the Java standard API for accessing directories. Adirectory is a centralized location where Java applications can retrieve external resourcesusing a logical name.Additional details for JNDI and how it works is beyond the scope of this lesson. The onlything that we need to know is that application servers maintain a directory to which itwill publish the DataSource that we configured earlier. Our application can then performa simple name lookup on that directory to retrieve the resource.For our purposes, it is enough for us to create a JNDI context using the defaultconstructor. This JNDI context abstracts the details of connecting to the directory,making resource lookup as simple as calling a single method. Take note that the nameused to lookup the resource must be the same name used in configuring the DataSource....Context ctxt = null;DataSource ds = null;try {// create an instance of the JNDI context to which we will perform lookupsctxt = new InitialContext();// retrieve the DataSource from the directory using a logical nameds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS");} catch (NamingException ne) {System.err("Specified DataSource cannot be found");}Once we have a valid DataSource instance, getting a Connection object is as simple asConnection conn = ds.getConnection();
  11. 11. java.sql.Connection / java.sql.StatementThe java.sql.Connection objects represent actual connections to the database. Once wehave an instance of this object, we can create an instance of a Statement object, whichwe can then use to perform SQL queries.The Statement object provides a number of methods to execute SQL queries. The twomost used are: • executeQuery – takes in SELECT statements and returns the result of the operation as a ResultSet object. • executeUpdate – takes in INSERT, UPDATE, or DELETE statements and returns the number of rows affected as an integer primitive.Below is a piece of sample code outlining the procedure:Context ctxt = null;DataSource ds = null;Connection conn = null;Statement stmt = null;ResultSet rs = null;try {ctxt = new InitialContext();ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS");conn = ds.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");} catch (NamingException e) {System.err("Cannot find named datasource");} catch (SQLException se) {System.err("Error occurred while performing query");} java.sql.ResultSetA ResultSet object encapsulates the results of a query to the database. The data inside aResultSet object can best be visualized as a table. The information can then be retrievedone row at a time, with the ResultSet object keeping track of which row is current.To iterate over the rows exposed in the ResultSet, it provides us with a method callednext(). Calling the next() method moves the internal pointer the ResultSetobject keeps to point to the next row. This method returns true if there is a next rowto be found, and false if there are no more rows left.
  12. 12. while ( {//read data from current row here} Figure 3: Sample of ResultSet iterationTo retrieve the data from each row, the ResultSet object provides us with a number ofget methods. There is a getString method for retrieving the data as a String, a getIntmethod for retrieving integer data, getBoolean for retrieving boolean data, etc. In allcases, these methods take in, as a parameter, either the column number of the columncontaining the data, or the column name. It is recommended however, that names beused to specify a column to read from instead of a row number. This makes theapplication easier to maintain, as it is possible that the column ordering might bechanged sometime after initial development.Context ctxt = null;DataSource ds = null;Connection conn = null;Statement stmt = null;ResultSet rs = null;try {ctxt = new InitialContext();ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS");conn = ds.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");while ( {String userName = rs.getString("name");String address = rs.getString("address");int userID = rs.getInt("userid");// perform operations on retrieved data here.}} catch (NamingException e) {System.err("Cannot find named datasource");} catch (SQLException se) {System.err("Error occurred while performing query");} Releasing system resourcesOne very important step that is often overlooked is the releasing of database resourcesafter an operation has been completed. This must be done explicitly and is theresponsibility of the programmer. Without performing such a release, the resourcestaken up by our operation can NOT be used in the future. For large-scale applications,this can rapidly result in loss of available connections.
  13. 13. The release of resources can be performed by calling on the close() methods availableon each of the Connection, Statement, and ResultSet objects. There is a specific orderinvolved: the ResultSet must be closed first, then the Statement, and finally theConnection object. Since the close method in each of those objects is defined to throwan SQLException, enclose the call within a try-catch block.A mistake that many developers make is to simply place the close methods within theprogram body. Here is an example:Context ctxt = null;DataSource ds = null;Connection conn = null;Statement stmt = null;ResultSet rs = null;try {ctxt = new InitialContext();ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS");conn = ds.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");while ( {String userName = rs.getString("name");String address = rs.getString("address");int userID = rs.getInt("userid");// perform operations on retrieved data here.}rs.close();stmt.close();conn.close();} catch (NamingException e) {System.err("Cannot find named datasource");} catch (SQLException se) {System.err("Error occurred while performing query");}The problem with this approach is that it only addresses success conditions. On caseswhere an exception has occurred within the code, the system resources will still NOT beproperly released. A better way of doing this would be to place the release code within afinally clause, to ensure that it happens no matter what.A proper example is presented below:Context ctxt = null;DataSource ds = null;Connection conn = null;
  14. 14. Statement stmt = null;ResultSet rs = null;try {ctxt = new InitialContext();ds = (DataSource)ctxt.lookup("jdbc/PostgreSQLDS");conn = ds.getConnection();stmt = conn.createStatement();rs = stmt.executeQuery("SELECT * FROM users");while ( {String userName = rs.getString("name");String address = rs.getString("address");int userID = rs.getInt("userid");// perform operations on retrieved data here.}} catch (NamingException e) { System.err("Cannot find named datasource");} catch (SQLException se) { System.err("Error occurred while performing query");} finally { try { if (rs != null) { rs.close(); } } catch (SQLException e) {} try { if (stmt != null) { stmt.close(); } } catch (SQLException e) {} try { if (conn != null) { conn.close(); } } catch (SQLException e) {}}The checks for null are necessary just in case an error condition occurred before one ormore of the objects have been given proper instances. Each close method should also bein a separate try-catch clause to ensure that an error caused in an attempt to close oneobject does not skip on the attempt to close the others. Summary • Obtain a Connection object either by using the DriverManager or by obtaining it
  15. 15. from a DataSource object (recommended). • Create a Statement object using the createStatement() method available in the Connection object. • Perform SQL queries using the Statement object and retrieve the results. • If the result of a query is a ResultSet object, iterate over the rows by repeatedly calling the next method while retrieving the data in each row. • Close all database related objects.EXERCISE1) Consider the following table: USERS userid gender firstname lastname login password14627895 M Jose Saraza jsaraza Asdfrewq16765248987 M Rosario Antonio rantonio qwer467952317568 F Milagros Paguntalan mpaguntalan ukelllll372324489 M Frank Masipiquena fmasipiquena Df23efzsxf2341Create the necessary SQL statements that will perform the following:a) Retrieve all male users.b) Retrieve all users with a first name starting with F.c) Change the login name for the entry with a userid of 65248987 into rtonio.d) Delete all female entries.e) Insert the following entry into the table:userid gender firstname lastname login password69257824 F Anne Sacramento asacramento k1lasdoj24f2) Create a LoginHandler class. It must contain a method with the following signature: public boolean isUserAuthorized(String loginName, String password)Inside the method body, create an implementation that would connect to the sampledatabase, and check against the users table whether an entry exists that has the samelogin and password as given in the parameters. Use the DriverManager class to obtain aconnection to the database.3) Create a servlet named UserEntryServlet that will service the following form:<HTML> <BODY> <table> <form action="UserEntryServlet" method="post"> <tr> <td>User ID:</td> <td><input type="text" name="userID"/></td> </tr> <tr> <td>First name</td> <td><input type="text" name="firstName"/></td> </tr>
  16. 16. <tr> <td>Last name</td> <td><input type="text" name="lastName"/></td> </tr> <tr> <td>Login name</td> <td><input type="text" name="loginName"/></td> </tr> <tr> <td>Password</td> <td><input type="text" name="userID"/></td> </tr> </table> </form></HTML>Using the values given in the form, insert a new entry into the users table in the sampledatabase. To connect to the database, configure the Application Server to handle adatasource.4) Create a servlet named UserRemovalServlet that will expect a parameter named"userID". Delete the entry in the database corresponding to that entry.