iBatis or Hibernate ?

December 16, 2011

Hello,
I have been thinking to write this one since long. It almost now took 10 months to write the new blog entry.
In this one I will be talking about the iBatis and Hibernate. I purposely did not mention comparison as I myself do not think they are comparable to each other. Both of them have a different purpose and different applications in designing the solutions for Data access. While taking interviews I often come across candidates mentioning iBatis as a competitor of Hibernate. This exactly is the reason I felt I should share my views around the same.

iBatis is a very good and handy SQLMapper tool. I had experienced it’s usefulness while consuming the iBatis framework to build the solution that involved invoking Oracle Stored Procedures that returns REFERENCE cursors back. You simply configure the returned resultset to the Java objects and you are done. You get to work with the Java Objects in your application without bothering to write the usual and monotonous traversing logic and initializing the Java objects on your own. But this is where some colleagues starts thinking it as an ORM(Object Relational Mapping) tool. This is not the fact. iBatis  helps you map Java objects to the Parameters being passed to Stored PRocedure/Function/SQL without worrying about JDBC.

ORM has a altogether different domain to address. To understand this we have to first understand the challenges involved in mapping Object model to Relational model. This is usually called as Object Relational Impedance. We will see few of them hereafter.
First and foremost thing is Object Inheritance available in Object model which is not in Relational model. Hibernate as such addresses this by implementing Table per Class, Table per subclass and Table per Class hierarchy. We cannot go into more details of these and already a lot of information is available around this. The crux is when persisting/retrieving the Object hierarchy to/from database, either a discriminator column or table joins are implemented based on the strategy selection.
Another important feature that ORM tool provides is persisting the Object Graph when parent is being persisted. These are some of the things which are not addressed by iBatis. Well, you can do this with iBatis provided you write your own code for this. ORM tools also has a feature that helps identifying the dirty instance and persist it to the database once it is associated to Persistence context. Apart from this ORM has lot of other features which can be checked here.

In essence when we want to build a solution that involves just retrieving data from database and present it to the user, iBatis is simpler and effective solution. Whereas when one has the liberty to derive Relational model from the Object model and heavily retrieve/persist Object Graphs, Hibernate is appropriate solution. Using hibernate only for Data retrieval makes your solution over-engineered.

Hope this helps someone trying to compare iBatis and Hibernate.

Advertisements

Decoupling Java applications and config/properties files

March 11, 2010

Hello,
I have been developing a stand-alone Java application packaged as an executable JAR file.
The application had,

  1. Database interaction using iBatis APIs.
  2. Log the various activities in a log file using log4j API.

I had packaged the “my-db.properties” file that feeds the driver/username/password information to “SqlMapConfig.xml(iBatis configuration file)” within the JAR itself.Also the “log4j-myapp.properties” file was placed inside the JAR.

This introduced strong coupling/dependency between these files and JAR. Whenever I need to change database or log4j configuration, I had to re-package the JAR.

I was searching for a solution for this and based on google searches and interpretation of Java documentation for Class.getResourceAsStream() addressed this problem in the following way.

Solution:

  1. Consider that we are generating this executable jar (myapp.jar) in  “myapp/dist” directory.
  2. To resolve dependencies on iBatis and log4j, put respective JARs in the same i.e “myapp/dist” directory.
  3. Add Class-Path attribute in “Manifest.mf” file that lists these JAR files.
  4. This can be done by providing the custom manifest file while generating the JAR file. #2 and #3 are widely used in various enterprise as well as standalone applications so doing this is not an issue.

  5. Create a directory named “config” in “myapp/dist” where we will keep properties file. Of course this can be any name you like.
  6. Add the entry “config/” to the Class-Path attribute in “Manifest.mf” file. This brings “config” directory in the classpath while executing the application.
  7. Put the “log4j-myapp.properties” and “my-db.properties” in “config” directory.
  8. Your application(may be constructor of your main class) can load the log4j configuration as shown below –
  9. 	/*Initialize log4j */
    	Properties props = new Properties();
    	props.load(this.getClass().getResourceAsStream("/log4j-myapp.properties"));
    	props.list(System.out);
    	PropertyConfigurator.configure(props);
    
  10. SqlMapConfig.xml” can point to the resource properties file as shown below. This does not change much as compared to log4j.
  11. <sqlMapConfig>
       <!-- This is where we specify the properties file where DB configuration is specified -->
       <properties resource="my-db.properties"/>
       <transactionManager type="JDBC" commitRequired="false">
       <dataSource type="SIMPLE">
         <property name="JDBC.Driver" value="${driver}"/>
         <property name="JDBC.ConnectionURL" value="${url}"/>
         <property name="JDBC.Username" value="${username}"/>
         <property name="JDBC.Password" value="${password}"/>
       </dataSource>
      </transactionManager>
      <sqlMap resource="com/amit/test/xyz.xml"/>
    </sqlMapConfig>
    
    
  12. Now when you run your application (java -jar myapp.jar), the properties files will be picked up from the config directory.

This ensures you do not need to change the JAR file for making Database and log4j configuration changes.

The Directory structure for “dist” looks as shown below –

Directory Strcture for "dist": myapp |----dist | |----myapp.jar | |----ibatis-2.3.4.726.jar |----log4j-1.2.14.jar |----ojdbc14_g.jar |----config | |---log4j-myapp.properties |---my-db.properties

Manifest.mf classpath entry as below –

Class-Path: config/ log4j-1.2.14.jar ibatis-2.3.4.726.jar ojdbc14_g.jar

Why this works?
If you see the line that loads log4j configuration file, it has “/” at the start of filename.

props.load(this.getClass().getResourceAsStream("/log4j-myapp.properties"));

As per the Java documentation(see below) for the method, we have to give “/” at the start and then only the resource will be located using absolute name calculated as mentioned.

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getResourceAsStream(java.lang.String)

I was facing issues earlier because,

  1. I was only giving “log4j-myapp.properties” while loading the log4j configuration in my program.
  2. In the Manifest.mf, I was not appending “/” at the end of “config” directory. Without this the resource was not getting located.

Of course this is not just limited to iBatis and/or log4j, but any properties file that needs to be controlled outside the realm of the JAR file especially in stand-alone application can be configured this way.
Java API documentation to the rescue once again. Many thanks to them.

Cheers !!
Amit