ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Migrating to Spring
Pages: 1, 2, 3

Changing the Data Tier: Spring JDBC

Configuring the custom DataSource was a matter of fancy XML work. Spring also provides base DAO classes to eliminate boilerplate JDBC code. That means the Spring framework takes care of connection management and closing ResultSets and PreparedStatements. What remains is my app-specific code.



The new DAO has the same interface as its predecessor:

package pool_test.data.jdbc ;

public class SimpleDAO {
  public void setupTable() ;
  public void putData() ;
  public Collection getData() ;
  public void destroyTable() ;
}

Under the hood, though, it's a different animal. Whereas the old version of the DAO had a lot of inline JDBC code, the new version offloads that grunt work to Spring:

package pool_test.data.jdbc ;

public class SimpleDAO extends JdbcDaoSupport {

  private GetDataWorker _getDataWorker ;
  private PutDataWorker _putDataWorker ;
  private CreateTableWorker _createTableWorker ;
  private DestroyTableWorker _destroyTableWorker ;

  // constructor is now empty

  protected void initDao() throws Exception {
    
    super.initDao() ;
    
    _getDataWorker =
      new GetDataWorker( getDataSource() ) ;

    _putDataWorker =
      new PutDataWorker( getDataSource() ) ;

    _createTableWorker =
      new CreateTableWorker( getDataSource() ) ;

    _destroyTableWorker =
      new DestroyTableWorker( getDataSource() ) ;

    return ;
    
  } // initDao()

  public void setupTable() {
    _createTableWorker.update() ;
  }

  public Collection getData() {
    return( _getDataWorker.execute() ) ;
  }

  // ... destroyTable() and getData()
  //   follow similar conventions ...

}

The first change is the parent class: SimpleDAO now extends Spring's JdbcDaoSupport, which has several methods and inner classes for database work. The first such method is setDataSource(), which assigns a JDBC DataSource to this object. Subclasses call getDataSource() to fetch this object.

initDao() is the next method inherited from JdbcDaoSupport. The parent class invokes this method to give its subclasses a chance to run any one-time initialization code. Here, SimpleDAO assigns values to its member variables.

The member variables are new, too: moving to Spring JDBC means moving SimpleDAO's functionality--fetching and storing data--to special inner classes such as GetDataWorker and PutDataWorker. There is one such inner class for each DAO action. For example, storing data is offloaded to PutDataWorker:

package pool_test.data.jdbc ;

import org.springframework ... SqlUpdate ;

public class SimpleDAO {

 ...
   private class PutDataWorker extends SqlUpdate {
    
     public PutDataWorker( final DataSource ds ){
      
       super( ds , SQL_PUT_DATA ) ;
    
       declareParameter(
             new SqlParameter( Types.VARCHAR ) ) ;
       declareParameter(
             new SqlParameter( Types.INTEGER ) ) ;

     }

     // a real app would load the SQL statements
     //   from an external source...
     private static final String SQL_PUT_DATA =
       "INSERT INTO info VALUES( ? , ? )" ;

   }

   ...

}

PutDataWorker extends SqlUpdate, a Spring template class that handles the grunt work of SQL INSERT and UPDATE calls. The declareParameter() calls tell Spring what data types the SQL statement will use--respectively a string and a number.

Notice, PutDataWorker is a very lean class. It calls super() to pass a DataSource and SQL statement to its parent class and declareParameter() to describe that query. SqlUpdate handles the real work of interacting with JDBC-related objects and closing connections. In turn, SimpleDAO.putData() is equally trim:

public class SimpleDAO {

  public void putData() {

    for( ... ){

      // ... "nameParam" and "numberParam" are
      // local loop variables ...

      Object[] params = {
        nameParam , // variable is a Java String 
        numberParam // some Java numeric type
      } ;

      _putDataWorker.update( params ) ;

    }
  }

}

putData() populates the database with some nonsense data. Notice that this method delegates to its worker class. Specifically, to an inherited method on its worker class. SqlUpdate.update() takes care of fetching the data, and closing the JDBC Connection and any relevant Statement objects. That means I can pitch a lot of my custom JDBC code, and even an entire class: the old DbUtil had convenience methods for closing Connections, Statements, and ResultSets.

What SqlUpdate does for update calls, Spring's MappingSqlQuery does for queries. Note the method mapRow() in GetDataWorker:

package pool_test.data.jdbc ;

import org.springframework ... MappingSqlQuery ;


// inside class SimpleDAO ...

private class GetDataWorker
  extends MappingSqlQuery {

  // ...constructor similar to PutDataWorker...
  
  protected Object mapRow( final ResultSet rs ,
       final int rowNum ) throws SQLException
  {
      
      final SimpleDTO result = new SimpleDTO(
        rs.getString( "names" ) ,
        rs.getInt( "numbers" )
      ) ;

      return( result ) ;
      
   } // mapRow()

}

This method takes care of translating the tabular ResultSet data into workable SimpleDTO objects, one row at a time. Spring calls this method for each row in the result set. While GetDataWorker.mapRow() interacts with the ResultSet, it isn't otherwise responsible for close()ing it or checking whether there are any rows left to process.

Pages: 1, 2, 3

Next Pagearrow