Using JDBC for OR Mapping Connecting to databases in Java James Brucker
Accessing a Database in Java
Connecting to a Database in Java (1) <ul><li>Java provides a standard interface for connecting to different databases:  ja...
DriverManager java.sql.DriverManager getConnection(  ur l , username, passwd):  Connection <<interface>> Connection create...
Using DriverManager // Connect to a MySQL database named &quot;world&quot;  // on the server named &quot;dbserver&quot; st...
Connecting to a Database in Java (2) <ul><li>DriverManager must find a  registered  database driver. </li></ul><ul><li>Way...
Connecting to a Database in Java (3) <ul><li>DriverManager  will select a suitable driver for the URL from the list of reg...
Patterns Question DriverManager getConnection(  ur l , user, passwd) : Connection <<interface>> Connection createStatement...
Database URL String DB_URL = &quot; jdbc:mysql://dbserver:3306/world &quot;; The syntax of the database URL depends on the...
Database URL (2) Example:   These 4 URL refer to the same database String URL = &quot; jdbc:mysql://localhost:3306/world &...
JDBC Driver You can download a JDBC driver (network connector) for almost any database, such as MySQL, PostgreSQL, Oracle,...
Installing and Using a Driver <ul><li>The Java Runtime must be able to  find  your driver! </li></ul><ul><li>Same rules ap...
Exercise <ul><li>Download the  mysql-connector-*.jar  file  </li></ul><ul><ul><li>use http://se.cpe.ku.ac.th/download/mysq...
Executing SQL Commands <ul><li>To execute an SQL command, use the  Connection  object to create an SQL  Statement  object....
Executing SQL Queries <ul><li>A statement.executeQuery( ) returns a ResultSet. </li></ul><ul><li>ResultSet is a scrollable...
ResultSet Methods <ul><li>ResultSet  contains one &quot;row&quot; for each result returned from the query. </li></ul><ul><...
ResultSet Methods <ul><li>A  ResultSet  contains one &quot;row&quot; for each result returned from the query.  Indices sta...
ResultSet Methods for Getting Data <ul><li>ResultSet &quot;get&quot; methods return column data: </li></ul><ul><li>getLong...
ResultSet and Type Compatibility <ul><li>SQL data types don't exactly match Java data types. </li></ul><ul><li>See Java AP...
How to Execute SQL Commands <ul><li>The Statement interface defines many execute methods: </li></ul><ul><li>Resultset rs =...
Parameters in PreparedStatement <ul><li>PreparedStatement uses placeholders for data values. </li></ul>PreparedStatement  ...
Create a Class to Manage DB Connection <ul><li>Create DBManager with a static factory method </li></ul>DBManager -  connec...
Simple version of DBManager (1) public class DBManager { // literal constants in Java code is baaad. // we will change to ...
Simple version of DBManager (2) private static Connection makeConnection( ) { try  {   // load the database driver class  ...
Simple version of DBManager (3) public class DataAccessException  extends RuntimeException { public DataAccessException(St...
How to Write the DAO <ul><li>Write the DAO using an O-R mapping framework: </li></ul><ul><ul><li>Hibernate, TopLink, or iB...
The World Application <ul><li>Insert class diagram or ER diagram </li></ul>
CityDao for World Application CityDao findById( code: string ): City findByName(name: String ): City[*] find( query: Strin...
CityDao using JDBC (1) public class CityDao { private static final Logger logger = ...;  // log4J private static final Cou...
CityDao using JDBC (2) /** find cities using a general query, use a   *  WHERE ..., HAVING ..., or other selection clause ...
CityDao using JDBC (3) /** convert a ResultSet entry to a City object */ private  City resultSetToCity(ResultSet rs)  thro...
CityDao using JDBC (4) // add this city to the cache if  ( !  cache .containsKey(id) )  cache .put(id, city); // now get r...
Why CityDao Needs a Cache <ul><li>What if the application requests cityDao.find(&quot;Bangkok&quot;) </li></ul><ul><li>two...
CityDao: delete public   boolean  delete( City city ) { if  ( city ==  null  || city.getId() ==  null  )  return   false ;...
CityDao: save and update public   boolean  save( City city ) { Long  id = city.getId( );  if  (  id  ==  null  )  this is ...
UI /** prompt for a city name and display city info */ private   void  citySearch( ) { out .print( &quot;Input name of cit...
UI search for country  <ul><li>private   void   countrySearch() { </li></ul><ul><li>out .print( &quot;Input name of countr...
Exercise <ul><li>Finish the CityDao and CountryDao. </li></ul><ul><li>Write JUnit tests to verify they are correct. </li><...
Use a Configuration File <ul><li>Purpose: </li></ul><ul><li>Configuration data such as database URL, username, password, s...
Loading Properties <ul><li>The  java.util.Properties  class can read or write &quot;properties&quot; files in this format....
Use Properties in DBManager public class DBManager { private void makeConnection( ) { Properties  properties =  PropertyMa...
Properties Filename is a property, too <ul><li>Use a System property to get  configuration file name . </li></ul>// get na...
java.util.Properties (a HashTable) Properties p = new Properties( ) create new java.util.Properties object String value = ...
System Properties <ul><li>String value = System.getProperty( name ) </li></ul><ul><li>get a system property </li></ul><ul>...
Details of Statement and ResultSet
Understanding  statement  objects <ul><li>A  Statement  object is tied to a  Connection . </li></ul><ul><li>Use an re-use ...
Understand ResultSet <ul><li>ResultSet is tied to a statement and a database connection. </li></ul><ul><ul><li>if statemen...
Using ResultSet to update a database <ul><li>Specify  ResultSet.CONCUR_UPDATABLE  when creating Statement. </li></ul><ul><...
RowSet <ul><li>RowSet  is like  ResultSet , but... </li></ul><ul><li>data not tied to database connection. </li></ul><ul><...
RowSet Question <ul><li>Suppose part of your application is expecting a  ResultSet , but you change the lower layers to re...
JTable <ul><li>Swing object looks like a spreadsheet table. </li></ul>A JTable
JTable Class Diagram <ul><li>JTable displays data returned by a TableModel. </li></ul>JTable TableModel describes data in ...
Design a TableModel for Queries <ul><li>Design a TableModel to manage a ResultSet </li></ul>JTable ResultSetTableModel Res...
Implementing TableModel <ul><li>ResultSet  contains some of the data we need. </li></ul><ul><li>class ResultSetTableModel ...
Implementing TableModel (2) <ul><li>ResultSet  is missing some information. </li></ul><ul><ul><li>public int getColumnCoun...
ResultSet Meta-data <ul><li>ResultSet  has a  getMetaData( )  method that returns a  ResultSetMetaData  object.  </li></ul...
Closing the Connection <ul><li>It is advisable to close Connection object when done.  This frees resources and ensures dat...
Connection Sharing <ul><li>A database connection consumes resources. </li></ul><ul><li>All instances can share the same Co...
Let the IDE build your Country Class <ul><li>public   class   Country  { </li></ul><ul><li>private  String  name ; </li></...
Summary <ul><li>JDBC specifies standard interfaces for communicating with different databases. </li></ul><ul><li>To use JD...
Important Design Concepts <ul><li>JDBC specifies standard  interfaces  for databases.  Any database can use JDBC by writin...
Learning More <ul><li>Sun Java Tutorial:  JDBC Database Access </li></ul><ul><li>Java API for the java.sql package: </li><...
Resources <ul><li>MySQL </li></ul><ul><li>http://dev.mysql.com/ </li></ul><ul><li>Learning SQL </li></ul><ul><li>http://ww...
Resources <ul><li>SQL Explorer for Eclipse </li></ul><ul><li>http://sourceforge.net/projects/eclipsesql </li></ul><ul><li>...
Upcoming SlideShare
Loading in …5
×

30 5 Database Jdbc

2,376 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,376
On SlideShare
0
From Embeds
0
Number of Embeds
16
Actions
Shares
0
Downloads
107
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

30 5 Database Jdbc

  1. 1. Using JDBC for OR Mapping Connecting to databases in Java James Brucker
  2. 2. Accessing a Database in Java
  3. 3. Connecting to a Database in Java (1) <ul><li>Java provides a standard interface for connecting to different databases: java.sql.Connection </li></ul><ul><li>Each database type requires its own driver that implements this interface. </li></ul><ul><ul><li>MySQL driver </li></ul></ul><ul><ul><li>Derby driver </li></ul></ul><ul><ul><li>Oracle driver ... </li></ul></ul><ul><li>Driver and related files are usually bundled in a jar file, e.g. mysql-connector-java-3.0.14-bin.jar </li></ul><ul><li>The DriverManager manages the selection of a driver and creating a connection. </li></ul>
  4. 4. DriverManager java.sql.DriverManager getConnection( ur l , username, passwd): Connection <<interface>> Connection createStatement(): Statement close( ) isClosed( ): boolean getCatalog( ): String MySqlConnection DriverManager finds the most suitable Connection class based on the URL that you give it. creates
  5. 5. Using DriverManager // Connect to a MySQL database named &quot;world&quot; // on the server named &quot;dbserver&quot; static final String DB_URL = &quot; jdbc:mysql://dbserver/world &quot;; static final String USER = &quot; student &quot;; static final String PASSWORD = &quot; secret &quot;; java.sql.Connection connection ; try { // load Driver for our database Class.forName( &quot;com.mysql.jdbc.Driver&quot; ) ; connection = DriverManager.getConnection( DB_URL, USER, PASSWORD ) ; } catch ( SQLException sqle ) { handle SQL exception } catch ( ClassNotFoundException e ) { handle the exception - driver class not found }
  6. 6. Connecting to a Database in Java (2) <ul><li>DriverManager must find a registered database driver. </li></ul><ul><li>Ways to make your driver available are: </li></ul><ul><li>Load the driver class in your program: </li></ul><ul><li>Class.forName(&quot; com.mysql.jdbc.Driver &quot;); </li></ul><ul><li>Add the driver to the jdbc.drivers property </li></ul><ul><li>System.setProperty(&quot; jdbc.drivers &quot;, </li></ul><ul><li>&quot; com.mysql.jdbc.Driver &quot;); </li></ul><ul><li>Specify jdbc.drivers property on command line: </li></ul><ul><li>java -D jdbc.drivers =&quot; com.mysql.jdbc.Driver &quot; ... </li></ul>
  7. 7. Connecting to a Database in Java (3) <ul><li>DriverManager will select a suitable driver for the URL from the list of registered JDBC drivers. </li></ul><ul><ul><li>it uses the &quot;sub-protocol&quot; field of the database_url . </li></ul></ul><ul><li>getConnection returns a Connection object that you use to communicate with the database. </li></ul>Connection connection = DriverManager. getConnection ( &quot; jdbc:mysql://host/database &quot;, &quot; username &quot;, &quot; password &quot; );
  8. 8. Patterns Question DriverManager getConnection( ur l , user, passwd) : Connection <<interface>> Connection createStatement(): Statement close( ) isClosed( ): boolean getCatalog( ): String MySqlConnection creates What design pattern is used by DriverManager? HSQLConnection
  9. 9. Database URL String DB_URL = &quot; jdbc:mysql://dbserver:3306/world &quot;; The syntax of the database URL depends on the specific driver (this is not good). The general format is: Protocol Sub-protocol Hostname Port DatabaseName <ul><li>The port number is the TCP port where the database server is listening for connection. </li></ul><ul><ul><li>3306 is the default port for MySQL </li></ul></ul><ul><li>Use hostname &quot;localhost&quot; for the local machine. </li></ul>
  10. 10. Database URL (2) Example: These 4 URL refer to the same database String URL = &quot; jdbc:mysql://localhost:3306/world &quot;; String URL = &quot; jdbc:mysql://localhost/world&quot;; String URL = &quot; jdbc:mysql:///world&quot;; String URL = &quot; jdbc:mysql:/world&quot;; The hostname and port are optional. For MySQL driver: defaults are localhost and port 3306
  11. 11. JDBC Driver You can download a JDBC driver (network connector) for almost any database, such as MySQL, PostgreSQL, Oracle, ... 4 Types of JDBC drivers: Type 1 : JDBC-to-ODBC bridge driver for Microsoft ODBC. Java JDBC includes the bridge driver: sun.jdbc.odbc.JdbcOdbcDriver. Type 2 : Native-API driver (written in C or C++ using JNI) Type 3 : Pure Java client-to-server driver, use a standard network protocol. The server translates requests to server-specific protocol. Type 4 : Pure Java drivers implementing a database-specific network protocol. Java programs can connect directly to the database.
  12. 12. Installing and Using a Driver <ul><li>The Java Runtime must be able to find your driver! </li></ul><ul><li>Same rules apply as using other runtime jar files. </li></ul><ul><ul><li>add as an external jar file to your IDE project </li></ul></ul><ul><ul><ul><li>easiest: let the IDE manage classpath </li></ul></ul></ul><ul><ul><li>add the path to the driver to your CLASSPATH CLASSPATH = /my/path/mysql-connector.jar </li></ul></ul><ul><ul><li>add to CLASSPATH using the Java command line: java -cp /my/path/mysql-connector.jar ... </li></ul></ul><ul><ul><li>Put driver in the JRE/lib/ext directory, e.g. C:/java/jre1.6.0/lib/ext/ mysql-connector.jar </li></ul></ul>
  13. 13. Exercise <ul><li>Download the mysql-connector-*.jar file </li></ul><ul><ul><li>use http://se.cpe.ku.ac.th/download/mysql </li></ul></ul><ul><ul><li>or, http://www.mysql.com </li></ul></ul><ul><li>Install it in a convenient directory. </li></ul>
  14. 14. Executing SQL Commands <ul><li>To execute an SQL command, use the Connection object to create an SQL Statement object. </li></ul><ul><li>Statement interface defines methods for executing commands. </li></ul>// createStatement( ) can accept parameters for options Statement statement = connection.createStatement( ) ; // execute an UPDATE command int count = statement.executeUpdate ( &quot; UPDATE City SET population=100000 WHERE name='Bangsaen' &quot; ); System.out.println(&quot;Modified &quot; + count + &quot; records&quot;);
  15. 15. Executing SQL Queries <ul><li>A statement.executeQuery( ) returns a ResultSet. </li></ul><ul><li>ResultSet is a scrollable set of values. </li></ul>Statement statement = connection .createStatement (); // execute a SELECT command ResultSet rs = statement .executeQuery ( &quot;SELECT * FROM Country WHERE population>1000000&quot; ); rs.first() ; // scroll to first result do { String name = rs . getString (1); // get by position int population = rs . getInt (&quot;population&quot;); // by name ... } while( rs.next() );
  16. 16. ResultSet Methods <ul><li>ResultSet contains one &quot;row&quot; for each result returned from the query. </li></ul><ul><li>ResultSet contains get methods for column data: </li></ul><ul><ul><li>&quot;get&quot; by column number -- starts at 1 (not 0)! </li></ul></ul><ul><ul><li>&quot;get&quot; by column name -- field names in table/query. </li></ul></ul>String query = &quot;SELECT * FROM Country WHERE ...&quot; ; ResultSet rs = statement . executeQuery ( query ); // go to first row of results rs.first( ) ; // display the values System.out.println( rs.getString ( 1 ) ); System.out.println( rs.getInt ( &quot; population &quot; ) ); get by column number get by name
  17. 17. ResultSet Methods <ul><li>A ResultSet contains one &quot;row&quot; for each result returned from the query. Indices start from 1 (not 0)! </li></ul>go to next row of results. &quot;false&quot; if no more. go to previous row. &quot;false&quot; if 1st result. go to first row of results. go to last row of results. go to k-th row of results. get int value of field &quot;name&quot; get int value of k-th column in a record ResultSet next() : boolean previous() : boolean first() : boolean last() : boolean absolute( k ) getInt( name: String ) getInt( index: int ) ...
  18. 18. ResultSet Methods for Getting Data <ul><li>ResultSet &quot;get&quot; methods return column data: </li></ul><ul><li>getLong ( 3 ) : get by column index (most efficient) </li></ul><ul><li>getLong ( &quot; population &quot; ) : get by field name (safest) </li></ul>getInt( ), getLong( ) - get Integer field value getFloat( ), getDouble() - get floating pt. value getString( ) - get Char or Varchar field value getDate( ) - get Date or Timestamp field value getBoolean( ) - get a Bit field value getBytes( ) - get Binary data getBigDecimal( ) - get Decimal field as BigDecimal getBlob( ) - get Binary Large Object getObject( ) - get any field value
  19. 19. ResultSet and Type Compatibility <ul><li>SQL data types don't exactly match Java data types. </li></ul><ul><li>See Java API and JDBC tutorial for conversion rules. </li></ul>For all compatibilities, see: /tutorial/jdbc/basics/retrieving.html int pop1 = rs.getInt( &quot; population &quot; ); long pop2 = rs.getLong( &quot; population &quot; ); // float - int conversion is possible, too float area = rs.getFloat( &quot; surfacearea &quot; ); // convert char(n) to String String region = rs.getString( &quot; region &quot; );
  20. 20. How to Execute SQL Commands <ul><li>The Statement interface defines many execute methods: </li></ul><ul><li>Resultset rs = statement. executeQuery (&quot;sql query&quot;); </li></ul><ul><ul><li>use for statements that return data values (SELECT) </li></ul></ul><ul><li>int count = statement. executeUpdate (&quot;update ...&quot;); </li></ul><ul><ul><li>use for INSERT, UPDATE, and DELETE </li></ul></ul><ul><li>boolean b = statement. execute (&quot;statements&quot;); </li></ul><ul><ul><li>use to execute any SQL statement(s) </li></ul></ul>
  21. 21. Parameters in PreparedStatement <ul><li>PreparedStatement uses placeholders for data values. </li></ul>PreparedStatement pstmt = connection. prepareStatement ( &quot;SELECT * FROM Country where name = ?&quot; ); // get data for Thailand pstmt .setString( 1, &quot;Thailand&quot;); ResultSet rs = pstmt.executeQuery ( ); saveResultSetAsObject( rs, country1 ); // get data for Laos pstmt .setString( 1, &quot;Laos&quot;); rs = pstmt.executeQuery ( ); saveResultSetAsObject( rs, country2 ); PreparedStatement will quote the string value for you.
  22. 22. Create a Class to Manage DB Connection <ul><li>Create DBManager with a static factory method </li></ul>DBManager - connection : Connection +getConnection( ) : Connection +close( ) : void // example how to use Statement statement = DBManager.getConnection().createStatement( ) ;
  23. 23. Simple version of DBManager (1) public class DBManager { // literal constants in Java code is baaad. // we will change to a configuration file later. private static String JDBC_DRIVER=&quot; com.mysql.jdbc.Driver &quot;; private static String url = &quot; jdbc:mysql://hostname/world &quot;; private static String user = &quot; student &quot;; private static String password = &quot; student &quot;; /* a single shared database connection */ private static Connection connection = null ; /* log4J logging object */ static Logger logger = Logger.getLogger(DBManager.class); private DBManager() { /* no object creation */ }
  24. 24. Simple version of DBManager (2) private static Connection makeConnection( ) { try { // load the database driver class Class. forName ( JDBC_DRIVER ); connection = DriverManager. getConnection ( url , user, password ); } catch ( SQLException sqle ) { logger.error(&quot;connection error&quot;, sqle); throw new DataAccessException( ... ); } catch ( ClassNotFoundException cnfe ) { .... } /* the public accessor uses lazy instantiation */ public static Connection getConnection( ) { if ( connection == null ) connection = makeConnection(); return connection; }
  25. 25. Simple version of DBManager (3) public class DataAccessException extends RuntimeException { public DataAccessException(String arg) { super(arg); } } <ul><li>Catch, Log, and rethrow any exception. </li></ul><ul><li>Necessary to avoid NullPointerException or SQLException in app. </li></ul><ul><li>Translate low-level exception into higher layer exception </li></ul><ul><li>What is a DataAccessException? </li></ul><ul><li>translate checked exceptions into unchecked exception to simplify code. </li></ul>
  26. 26. How to Write the DAO <ul><li>Write the DAO using an O-R mapping framework: </li></ul><ul><ul><li>Hibernate, TopLink, or iBatis </li></ul></ul><ul><ul><li>Java Persistence API provider, like OpenJPA </li></ul></ul><ul><ul><li>write your own O-R mapping using JDBC </li></ul></ul><ul><li>Apache Cayenne has a GUI modeler that lets you specify O-R mapping visually; can reverse engineer or create database schema and Java code. No XML files or annotations. </li></ul>
  27. 27. The World Application <ul><li>Insert class diagram or ER diagram </li></ul>
  28. 28. CityDao for World Application CityDao findById( code: string ): City findByName(name: String ): City[*] find( query: String ) : City[*] save( Country ) : boolean delete( Country ) : boolean <ul><li>The primary key is an integer city ID. </li></ul><ul><li>Search by name is used in our application, so I add a method for it. </li></ul>
  29. 29. CityDao using JDBC (1) public class CityDao { private static final Logger logger = ...; // log4J private static final CountryDao cityDao; private static HashMap<Long,City> cache = ...; /** retrieve a city by its id */ public City findById( Long id ) { if ( cache.containsKey(id) ) return cache.get(id); List<City> list = find(&quot; WHERE id = &quot;+id); return list.get(0); } /** retrieve a city by name */ public List<City> findByName( String name ) { name = sanitize( name ); List<City> list = find(&quot; WHERE name = ' &quot;+name+&quot; ' &quot;); return list; }
  30. 30. CityDao using JDBC (2) /** find cities using a general query, use a * WHERE ..., HAVING ..., or other selection clause */ public List<City> find( String query ) { List<City> list = new ArrayList<City>( ); Statement statement = DBManager.getStatement( ); String sqlquery = &quot;SELECT * FROM city c &quot; + query; try { logger .debug( &quot;executing query: &quot; + sqlquery ); ResultSet rs = statement.executeQuery( sqlquery ); while ( rs.next() ) { City c = resultSetToCity( rs ); list.add( c ); } } catch ( SQLException sqle ) { logger .error( &quot;error executing: &quot; +sqlquery, sqle); } finally { DBManager.closeStatement( statement ); } return list; }
  31. 31. CityDao using JDBC (3) /** convert a ResultSet entry to a City object */ private City resultSetToCity(ResultSet rs) throws SQLException { City city = null ; Long id = rs.getLong( &quot;id&quot; ); // is this city already in cache? if so, use it if ( cache.contains(id) ) city = cache.get(id); else city = new City(); city.setId(id); city.setName( rs.getString( &quot;Name&quot; ) ); city.setDistrict( rs.getString( &quot;District&quot; ) ); city.setPopulation( rs.getInt( &quot;Population&quot; ) ); String countrycode = rs.getString( &quot;countrycode&quot; );
  32. 32. CityDao using JDBC (4) // add this city to the cache if ( ! cache .containsKey(id) ) cache .put(id, city); // now get reference to the country this city refers logger .info( &quot;get country for city &quot; +city.getName() ); Country country = countryDao .findById( countrycode ); city.setCountry( country ); return city; }
  33. 33. Why CityDao Needs a Cache <ul><li>What if the application requests cityDao.find(&quot;Bangkok&quot;) </li></ul><ul><li>two times? </li></ul><ul><li>We should return the same object each time. </li></ul><ul><li>Necessary to avoid infinite loops: </li></ul><ul><ul><li>cityDao uses JDBC and gets data for Bangkok </li></ul></ul><ul><ul><li>the countrycode for Bangkok is &quot;THA&quot;. cityDao must convert this to a country object reference. </li></ul></ul><ul><ul><li>cityDao calls countryDao.findById( &quot;THA&quot; ) </li></ul></ul><ul><ul><li>countryDao finds Thailand, and the capital city has a cityID = 3320. It must convert this to a city reference. </li></ul></ul><ul><ul><li>countryDao calls cityDao.findById( 3320 ) </li></ul></ul><ul><ul><li>cityDao uses JDBC and gets data for Bangkok again </li></ul></ul><ul><ul><li>repeat step 2. </li></ul></ul>
  34. 34. CityDao: delete public boolean delete( City city ) { if ( city == null || city.getId() == null ) return false ; Long id = city.getId( ); Statement statement = DBManager. getStatement ( ); int count = 0; if ( statement == null ) return false ; String query = &quot;DELETE FROM city WHERE id=&quot; + id; try { count = statement.executeUpdate( query ); } catch ( SQLException sqle ) { logger .error( &quot;error executing: &quot; +query, sqle ); } finally { DBManager.closeStatement( statement ); } // is city in the cache? if ( cache.containsKey(id) ) cache.remove( id ); return count > 0; }
  35. 35. CityDao: save and update public boolean save( City city ) { Long id = city.getId( ); if ( id == null ) this is a new city, save it ; else { if ( cache.containsKey( id ) ) this city is already in database, update it else this city is not in the database, save it but check that no other city has this id } We can use save( ) for both saving a new object and updating an existing object.
  36. 36. UI /** prompt for a city name and display city info */ private void citySearch( ) { out .print( &quot;Input name of city: &quot; ); String name = in .next().trim(); // run the query City city = cityDao .findByName( name ); if ( city == null ) { out .println( &quot;Sorry, no match or query error&quot; ); } else { out .println(&quot;Name: &quot;+city.getName( ) ); out .println(&quot;District: &quot;+city.getDistrict( ) ); out .println(&quot;Country: &quot; +city.getCountry( ).getName( ) ); ... } }
  37. 37. UI search for country <ul><li>private void countrySearch() { </li></ul><ul><li>out .print( &quot;Input name of country: &quot; ); </li></ul><ul><li>String name = in .next().trim(); </li></ul><ul><li>// perform the query </li></ul><ul><li>List<Country> results = countyDao .findByName( name ); </li></ul><ul><li>if ( results == null ) ... // failed </li></ul><ul><li>for ( Country country : results ) { </li></ul><ul><li>out .printf( &quot;Name: %s &quot; , country.getName() ); </li></ul><ul><li>out .printf( &quot;Capital: %s &quot; , country.getCapital() ); </li></ul><ul><li>out .printf( &quot;Region: %s &quot; , country.getRegion() ); </li></ul>
  38. 38. Exercise <ul><li>Finish the CityDao and CountryDao. </li></ul><ul><li>Write JUnit tests to verify they are correct. </li></ul><ul><li>What happens if you enter invalid country name? </li></ul>
  39. 39. Use a Configuration File <ul><li>Purpose: </li></ul><ul><li>Configuration data such as database URL, username, password, should be in a file not in the Java code . </li></ul><ul><li>Put this data in a configuration file. </li></ul><ul><li>Example : world.config </li></ul># World database properties jdbc.url=jdbc:mysql://localhost/world user=student password=secret jdbc.drivers=com.mysql.jdbc.Driver
  40. 40. Loading Properties <ul><li>The java.util.Properties class can read or write &quot;properties&quot; files in this format. (can also write XML). </li></ul>// get name of the configuration file String config = &quot; world.config &quot;; // allow user to change this: java -dworld.config=... config = System.getProperty(&quot;world.config&quot;, config ); // load the properties Properties properties = new Properties( ); try { FileInputStream fis = new FileInputStream( config ); properties.load( fis ) ; fis.close( ); } catch ( FileNotFoundException e ) { ... }
  41. 41. Use Properties in DBManager public class DBManager { private void makeConnection( ) { Properties properties = PropertyManager.getProperties() ; String jdbc_driver = properties.getProperty (&quot;jdbc.drivers&quot;); String url = properties.getProperty (&quot;jdbc.url&quot;); // pass all remaining properties to DriverManager // including user and password properties try { class.forName( jdbc_driver ); connection = DriverManager.getConnection(url, properties ); } catch ( SQLException sqle ) { log exception and rethrow as DataAccessException } catch ( FileNotFoundException e ) { ...
  42. 42. Properties Filename is a property, too <ul><li>Use a System property to get configuration file name . </li></ul>// get name of the configuration file String configfile = System. getProperty ( &quot;world.config&quot; ); if ( configfile == null ) configfile = DEFAULT_CONFIG_FILE; C> java -D world.config =c:/temp/config.txt world.jar This enables user to change the filename at runtime:
  43. 43. java.util.Properties (a HashTable) Properties p = new Properties( ) create new java.util.Properties object String value = p.getProperty( name ) get a named property; returns null if not found. String value = p.getProperty( name, default_value ) get a property, returns default_value if not found.
  44. 44. System Properties <ul><li>String value = System.getProperty( name ) </li></ul><ul><li>get a system property </li></ul><ul><li>Properties p = System.getProperties( ) </li></ul><ul><li>get all the system properties </li></ul>
  45. 45. Details of Statement and ResultSet
  46. 46. Understanding statement objects <ul><li>A Statement object is tied to a Connection . </li></ul><ul><li>Use an re-use a statement object for many database commands. </li></ul><ul><li>If the Connection is closed, the statement object is invalid (disconnected). </li></ul><ul><li>Statement object consumes resources </li></ul><ul><ul><li>close it when you are finished </li></ul></ul>Statement statement = connection.createStatement(); statement .executeQuery( &quot;SELECT * FROM ... &quot; ); ... statement .close( );
  47. 47. Understand ResultSet <ul><li>ResultSet is tied to a statement and a database connection. </li></ul><ul><ul><li>if statement or connection is closed, results are gone </li></ul></ul><ul><ul><li>if another command is executed, results are gone </li></ul></ul><ul><li>ResultSet can change (!) after performing the query </li></ul><ul><li>ResultSet can update a database </li></ul>Statement stmt = connection.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE , ResultSet.CONCUR_UPDATABLE ); ResultSet rs = statement.executeQuery( query );
  48. 48. Using ResultSet to update a database <ul><li>Specify ResultSet.CONCUR_UPDATABLE when creating Statement. </li></ul><ul><li>Requires (a) support by database driver, (b) UPDATE privilege on tables </li></ul>// rs is scrollable, will not show changes made // by others, and will be updatable Statement statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE ); ResultSet rs = statement.executeQuery( query ); rs.next(); int population = rs.getInt(&quot; population &quot;); // add 10,000 to the population rs. updateInt ( &quot; population &quot;, population+10000 ); rs. updateRow ( );
  49. 49. RowSet <ul><li>RowSet is like ResultSet , but... </li></ul><ul><li>data not tied to database connection. </li></ul><ul><li>can be cached. </li></ul><ul><li>can be updated by a re-connection to database </li></ul><ul><li>can store other kinds of data, such as from a file or spreadsheet </li></ul><<interface>> ResultSet <<interface>> RowSet <<interface>> CachedRowSet <<interface>> WebRowSet
  50. 50. RowSet Question <ul><li>Suppose part of your application is expecting a ResultSet , but you change the lower layers to return a RowSet instead. </li></ul><ul><li>Do the upper layers of the application need to change? </li></ul><<interface>> ResultSet <<interface>> RowSet <<interface>> CachedRowSet <<interface>> WebRowSet
  51. 51. JTable <ul><li>Swing object looks like a spreadsheet table. </li></ul>A JTable
  52. 52. JTable Class Diagram <ul><li>JTable displays data returned by a TableModel. </li></ul>JTable TableModel describes data in the table AbstractTableModel getColumnCount( ) : int getColumnName( index ) : String getColumnClass( index ) : Class getRowCount( ) : int getValueAt( row, col ) : Object
  53. 53. Design a TableModel for Queries <ul><li>Design a TableModel to manage a ResultSet </li></ul>JTable ResultSetTableModel ResultSetTableModel(statement) runQuery( query : String ) AbstractTableModel getColumnCount( ) : int getColumnName( index ) : String getColumnClass( index ) : Class getRowCount( ) : int getValueAt( row, col ) : Object
  54. 54. Implementing TableModel <ul><li>ResultSet contains some of the data we need. </li></ul><ul><li>class ResultSetTableModel { </li></ul><ul><li>private Statement statement; </li></ul><ul><li>private ResultSet rs ; </li></ul><ul><ul><li>public Object getValueAt(int row, int col) { </li></ul></ul><ul><ul><li>if ( rs == null ) return null; </li></ul></ul><ul><ul><li>rs .absolute( row + 1 ); </li></ul></ul><ul><ul><li>rs .getObject( col ); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>public int getRowCount() { </li></ul></ul><ul><ul><li>if ( rs == null ) return 0; </li></ul></ul><ul><ul><li>rs .last(); // move to last row </li></ul></ul><ul><ul><li>rowCount = rs .getRow(); </li></ul></ul><ul><ul><li>return rowCount ; </li></ul></ul><ul><ul><li>} </li></ul></ul>
  55. 55. Implementing TableModel (2) <ul><li>ResultSet is missing some information. </li></ul><ul><ul><li>public int getColumnCount( ) { </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>public String getColumnName( int col ) { </li></ul></ul><ul><ul><li>} </li></ul></ul>
  56. 56. ResultSet Meta-data <ul><li>ResultSet has a getMetaData( ) method that returns a ResultSetMetaData object. </li></ul><ul><li>ResultSetMetaData describes the ResultSet. </li></ul>try { ResultSet resultSet = statement. executeQuery ( query ); ResultSetMetaData metadata = resultSet. getMetaData (); int numberOfColumns = metadata .getColumnCount(); for(int col=1; col<=numberOfColumns; col++) { // get name and SQL datatype for each column String name = metadata . getColumnName ( col ); int type = metadata . getColumnType ( col ); int typeName = metadata . getColumnTypeName ( col ); } catch( SQLException sqle ) { ... }
  57. 57. Closing the Connection <ul><li>It is advisable to close Connection object when done. This frees resources and ensures data integrity. </li></ul>Connection connection = DriverManager.getConnection(...); /* use the database */ ... /* done using database */ public void close( ) { if ( connection == null ) return; try { connection .close(); } catch ( SQLException sqle ) { /* ignore it */ } finally { connection = null; } }
  58. 58. Connection Sharing <ul><li>A database connection consumes resources. </li></ul><ul><li>All instances can share the same Connection object. </li></ul><ul><li>To enforce this use the Singleton Pattern : </li></ul><ul><ul><li>use a factory method to get connection </li></ul></ul><ul><ul><li>the method always returns the same instance of the connection </li></ul></ul>
  59. 59. Let the IDE build your Country Class <ul><li>public class Country { </li></ul><ul><li>private String name ; </li></ul><ul><li>private String continent ; </li></ul><ul><li>private String region ; </li></ul><ul><li>private float surfaceArea ; </li></ul><ul><li>private long population ; </li></ul><ul><li>private float lifeExpectancy ; </li></ul><ul><li>private long gnp ; </li></ul><ul><li>private String governmentForm ; </li></ul><ul><li>private String capital ; </li></ul><ul><li>/** auto-generated constructor </li></ul><ul><li>public Country(String name,... </li></ul><ul><li>{ </li></ul><ul><li>this . name = name; </li></ul><ul><li>this . continent = continent; </li></ul>Eclipse: Source menu
  60. 60. Summary <ul><li>JDBC specifies standard interfaces for communicating with different databases. </li></ul><ul><li>To use JDBC you need a JDBC or ODBC driver for the database. </li></ul><ul><li>The application must load a database-specific driver. DriverManager will choose driver when creating a Connection. </li></ul><ul><li>a Connection object manages the connection to a database. </li></ul><ul><li>a Statement object is used to submit database statements and get results. </li></ul><ul><li>A query returns a ResultSet containing data and meta-data. </li></ul><ul><li>A ResultSet can be read-only or updateable depending on the Statement object (specified in Statement constructor). </li></ul><ul><li>properly close a Statement or Connection when finished to release resources and ensure data integrity. </li></ul>
  61. 61. Important Design Concepts <ul><li>JDBC specifies standard interfaces for databases. Any database can use JDBC by writing classes that implement these interfaces. </li></ul><ul><li>To re-use a connection in different classes, use the Singleton Pattern and a Factory Method for getting the connection object. </li></ul><ul><li>Use a finally clause on try - catch blocks to ensure that some code is always executed. Inside the try - catch, you must not use 'return' since this would bypass the &quot;finally&quot; clause. Use 'break'. </li></ul>
  62. 62. Learning More <ul><li>Sun Java Tutorial: JDBC Database Access </li></ul><ul><li>Java API for the java.sql package: </li></ul><ul><ul><li>DriverManager </li></ul></ul><ul><ul><li>Connection </li></ul></ul><ul><ul><li>Statement </li></ul></ul><ul><ul><li>ResultSet </li></ul></ul><ul><ul><li>ResultSetMetaData </li></ul></ul><ul><ul><li>DatabaseMetaData (describes the database) </li></ul></ul>
  63. 63. Resources <ul><li>MySQL </li></ul><ul><li>http://dev.mysql.com/ </li></ul><ul><li>Learning SQL </li></ul><ul><li>http://www.w3schools.com/sql/ nice tutorial and command reference </li></ul><ul><li>Learning JDBC </li></ul><ul><li>JDBC Trail in Sun's Java Tutorial . </li></ul><ul><li>Dietel, Java How To Program , Chapter 25. </li></ul><ul><li>... and zillions of resources on the web </li></ul>
  64. 64. Resources <ul><li>SQL Explorer for Eclipse </li></ul><ul><li>http://sourceforge.net/projects/eclipsesql </li></ul><ul><li>http://www.onjava.com/pub/a/onjava/2005/05/11/sqlexplorer.html </li></ul>

×