Spring Framework DB2

Tutorial: Spring Framework DB2

Setup To continue these tutorials, we need to do three things: make a bit of a change to the petstore database, download some new libraries, and install two new projects into Eclipse.

  Change the petstore database to enable foreign key constraints. We have designed our petstore so that the inventory table has a supplier column, which is intended to be the ID of one of the suppliers in the suppliers table. However, right now the database does not enforce this---you can enter any number you like for this field in inventory. We will rectify this situation by using foreign key constraints. Specifically, we will set up the database so that for any row in inventory, the supplier column must be equal to one of the id field of one of the rows of the suppliers</tt> table (in other words, the values of the supplier</tt> column are constrained by the "foreign key" that is the id</tt> column of the suppliers</tt> table). <ol> <li> Log into the database server and select your petstore database (remember, it will be named sahana2_username_petstore</tt>. </li> <li> Click on the "Structure" icon of the inventory</tt> table (the second icon from the left). </li> <li> Select the "Operations" tab. In the "Table options" box, set the Storage Engine to "InnoDB" and click on "Go." </li> <li> Repeat for the suppliers</tt> table. </li> <li> Go back to the "Operations" tab for inventory</tt> and click on the "Structure" icon.  In the row for "Supplier" click on the "Index" icon (should be the right-most enabled icon). </li> <li> Click on "Relation view."  On the drop-down menu for "Supplier" select "suppliers-&gt;ID" and click on "Save." </li> </ol> </li>

<li> Get the new libraries file, unpack it, and add the JAR files to the libs</tt> directory that you created in Part 1 of this tutorial. </li>

<li> Get the [[Media:db-tut2.zip]] file which contains two new projects: tutorial-db-spring-cleaning</tt> and tutorial-hibernate-spring</tt>. Load these two projects into your workspace as you did in Part 1 of the tutorial. For tutorial-db-spring-cleaning</tt>, link against mysql-connector-java-5.1.6-bin.jar</tt>, spring.jar</tt>, and commons-logging.jar</tt> (just as for tutorial-jdbc-spring</tt>). For <tt>tutorial-hibernate-spring</tt>, link against all of the JAR files that are now in your <tt>libs</tt> directory. </li>

</ol>

Spring cleaning

Our first task is to clean up our JDBC-based Spring-framework application from Part 1. The key thing to do is to step back a bit an ask ourselves how beans are really intended to be used. <i>An object should typically be created as a bean if it is intended to be a singleton object that is needed by many disparate classes in an application.</i>

Without something like the Spring framework, such an object (let's call it <tt>b</tt>) would have to be created by some object (let's call it <tt>m</tt>) that is responsible (maybe indirectly) for creating all of those disparate objects that depend on <tt>b</tt>. In other words, the flow of control looks something like: <ul> <li><tt>m</tt> creates <tt>b</tt>.</li> <li><tt>m</tt> creates many other objects, giving each a reference to <tt>b</tt>.</li> <li>Each of those objects creates more objects, continuing to pass along this reference to <tt>b</tt> until finally all objects that depend on	<tt>b</tt> have been created.</li> </ul> Notice that some of these objects many not even depend on <tt>b</tt> themselves; but they still need to know about it so they can pass it along this chain.

We can make this a little bit cleaner by implementing the Singleton design pattern ourselves, as we've seen. But even here the tt gets to be a little annoying, as every class that depends on <tt>b</tt> has to invoke the same tt to get it when an object is instantiated.

In effect, Spring's dependency injection is automatically writing and executing this Singleton-related tt for us. It is important to note, though, that Spring will only inject beans into other beans.

It can be helpful to see where a bean is not appropriate. Referring to our tutorial, an <tt>Inventory</tt> is a likely candidate for a bean. It is intended to be a singleton, and it might be used by several disparate classes (in <tt>tutorial-spring-cleaning</tt> it is used by several independent classes that provide an MVC-based application for examining the database). An <tt>InventoryItem</tt>, on the other hand, is not a good candidate for a bean. <tt>InventoryItem</tt>s are not Singletons; we need a distinct object for each item in the inventory. Instantiation and access to <tt>InventoryItem</tt>s is always mediated through the <tt>Inventory</tt> object. Although many different disparate objects may depend on one or another <tt>InventoryItem</tt>s, they are always obtained from an <tt>Inventory</tt>. Thus an <tt>InventoryItem</tt> might as well be an ordinary Java object that is not managed by Spring. Ditto for <tt>Suppliers</tt> vs. <tt>Supplier</tt>. So now our <tt>Inventory</tt>-related bean definitions look like the following (<tt>tutorial-spring-cleaning/metadata/spring/petstore.xml</tt>): &lt;bean id="inventoryDAO" class="petstore.Inventory" &gt; &lt;constructor-arg ref="dataSource" /&gt; &lt;constructor-arg ref="supplierDAO" /&gt; &lt;/bean&gt;

&lt;bean id="inventoryView" class="petstore.InventoryView"&gt; &lt;constructor-arg ref="inventoryDAO" /&gt; &lt;/bean&gt;

&lt;bean id="inventoryAdd" class="petstore.InventoryAdd"&gt; &lt;constructor-arg ref="inventoryDAO" /&gt; &lt;constructor-arg ref="inventoryAddValidator" /&gt; &lt;/bean&gt;

&lt;bean id="inventoryAddValidator" class="petstore.InventoryAddValidator"&gt; &lt;constructor-arg ref="inventoryDAO" /&gt; &lt;constructor-arg ref="supplierDAO" /&gt; &lt;/bean&gt;

<tt>InventoryView</tt> and <tt>InventoryAdd</tt> are two MVC-related classes that have no dependencies on each other in any way. However, each depends on the <tt>Inventory</tt> object: the former is a view of the object, and the latter allows adding new items. We are also making use of a validator object, which is used to ensure that the data comprising a potential new inventory item is legal. It depends on both the <tt>Inventory</tt> and <tt>Suppliers</tt> but not the <tt>InventoryView</tt> or <tt>InventoryAdd</tt>.

Something to note about our re-design is the following: except for the <tt>main</tt> method of <tt>PetStore</tt>, no class ``knows'' that it is or uses Spring-mananged beans. The <tt>main</tt> method looks as follows: public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("petstore.xml") ;

ctx.getBean("mainApp") ; }

<tt>mainApp</tt> is a bean that is created by instantiating a <tt>PetStore</tt> object. No other class invokes <tt>getBean</tt> or needs an <tt>ApplicationContext</tt>. Indeed, a search through the project shows that the only other Spring-related types are those involved in managing JDBC. In fact, this is how a Spring-managed application is supposed to look; classes are Plain Old Java Objects (POJOs) that know nothing of the framework that is managing them. This (at least in theory) allows for changes in the framework without significant disruption of the business/application logic, which is what the compiled tt should be focusing one.

Object/relational mapping and Hibernate

A not-so-pretty part of even our cleaned-up Spring application is that the DAOs potentially have a lot of SQL hard-ttd into them. In general, this is difficult to avoid with JDBC, as the DAOs must communicate directly with the database.

An object/relational mapper is something that provides an automatic mapping between persistent relational database data (for example, rows in tables) and in-memory objects in an application. In the simple case of mapping rows to objects, one typically specifies a schema that identifies what kind of object corresponds to a row in a given table and how to translate from column names to fields. One can then allow the O/R mapper to manage the corresponding objects, and then it is responsible for initializing the objects, ensuring that updates to the objects are reflected in the database, etc.

The O/R mapper that we will use is called Hibernate. Although we could use Hibernate directly, Spring provides a Hibernate module that handles some of the grungy details for us, so we will use that module. Hibernate actions are grouped together in a session, so first we configure Spring to make a <tt>SessionFactory</tt>, which we can use to get a session as needed: &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt; &lt;property name="driverClassName" value="com.mysql.jdbc.Driver"/&gt; &lt;property name="url" value="jdbc:mysql://localhost/petstore"/&gt; &lt;property name="username" value="pstore"/&gt; &lt;property name="password" value="pstore_pw"/&gt; &lt;/bean&gt;

&lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt; &lt;property name="dataSource" ref="dataSource"/&gt; &lt;property name="mappingResources"&gt; &lt;list&gt; &lt;value&gt;petstore.hbm.xml &lt;/list&gt; &lt;/property&gt; &lt;property name="hibernateProperties" value="hibernate.dialect=org.hibernate.dialect.HSQLDialect" /&gt; &lt;/bean&gt;

Notice that we still need a <tt>DataSource</tt> to handle the underlying protocol for communicating with the database. We then create a <tt>SessionFactory</tt> on top of that <tt>DataSource</tt>. The <tt>mappingResource</tt> property specifies the name of a file that defines the mapping between the database and in-memory objects. The <tt>hibernateDialect</tt> property allows us to use an extension of SQL called HQL to access the database, which will make certain operations simpler. Now let's look at the mapping file (<tt>tutorial-hibernate-spring/metadata/hibernate/petstore.hbm.xml</tt>):

&lt;?xml version="1.0"?&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt;

&lt;hibernate-mapping&gt;

&lt;class name="petstore.Supplier" table="suppliers" lazy="false"&gt; &lt;id name="id" column="ID"&gt; &lt;generator class="native" /&gt; &lt;/id&gt; &lt;property name="name" column="Name" /&gt; &lt;property name="street" /&gt; &lt;property name="city" /&gt; &lt;property name="state" /&gt; &lt;property name="zip" /&gt; &lt;/class&gt;

&lt;/hibernate-mapping&gt;

Ignore the <tt>lazy</tt> attribute for now. This mapping says that <tt>Supplier</tt> objects are to be mapped from the database as rows from the <tt>suppliers</tt> table. The <tt>name</tt>, <tt>street</tt>, etc. fields are all to be set from the same-named columns in the table (if no <tt>column</tt> attribute is specified, it defaults to the value of the <tt>name</tt> attribute). In order for Hibernate to manage the objects, they must have an id field; this mapping tells Hibernate to use its own strategy for determining the value of that field (which in this case will be to set it according to the <tt>ID</tt> column of the table). Now let's look at the <tt>Supplier</tt> class definition:

package petstore;

public class Supplier {

private int id ; private String name ; private String street ; private String city ; private String state ; private String zip ;

public Supplier { }

public int getId { return id ; }

private void setId(int id) { this.id = id ; }

// The rest of the getters and setters. }

Hibernate requires getter and setter methods for each field that is to be mapped from the database. To initialize an object, Hibernate will create the object with the default constructor and then invoke the appropriate <tt>set</tt> methods. Note that these methods need not be <tt>public</tt>---in particular, it actually makes sense to make <tt>setId</tt> <tt>private</tt> so that only Hibernate can set the object ID. There is nothing more to this class. So how do we get <tt>Supplier</tt> objects into our application? One way is to explicitly request that Hibernate construct them, as in our <tt>Suppliers</tt> bean:

public Suppliers(SessionFactory sessionFactory) {

// The HibernateTemplate (Spring) handles getting the current // Hibernate Session. HibernateTemplate template = new HibernateTemplate(sessionFactory) ; suppliers = template.find("from Supplier") ;

observers = new ArrayList<SuppliersObserver> ; notifyObservers ;

}

<tt>HibernateTemplate</tt> is a Spring-provided convenience class that lets us perform database operations without dealing explicitly with setting up Hibernate sessions. The <tt>find</tt> method takes an HQL query as an argument and returns a <tt>java.util.List</tt> of objects constructed by executing the query on the database and then mapping the rows of the resulting table to objects according to the mapping file. In this example, we use a very simple query that says to get every row of the table use to define <tt>Supplier</tt> objects. However, this is not the only way to get a <tt>Supplier</tt> object. Consider the mapping for <tt>InventoryItem</tt>:

&lt;class name="petstore.InventoryItem" table="inventory"&gt; &lt;id name="id" column="ID"&gt; &lt;generator class="native" /&gt; &lt;/id&gt; &lt;property name="description" column="Description" /&gt; &lt;property name="quantity" /&gt; &lt;property name="price" /&gt; &lt;many-to-one name="supplier" class="petstore.Supplier" column="supplier" /&gt; &lt;/class&gt;

The last line of the mapping says that the <tt>supplier</tt> field is defined by the <tt>supplier</tt> column; no surprise there. However, in the database, that field value is an <tt>int</tt>, and we want the corresponding <tt>Supplier</tt> object. Here we are making use of the foreign key constraints that we implemented at the beginning of this tutorial. The existence of that constraint in the database is enough for Hibernate to know that the integer field value corresponds to the value of the <tt>id</tt> column of one of the rows in the <tt>suppliers</tt> table, and that the <tt>supplier</tt> field of this <tt>InventoryItem</tt> should be set by constructing the corresponding <tt>Supplier</tt> object from that row of the <tt>suppliers</tt> table. We are also saying that there is a <tt>many-to-one</tt> relation between <tt>InventoryItem</tt>s and <tt>Supplier</tt>s; that is, many of the former may reference one of the latter.

It would be great if, once we have created an object via Hibernate that corresponds to a row in a database table, any changes to that object are automatically propagated to the database (e.g., changing the quantity of an <tt>InventoryItem</tt> automatically changing the corresponding field value of the corresponding row in the <tt>inventory</tt> table. However, things are not quite this straightforward. A bit of terminology might be helpful at this point.  A persistent object is one that is associated to the database in some way, and is usually managed by Hibernate during some portion of its lifetime.  It is usually a POJO (with a default constructor and getters/setters for Hibernate). A persistent object can be in one of three states:  transient (has never been associated with the database---remember that a persistent object is just an object); persistent (currently associated with a session); and detached (was associated with a session, but is no longer, probably because the session has been closed). A session corresponds to a (typically short-lived) conversation between the application and the collection of persistent objects. A session indirectly is a conversation with the database, because Hibernate ensures that during a session, persistent identity (the row of the database that is mapped to an object) is the same as Java identity (in-memory location of the object).

So let's consider a concrete example. Suppose we want to change the quantity of a particular <tt>InventoryItem</tt> and ensure that the change is reflected in the database. The way we currently get our inventory is that we instantiate an <tt>Inventory</tt> object (bean), which in turn creates a <tt>List</tt> of <tt>InventoryItem</tt>s by executing <tt>template.find("from InventoryItem")</tt>. This (Spring) method is just a cover of a Hibernate method; one of the convenient things that Spring does for us is to manage the opening and closing of Hibernate sessions. In particular, this method invocation causes a Hibernate session to be opened, the database to be queried and the <tt>InventoryItem</tt>s to be created, and then the session to be closed. But because of this last step, the persistent <tt>InventoryItem</tt> objects are now detached. Trying to invoke <tt>setQuantity</tt> on them directly does change the in-memory object, but because the object is detached, no corresponding change to the database is made.

There are (at least) two ways to ensure that changes to the in-memory object are transferred to the database. One way is to make changes to the object during a session; here is how that would be implemented as an <tt>updateItemQuantity</tt> method in <tt>Inventory</tt>: public void updateItemQuantity(final int itemID, final int quantity) { template.execute(new HibernateCallback {       public Object doInHibernate(Session session) {            InventoryItem item =                (InventoryItem)session.load(InventoryItem.class, itemID) ;            item.setQuantity(quantity) ;            return null ;

}   }) ;

notifyObservers ; }

The <tt>execute</tt> method expects an implementation of <tt>HibernateCallback</tt>, which specificies the <tt>doInHibernate</tt> method. That method is provided a <tt>Session</tt>, and all tt in that method is executed in the context of that session. Thus we can load in the corresponding <tt>InventoryItem</tt> and then change the quantity with the appropriate setter method; Hibernate will "intercept" this instruction and ensure that the change is also propagated to the database. Note that it is not adequate to get the <tt>InventoryItem</tt> from <tt>items</tt> directly, as those objects are detached; we must ask Hibernate to give us the object. Also note that we have obtained a new persistent object; it is not the same one as the object in <tt>items</tt> with the same ID. This must be handled by re-loading the list from the database whenever is considered appropriate.

An alternative is to change the in-memory object and then instruct Hibernate to identify the persistent object and make the changes: public void updateItemQuantity(final int itemID, final int quantity) { for (InventoryItem item : items) { if (item.getId == itemID) { item.setQuantity(quantity) ; template.update(item) ; }   }

notifyObservers ; } Here the <tt>update</tt> method re-attaches the persistent object and propagates the change back to the database.