JDO and Hibernate


December 5, 2013 Maithilish

8.3. Retrieve

In this section, we retrieve persisted symbols through a variety of ORM like JDO, Hibernate and MyBatis. We do so, just to demonstrate that objects persisted through an ORM are readily retrievable through others.
JDO

In JDO, we use PersistenceManager to retrieve an object from the database.

    
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
       Symbol symbol = pm.getObjectById(Symbol.class, name);
       // use the object

    } finally {
          pm.close();
    }
Sometimes, we may be like to retrieve only a certain fields of an object, and for this, JDO supports JDOQL and SQL query. Following code uses JDO’s NamedQuery feature to retrieve list of symbol names from SYMBOL table.
  PersistenceManager pm = pmf.getPersistenceManager();
  try {
      Query query = pm.newNamedQuery(Symbol.class, "selectSymbolNames");
      query.setResultClass(String.class);
      List<String> list = (List<String>) query.execute();
  } finally {
      pm.close();
  }
Query element defines the NamedQuery and its SQL.
in.fins.shared/package.jdo

<class name="Symbol">
   <field name="name" primary-key="true" />
   <field name="label" />
   <field name="dataGroups">
      <element column="symbol_name"/>
   </field>
   <query name="selectSymbolNames" language="javax.jdo.query.JDOQL"><![CDATA[
            SELECT s.name FROM in.fins.shared.Symbol s
            ]]></query>
</class>

JDO Class enhancement

JDO uses byte-code manipulation to make normal Java classes as persistable through a process is known as class enhancement. This enables JDO to keep track of modifications to persistence objects so as to trigger database update only on changes. In RStore, ant target enhance takes care of enhancement. DataNucleus throws ClassNotPersistenceCapableException when we try to persist classes which are not enhanced.
Hibernate and MyBatis require no class enhancement.
Hibernate

Configuration file of Hibernate is hibernate.cfg.xml in which we define session factory, one for each database connection, using session-factory element. JDBC properties are set within the session-factory element. Whereas JDO loads the mapping file from class path, Hibernate requires inclusion of mapping files in its configuration file, via mapping element. Following configuration includes three mapping files.

src/hibernate.cfg.xml

<hibernate-configuration>
        <session-factory>

                <!-- Database connection settings -->
                   .....

                <!-- mapping files -->
                <mapping resource="in/fins/shared/Symbol.hbm.xml" />
                <mapping resource="in/fins/shared/DataGroup.hbm.xml" />
                <mapping resource="in/fins/shared/Data.hbm.xml" />

        </session-factory>
</hibernate-configuration>

Each hbm.xml file maps a single persistable class, and let’s go through Symbol.hbm,xml to understand Hibernate mapping concepts.
in.fins.shared/Symbol.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping package="in.fins.shared">

	<class name="Symbol" table="SYMBOL">
		<id name="name" column="name" />
		<list name="dataGroups" cascade="all">
			<key column="SYMBOL_NAME" />
			<list-index column="DATAGROUPS_INTEGER_IDX" />
			<one-to-many class="DataGroup" />
		</list>
	</class>

	<query name="selectSymbolNames"><![CDATA[
	      select name from Symbol 
	      ]]>
	</query>

</hibernate-mapping>

Mapping structure is almost similar to JDO with some variations in naming of elements and attributes. Table attribute is explicitly mentioned in class element. An id element defines primary key field, whereas property element defines a regular field. Attribute type=”serializable” in property element serializes the field. For 1-N relationship, list element is used with one-to-many element where foreign key is specified with key element. Query element specifies named query.
Typical Hibernate session is as shown in the following snippet from HibernateDao.
in.rstore.dao.hibernate/HibernateDao.java

        try {
                Configuration configuration =
                      new Configuration().configure();
                ServiceRegistry serviceRegistry = 
                      new ServiceRegistryBuilder()
                         .applySettings(configuration.getProperties())
                         .buildServiceRegistry();
                SessionFactory sf = 
                         configuration.buildSessionFactory(serviceRegistry);

                Session session = sf.openSession();
                Symbol symbol = (Symbol) session.load(Symbol.class, name);
                    ....

        } catch (HibernateException e) {
                throw new ExceptionInInitializerError(e);
        } finally {
                session.close();
        }

Configuration().configure() searches for hibernate.cfg.xml in classpath and configures the SessionFactory. Session obtained from SessionFactory is used to interact with the database. Session.getNamedQuery() and Query.list() methods are used to query the database through NamedQuery.
MyBatis

MyBatis is altogether a different class of ORM, which relays heavily on SQL to map object to tables. One has to have a fair degree of SQL skill to work with MyBatis. This section is optional and you may skip this if you aren’t planning to use MyBatis in your project.

JDO and Hibernate are the leaders in open source ORM softwares. For some reasons, you still like to work with MyBatis, then go through the reminder of this section.
MyBatis configuration file is mybatis-config.xml, wherein typeAlias element provides short alias to long fully qualified class name, environment element configures JDBC connection and mapper element adds mapping file. Following snippet from Mapper.xml, shows MyBatis mapping structure.
in.fins.shared/Mappers.xml

<mapper namespace="mappers">

        <resultMap id="resultSymbol" type="Symbol">
                <id property="name" column="name" />
                <collection property="dataGroups" ofType="DataGroup"
                        column="name" javaType="List" select="selectDataGroups" />
        </resultMap>
        ....

        <select id="selectSymbol" parameterType="String" resultMap="resultSymbol">
                select * from Symbol where name = #{name}
        </select>

        <select id="selectDataGroups" parameterType="String" resultMap="resultDataGroup">
                select * from datagroup where symbol_name = #{name}
        </select>
        ....

Mapping structure is entirely different from what we have seen in JDO and Hibernate. Select element select rows from a table via SQL The first select element, selectSymbol selects a row whose name column equals the input parameter and the second select element, selectDataGroups selects rows from DATAGROUP table where column symbol_name matches input parameter. It is important to note that, these two statements are distinct and no way interconnected. The first one, fetches a single Symbol object, but its List<DataGroup> field will be null, and the second one, fetches a list of DataGroup. Now the question is how to set the list to List<DataGroup> field of Symbol.
Attribute resultMap in select element, indicates that result of select has to be handed over to a specific resultMap defined by resultMap element, which may be used to interlinks the multiple statements. From the result of selectSymbol statement, MyBatis constructs a ResultMap named resultSymbol. On doing so, when it encounters collection element in ResultMap, it fires selectDataGroups statement to fetch a list of DataGroup which is set Symbol.dataGroups field. ResultMap chaining, allows us to populate DataGroup.List<Data> field in a similar fashion. Refer RStore’s Mapper.xml, for the complete listing.
In JDO and Hibernate, an attribute is all that is required to serialize a field. But in MyBatis, it not possible to get away so easily. Generally, database stores serialized object in a Binary Large Object (BLOB) column and MyBatis gets it back as Blob object. It is our job to deserialize the blob and assign it to a field. MyBatis supports a construct, known as TypeHandler, for this sort of type conversion, and RStore uses a custom type handler in.rstore.dao.mybatis.BlobTypeHandler to convert Blob to List<Fact>
Next chapter integrates Fins with database using the concepts covered in this chapter.
Forward Pointers

DataNucleus JDO Documentation – refer JDO API tab of DataNucleus Access Platform

1-N Mapping – refer JDO : 1-N Relationships with Lists
Class Enhancement – refer JDO Class enhancement
Hibernate – refer Hibernate Core Reference Manual of latest version in Hibernate Docs site