Chapter 6. Spring Data

Data persistence and retrieval are inevitable operations in an enterprise world. The advent of JDBC paved the way to interact with multiple databases with ease and comfort. JDBC techlogies have gained popularity in no time because of their unified API to access any database, be it MySQL or Oracle or Sybase or any Relational Database System.

Spring took one step ahead and created an even lighter framework, abstracting the JDBC behind the scenes. Although the JDBC and Spring marriage makes a happy family, there are some unsophisticated or unavailable features from the joint venture. One feature that comes to mind is the support for Object Relational mappings. We still have to write plain old SQL statements to access the data from persistent stores. This is the opportunity Hibernate grabbed and became an instant hit! With millions of downloads over the time, it is now a popular and powerful open source framework. Spring added more abstraction on top of the already powerful Hibernate to make it even better.

This chapter explains how the Spring Framework can be used effectively for accessing databases, without even having to worry about connections and statements. We then continue on to Spring’s ORM support, using Hibernate.

JDBC and Hibernate

The joint venture did not attempt to bridge the gap between Objects and Relational Data. JDBC is certainly one of the first-hand choices for a Java developer when working with databases. JDBC abstracts away the intricacies involved in accessing different databases. It gives a clear and concise API to do the job easily.

As many developers who worked with JDBC will moan about, there is a lot of redundant or boilerplate code that needs to be written (or cut and pasted!), even if our intention is to fetch a single row of data.

The Spring Framework has changed this scenario drastically. Using a simple template pattern, Spring has revolutionized database access, digesting the boilerplate code altogether into itself. We do not have to worry about the unnecessary bootstrapping and resource management code or ugly exceptions. We are at last able to do what we have been employed to do—write just the business logic. We will see in this chapter how the framework has achieved this objective.

There is a second scenario to consider: we often wish to work with relational entities as if they are objects in your code. As relational entities differ from Java Objects, unless there is a bridge between them, this wish will not be fulfilled.

The good news that there are softwares built to manage this gap—simply called as Object Relational Mapping (ORM) frameworks. Hibernate, Java Data Objects (JDO), iBatis, and TopLink belong to this category. Using these ORM tools, we do not have to work at a low level as exposed by JDBC; instead we manipulate the data as objects.

For example, a table called MOVIES consists of many rows (Movies). The analogue to this relational entity would be modeled as a Movie object in our code, and the mapping of the MOVIE row to Movie domain object is performed by the framework behind the scenes.

Spring JDBC

We can agree that JDBC is a simple API for data access. However, when it comes to coding, it is still cumbersome, as we still have to write unnecessary, rudimentary code. Some say that about 80 percent of the code is repetitious. In a world of reusabiltiy, this is unacceptable. Spring does exactly this—abstracts away all the resource management so we can concentrate on the meat of the application. It might not surprise you to know that Spring “reuses” its template design pattern, allowing us to interact with the databases in a clean and easy manner. The core of the JDBC package revolves around one class: JdbcTemplate. This class plays the key role in accessing data from our components.

JdbcTemplate

The basic and most useful class from the framework is the JdbcTemplate. This call should serve to do most of your work. But should you require a bit more sophistication, the two variants of JdbcTemplate—the SimpleJdbcTemplate and NamedParameterJdbcTemplate—should provide you that.

The JdbcTemplate class provides the common aspects of database operations, such as inserting and updating data, using prepared statements, querying tables by using standard SQL queries, invoking stored procedures, and so on. It can also iterate over the ResultSet data efficiently and effectively.

The connection management is hidden from the user, and so is the resource pooling and exception management. Regarding the exceptions, one does not have to clutter the code with try-catch blocks because the database-specific exceptions are wrapped under covers by Spring’s Runtime Exceptions.

As always inline with the template design pattern, the JdbTemplate provides callback interfaces for us to implement our business logic. For example, PreparedStatementCallback is used for creating PreparedStatements, while RowCallbackHandler is where you extract the ResultSet into your domain objects. The CallableStatementCallback is used when executing a stored procedure. We will work briefly with these callbacks in the next few sections.

Configuring JdbcTemplate

Before we can jump into working with the JdbcTemplate, we need to take care of a few details about its creation. First, we need to supply a DataSource to the JdbcTemplate so it can configure itself to get database access. As we have seen in the previous chapter (JMS), just as ConnectionFactory was the gateway to a JMS Provider, so is the DataSource the gateway to our Database. It supplies the connection information which is used by the JdbcTemplate to get access to the underlying databse.

You can configure the DataSource in the XML file as shown in the following code snippet. I am using an open source JDBC framework—Apache commons DBCP—for creating my datasources.

<bean id="movieDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close">
  <property name="driverClassName" value="${jdbc.driver}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

Once we have the datasource created, our next job is to create the JdbcTemplate.

We have primarily two options: First, we can instantiate a JdbcTemplate in our Data Access Object (DAO), injecting the DataSource into it. Alternatively, we can define the JdbcTemplate in the XML file, wiring the datasource to it, and then injecting the JdbcTemplate reference into the DAO class. The following snippet uses this second option:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="movieDataSource"/>
</bean>

<bean id="movieDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
  destroy-method="close">
  ....
</bean>

The JdbcTemplate is a threadsafe object once configured, so you can inject it into any number of DAOs.

Let’s define the DAO for accessing the MOVIES database. The following snippet shows this class:

public class MovieDAO implements IMovieDAO {
  private JdbcTemplate jdbcTemplate = null;
  
  private void setJdbcTemplate(JdbcTemplate jdbcTemplate){
    this.jdbcTemplate = jdbcTemplate;
  }
  
  private JdbcTemplate getJdbcTemplate() {
    return this.jdbcTemplate;
  }
  ...
}

The IMovieDAO is the interface that has all the movie-related functionality which is shown here:

public interface IMovieDAO {
  public Movie getMovie(String id);
  public String getStars(String title);
  public List<Movie> getMovies(String sql);
  public List<Movie> getAllMovies();
  public void insertMovie(Movie m);
  public void updateMovie(Movie m);
  public void deleteMovie(String id);
  public void deleteAllMovies();
}

The MovieDAO has JdbcTemplate as a member variable. It is configured and wired with a datasource in the XML file and injected into our concrete DAO. The wiring XML file is shown here:

<bean id="movieDao" class="com.madhusudhan.jscore.data.MovieDAO">
  <property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
 
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="movieDataSource"/>
</bean>

<bean id="movieDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
  destroy-method="close">
  ....
</bean>

Here is a snippet of the MovieDAO class.

public class MovieDAO implements IMovieDAO {
  private JdbcTemplate jdbcTemplate = null;
  
  private void setJdbcTemplate(JdbcTemplate jdbcTemplate){
    this.jdbcTemplate = jdbcTemplate;
  }
  
  private JdbcTemplate getJdbcTemplate() {
    return this.jdbcTemplate;
  }
  ...
}

That’s it! Your JdbcTemplate is configured and ready to be used straightaway. Let’s concentrate on what we can do with the template in our hand.

Using JdbcTemplate

The simplest operation is to fetch movie actors using a criteria such as a movie title. We can write a simple SQL query like select stars from MOVIES to retrieve the movie actors.

Our MovieDAO has a method getStars() that takes a title and returns comma-separated stars list. The snippet here shows the implementation of this query:

@Override
public String getStars(String title) {
 
  String stars = getJdbcTemplate().
    queryForObject("select stars from MOVIES where title='"+ title +"'",
                String.class);
  return stars;
}

The query was executed using queryForObject method on JdbcTemplate. This method takes two parameters, a SQL query without bind variables and an expected type of the result.

The expected result is a comma-separated stars list. We can improve this query by parameterizing the query. The where clause will have a bind variable that will change on queries. It is shown in the listing here:

@Override
public String getStars(String title) {
  
  // using where clause
  String stars = getJdbcTemplate().
    queryForObject("select stars from MOVIES where title=?", 
      new Object[]{title}, String.class);

  return stars;
}

Here, ideally the second argument is passed via method arguments.

There are plenty of queryForXXX methods defined on the JdbcTemplate, such as queryForInt, queryForList, queryForMap, and so on. Please refer to the Spring Framework’s API to understand the workings of these various methods.

Returning domain objects

The previous queries returned a single piece of data, movie stars, as we have seen in that case.

How can we retrieve a single row, say a Movie object for a given an id? The JdbcTemplate’s queryForObject method comes handy for such requirement. One additional thing we need to do is to pass a RowMapper instance.

The JDBC API returns a ResultSet, and we need to map each and every column of data from the ResultSet onto our domain objects. The Spring framework eliminates this repetitious process by providing the RowMapper interface.

Simply put, RowMapper is an interface for mapping table rows to a domain object. It has one method called mapRow that should be implemented by the concrete classes.

What we need to do is implement this interface to map our table columns to a Movie object. Let’s implement a row mapper for our Movie domain object—see the snippet here:

public class MovieRowMapper implements RowMapper {
  Movie movie = null;
  public Object mapRow(ResultSet rs, int rowNum) throws SQLException{
    movie = new Movie();
    // This is where we extract data 
    // from ResultSet and set it on Movie object
   
    movie.setID(rs.getString("id"));
    movie.setTitle(rs.getString("title"));
    ...
    return movie;
  
  }
} 

Basically, the idea is to extract the relevant columns from the ResultSet and populate our Movie domain object and return it.

Now that our MovieRowMapper is implemented, use jdbcTemplate to retrieve the results.

@Override
public Movie getMovie(String id){

  String sql = "select * from MOVIES where id=?";

  return getJdbcTemplate().queryForObject(sql, 
    new Object[]{id},new MovieRowMapper());
}

The JdbcTemplate executes the query by binding the argument and invoking the MovieRowMapper with a returned ResultSet from the query.

We need to enhance this logic a bit more to get all the movies (as a list) instead of a single movie result.

We can use the same MovieRowMapper for returning all the movies. However, it should be wrapped in a RowMapperResultSetExtractor as shown here:

public List getAllMovies(){
  RowMapper mapper = new MovieRowMapper();
  String sql = "select * from MOVIES";
  
  return getJdbcTemplate().query(sql, 
    new RowMapperResultSetExtractor(mapper,10));
}

Manipulating data

We can use the jdbcTemplate.update() method to insert, update, or delete the data. The following code shows the insertion of Movie into our database.

@Override
public void insertMovie(Movie m) {
  String sql = "insert into MOVIES (ID, TITLE, GENRE, SYNOPSIS) 
    values(?,?,?,?)";

  // The insert parameters
  Object[] params = new Object[] { m.getID(), m.getTitle(), m.getGenre(), 
m.getSynopsis() };

  // The insert parameters types
  int[] types = new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, 
Types.VARCHAR };

  // Run the query
  jdbcTemplate.update(sql, params, types);
}

The second and third parameters indicate the input values and their respective types.

Similarly, deleting a single movie from the database is straightforward:

@Override
public void deleteMovie(String id) {
  String sql = "delete from MOVIES where ID=?";
  Object[] params = new Object[] { id };
  jdbcTemplate.update(sql, params);
}

In order to delete all movies, use the following code:

@Override
public void deleteAllMovies(){
  String sql = "delete from MOVIES";
  jdbcTemplate.update(sql);
}

Calling stored procedures is also an easy thing, using the update method:

public void deleteAllMovies(){
  String sql = "call MOVIES.DELETE_ALL_MOVIES";
  jdbcTemplate.update(sql);
}

As we have noticed, the JdbcTemplate has eased our burden in accessing the database dramatically. I advise you to refer to Spring’s API for more such methods on the template class.

Hibernate

Hibernate provides a mapping of database columns to the objects by reading some configurations. We define the mapping of our domain objects to the table columns in the XML configuration file.

The configuration file for each of the mappings should have an extension of .hbm.xml. Spring abstracts the framework one step more and provides us with classes like HibernateTemplate to access the database. However, Spring advocates to drop HibernateTemplate in favour of using Hibernate’s native API.

We’ll look into details in a minute, but first let’s see how we can prepare the required configurations.

For example, let’s define our MOVIE object by using hibernate mapping rules.

<hibernate-mapping>
  <class name="com.madhusudhan.jscore.data.Movie" table="MOVIES">
  <id name="id" column="ID">
    <generator class="assigned"/>
  </id>
  <property name="title" column="TITLE"/>
  <property name="genre" column="GENRE"/>
  <property name="synopsis" column="SYNOPSIS"/>
 </class>
</hibernate-mapping>

The class attribute defines the actual domain class, Movie in this case. The id attribute is the primary key and is set as assigned, meaning it is the application’s responsibility to set the primary key. The rest of the properties are mapped against the respective columns on the MOVIES table.

Hibernate requires a Session object in order to access the database. A Session is created from the SessionFactory. When using Spring framework, you can use Spring’s LocalSessionFactoryBean to create this SessionFactory. The LocalSessionFactoryBean requires a datasource to be wired in, along with hibernate properties and mapping resources.

The hibernateProperties attribute on the factory bean enables the database specific properties such as database dialect, pool sizes, and other options. The mappingResources property loads the mapping config files (Movie.hbm.xml, in our case).

<bean id="sessionFactory" 
  class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
  <property name="dataSource" ref="movieDataSource" />
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
      <prop key="hibernate.show_sql">false</prop>
    </props>
  </property>
  <property name="mappingResources">
    <list>
      <value>Movie.hbm.xml</value>
    </list>
  </property>
</bean>

Using old style HibernateTemplate

Now that the sessionFactory is defined, the next bit is to define HibernateTemplate. The HibernateTemplate requires a SessionFactory instance, so the following declaration wires the sessionFactory that we defined above.

<bean id="hibernateTemplate" 
  class="org.springframework.orm.hibernate.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="movieDao" 
  class="com.madhusudhan.jscore.data.MovieDAO">
  <property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>

That’s all—the configuration is completed. Let’s see how we get the data from our database.

The getMovie method shown here uses the template’s load method.

public Movie getMovie(String id){  
  //Searching for a movie
  return (Movie)getHibernateTemplate().load (Movie.class, id);
}

As you can see, there’s no SQL that retrieves a movie in this method. It feels like we are working with Java objects rather than data! The load method accesses the database to load the matching row based on the id passed.

Updating a Movie is simple as well:

public void updateMovie(Movie m){
  //Updating a movie
  getHibernateTemplate().update (m);
}

As you can see, the single statement above does the job! Deleting a row is as simple as invoking the delete method.

public void deleteMovie(Movie m){
  // Deleting a movie
  getHibernateTemplate().delete (m);
}

Running queries is straightforward, too. Hibernate introduces Hibernate Query Language (HQL) for writing queries. Use find methods to execute such queries.

For example, returning a Movie based on a ID is shown here:

public Movie getMovie(String id){
  String sql="from MOVIES as movies where movies.id=?";
  // Finding a movie
  return (Movie)getHibernateTemplate().find(sql, id);
}

That’s about using Hibernate from a very high ground. I strongly advise you to pick up any Hibernate book to understand in detail.

Preferred style—using native API

The recomended way to use Spring with Hibernate is to use Hibernate’s API rather than Spring’s template wrapper. The subject is provided at length in my other book Just Spring Data Access, so please go through it if you have the copy. For completness, let’s browse through this style quickly.

The Hibernates’s org.hibernate.SessionFactory and org.hibernate.Session forms the central part of the Hibernate API.

Spring provides a org.springframework.orm.hibernate3.LocalSessionFactoryBean to create a wrapper around the SessionFactory. This wrapper is then injected into our DAO object.

As expected, this bean should be wired in with a DataSource, along with other Hibernate properties. The configuration is almost same as the one shown earlier:

<bean id="sessionFactory" 
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
  <property name="dataSource" ref="mySqlDataSource" /> 
  <property name="mappingResources">
     <list> 
       <value>Trade.hbm.xml</value>
     </list>
   </property>
<property name="hibernateProperties">
  <props> 
   <prop key="hibernate.show_sql">false</prop> 
   <prop key="hibernate.hbm2ddl.auto">true</prop>
   ....
  </props>
</bean>

The TradeDAO, along with the injected SessionFactory, is declared here:

public class TradeDAO {
  private SessionFactory sessionFactory = null;
  public SessionFactory getSessionFactory() {
   return sessionFactory;
  }
  public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
  }
}

Once we have the handle to the SessionFactory, we can fetch a Session out of it by using getSessionFactory().getCurrentSession() method invocation. The session is the main interface that we should be using to do the database operations. For example, in order to persist the Trade, all we need to do is to call a save method on this session. This is shown here:

public void persist(Trade t) {
  session.beginTransaction();
  session.save(t);
  session.getTransaction().commit();
}

That’s it, you are done with persisting the trade—no messy SQL or ResultSets or RowMappers!

Note that each of these database operation should be carried in a transaction, hence we are surrounding our code by beginning a transaction and commiting the same.

There are a plethora of operations that you could carry out on the Session object—refer to the API to get more insight.

Summary

In this chapter, we discussed Spring’s support of JDBC and Hibernate. As we have seen in the examples, Spring has truly simplified our lives by providing a simple yet powerful API to work with. We can concentrate on the business logic rather than writing reams of repetitive code fragments.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.164.75