Showing posts with label Hibernate. Show all posts
Showing posts with label Hibernate. Show all posts

Tuesday, November 20, 2007

JRuby and Hibernate

The beautiful thing about Rails on JRuby is that you have access to Java. Perhaps you have existing code you'd like to reuse or maybe there's some functionality in a Java library you'd like to use. Whatever the reason, it's good to know how to do it.

So today I created a new Rails app to demonstrate how to use Rails' controllers and views with some model classes from one of my earlier Java projects. My old app used the typical HibernateUtil singleton (section 1.2.5 of the Hibernate docs). I also liked the ActiveRecord pattern so my Java domain classes had some handy "find" methods. So in order to make this work in a Rails app, I installed the goldspike plugin:
script/plugin install http://jruby-extras.rubyforge.org/svn/trunk/rails-integration/plugins/goldspike

and then ran the rake task war:standalone:create

I copied the classes and lib directories from my old apps' WEB-INF directory to the WEB-INF directory in my Rails app and then generated a controller and modified it to look like this:
require 'java'
import 'com.example.domain.Person'
import 'com.example.util.HibernateUtil'

class PersonController < ApplicationController
def list
with_transaction do
@people = Person.find_all.to_a
@people.sort!{|p1, p2| p1.name.downcase <=> p2.name.downcase}
end
end

def with_transaction
begin
tx = HibernateUtil.session_factory.current_session.beginTransaction
yield
tx.commit
HibernateUtil.session_factory.current_session.close
rescue
tx.rollback
end
end
end

Finally, I added a list.rhtml template for the "list" action and voila! I have a Rails-ish app that uses Hibernate instead of ActiveRecord.

Tuesday, April 10, 2007

It's spelled S-Q-L

Why do so many Java developers suck at SQL? Are they just born that way? Are they brainwashed? Do they think that Hibernate will just do it all for them? What's the problem?

The reason I ask is that I'm working on a Java system where the developers obviously thought nothing of letting Hibernate lazily instantiate every relationship as they iterated through collections and navigated down relationships. Not once did they stop to consider the SQL that was being thrown across the network to the database or the performance penalty that it would incur. Just a couple weeks ago I turned on Hibernate's SQL logging just to see 631 queries go flying by in order to prepare the data for a single JSP. WTF?! 631 Queries!!?

Then today I saw another atrocious example of bad code that instantiated several collections of some very large classes from the database to just throw them all away after navigating through them to get a count. Whatever happened to count(*)? In the end I replaced hundreds of lines of convoluted Java code with about twenty lines of SQL. Yes SQL, not HQL (which rocks BTW), but just wasn't appropriate for this task.

Perhaps it's unfair of me to pick on Java developers but for one reason or another a lot of the Java developers I run into have this resistance to leveraging the relational query engine at their disposal. They don't strike a good balance between the object oriented and relational worlds that their systems stride. Use the right language for the right task. And if you can't determine when to turn to SQL, turn on SQL logging and watch what the heck is going on. When you see SQL tearing by, just pause for a moment and ask yourself if there's a better way to do what you want. And remember you have decades of querying technology just waiting to be used. Don't be afraid of writing an elegant query.

Thursday, August 24, 2006

Watch that SQL!

Long before I used object relational mapping tools like Hibernate or Toplink in Java or ActiveRecord in Ruby on Rails I used to write a fair amount of SQL (some real nasty queries too!). And in a lot of the shops where I worked it was standard practice to create an explain plan just to make sure that the database could execute the SQL efficiently. If it couldn't, I would dutifully restructure the query, add indexes, or go ask for some DBA help.

But nowadays in this wonderful land of ORMs people just let the framework crank out the queries and never ever look at them. To me, that's just plain wrong. If you're using Hibernate turn on the logging. If you're using Rails just go take a look at the development.log file and go watch what's going on! You may be surprised.

I started a new job a few weeks ago and just wanted to see what Hibernate was doing. And lo and behold, a JSP page was causing 69 queries to run in order to generate a simple list of rows from a table. The main problem was that every lazily instantiated relationship for each object in the collection was being traversed after the initial fetch.

So what could have been done? Well in this case, Hibernate has several options:

  1. Hibernate's query language is quite expressive and something like select e from Employee e left outer join fetch e.department d would have caused both objects to be fetched in a single query.
  2. The fetch keyword I used in the first example has one limitation (for good reason too). It can only be used to fetch one collection. So take advantage of Hibernate's caching to prefetch related objects instead. Hibernate will associate any newly instantiated objects with objects that already exist in cache. Even if you're not using something like EHCache you still have some caching built into your session so don't discount this tip right away.
  3. Use a DTO-like object and go old-school and only select the fields you need with something like: select new EmployeeListDTO( e.firstName, e.lastName, d.name) from Employee e left outer join e.department d
Now if you're using ActiveRecord you don't have the double edged sword of a cache so the second option I described above isn't available, but the other two are possibilities:

  1. Employee.find :all :include => :department
  2. Employee.find_by_sql "select e.first_name, e.last_name, d.name from employees e left outer join departments d on e.department_id = d.id"
The second option shows one distinct design difference between Hibernate and ActiveRecord. Hibernate gives you a SQL-like query language but does away with having to specify join constraints because that information is in the mapping metadata. Whereas ActiveRecord says why reinvent SQL and just let's you have at it. Oddly enough I like both approaches...

Finally, be sure to use the ad-hoc query tools at your disposal to try out your queries before you embed them in your app. If you're using Hibernate 2.x then go get a copy of Hibernate Console (part of the Hibernate Tools). It can be a bit of a pain to get it setup but I really appreciate being able to work out the query before running it as part of my app. If you're using Hibernate 3.x and Eclipse then go get the Hibernate Tools plugin. If you're using Ruby on Rails then you already have all the tools you need. Simply drop to the command line, cd to your project directory and then type script/console. Open up a second shell window (if you're running unix) and type tail -f log/development.log from your project directory and you can instantly watch what SQL Rails generates when you execute those find methods.

Now go out there and watch what you're doing for database access! Don't let all that ORM goodness make you lazy.

Tuesday, May 23, 2006

DAOs and ORMs

The discussion that this article on the ServerSide generated reminds me of an article I wrote a little while ago. The original poster gets a bit confused about the problem because he assume the use of an ORM means that you need to use the "Open Session In View" pattern. But if you get by that and read some of the comments, you discover that many people (like me) don't believe that the DAO pattern is necessary when using an ORM solution.

A valid concern about ditching DAOs is the coupling that may happen between your domain objects and your persistence mechanism. But if you like ActiveRecord or Rich Domain Models or Annotations or XDoclet then you've already made the choice of productivity over ultimate framework plugability and should just get over it.

But if the coupling is still nagging you and you're concerned about sprinkling framework API calls throughout your code then maybe you want to consider looking at EJB3. Instead of using the vendor's API (e.g., Hibernate, Toplink, etc.) you can reference standard annotations and classes that are free of implementation specifics. At least that way you've provided some hope of switching out implementations.

In the end, question why you're using the DAO pattern and then ask yourself if you've already done something in your code that has violated that pattern. Think about your use of OpenSessionInView filters or the navigation of lazily instantiated collections in your view layer. Maybe DAO and ORM really don't mix...

Sunday, February 26, 2006

Hibernate vs ActiveRecord

Over the last 2+ years I've grown quite accustomed to the facilities of Hibernate (one of the most popular Java object-relational persistence frameworks). And before that I used TopLink for a couple of years. So now when it comes to my work with Ruby on Rails I have some pretty high expectations.

The out-of-box experience with Rails' persistence framework is undoubtedly different but similar enough to Hibernate to make life fairly comfortable. But recently I started watching the SQL that gets generated from Rails and decided I'd like to optimize them a bit. But unfortunately that isn't as easy as everything else in Rails. I found this article at TheServerSide that sums things up pretty well. I think Rails comes out on the losing end. Now the question becomes, are the things you lose worth the things you gain?

Thursday, October 27, 2005

Hibernate & Ruby


In my previous project I was using the latest and greatest version of Hibernate and was happily employing the Hibernate Eclipse plugin for writing my HQL queries before embedding them in my application. But my current project uses an older version of Hibernate (2.1.x) so the Eclipse plugin is out of the question. Fortunately I can remember back to when I used the forerunner of the Eclipse plugin, a little program that was called Hibern8IDE. It later became part of the Hibernate extension tools and was then thankfully renamed "Hibernate Console". Fortunately it's still available for download from hibernate.org.

Now the only problem is that this project also uses Spring which informs Hibernate about the XDoclet-generated mapping files at runtime in a decidedly non-hibernate fashion. What I needed was to create a good old fashioned hibernate.cfg.xml which contains references to each *.hbm.xml file. But I wanted to script the generation of this file so that I wouldn't have to manually maintain the file as the collection of *.hbm.xml changes over time. So I turned to my new friend Ruby. The top and bottom part of this script use "here docs" to generate the boiler plate static XML. But then right in the middle I got this:


`find . -name '*.hbm.xml' -print`.each { |f|
f.gsub!(/.*(com\/company.*?)\n/, '\1')
puts "<mapping resource=\"#{f}\"/>"
}


The first line executes the Unix find command, and then begins an iterator over each line of that command's results. Then within the block I use a simple regex within the String's substitution method to get the Java package and file name. Then finally I print out an XML element whose resource attribute contains the name of the *.hbm.xml file. That's a lot of stuff in only four lines of code! Ruby is very expressive. Now I must emphasize the value of a good editor to color code something like that so a person can make sense of it. I definitely recommend the RDT plugin for Eclipse.

Sunday, October 02, 2005

Seam

After yesterday's rant about layers upon layers of code and XML based dependency injection I found Norman Richard's blog about a new web framework called Seam from JBoss. Apparently Gavin King, the guy who brought us Hibernate, is involved in this as well. That's a very good sign. From what I've read it looks like this might be just what I'm looking for. It's brand new and will undoubtedly have rough spots and missing functionality, but it really does seem to be headed in the right direction.

Sunday, September 25, 2005

On JSF, Struts, & Spring Part Deux

After a Saturday of messing around with Spring, JSF, & Hibernate I have a nice little application that does nothing more than retrieve an object from my local PostgreSQL database and display the value in a web page. While the end result isn't very exciting there is a whole symphony of integration going on under the covers.

Hibernate and Spring

I first created a couple business domain classes that use the latest and greatest Hibernate/EJB3 Java 5 annotations to describe how they map to database entities. This is currently supported in Hibernate 3.1 beta 3 so I didn't really expect to be able to use this stuff once I got to integrating it with Spring. I assumed I'd have to either write Hibernate mappings in XML or maybe integrate XDoclet to generate the mappings. Well to my surprise Spring has org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean!! So Spring was good to go! All I had to do was declare the sessionFactory and the transactionManager that I wanted in applicationContext.xml. I still haven't figured out a way to get it to autodiscover the annotated business model so I had to manually list the two classes but that wasn't too big of a problem.

I then moved on to creating a subclass of Spring's HibernateDaoSupport class and configuring it in applicationContext.xml where I learned about the declarative transaction management features of Spring. In this XML file I was able to wire together the DAO, the Hibernate sessionFactory, the transactionManager and indicate which DAO methods require a transaction. This simplified the code in the DAO by injecting the necessary Hibernate Session and Transactions at runtime. But this comes at the cost of using a HibernateDaoSupport method called getHibernateTemplate() whose returned object basically delegates to the injected Hibernate session and turns Hibernate exceptions into unchecked exceptions. This also has the unfortunate side effect of burying the native Hibernate API. I don't really care for that idea too much but it's a tradeoff for not having to manage session and transaction resources manually.

So I then created a little JUnit test, used the FileSystemXmlApplicationContext to start up Spring and then used the context to get the configured DAO from Spring and called a method. Everything worked as expected.

Spring and JSF

Next it came time to integrate JSF. This became a little more time consuming. First of all I needed to figure out how to initialize all the Spring stuff within a web application which in turn initializes all the Hibernate stuff. It was actually fairly simple. I only had to configure a listener in the web.xml file for org.springframework.web.context.ContextLoaderListener. Also by using context-param in web.xml I was able to tell this ContextLoaderListener instance where to find my spring applicationContext.xml files.

Secondly, JSF has its own Dependency Injection framework for configuring backing beans that have request, session or application scope and it was unclear to me how to integrate the two dependency injection frameworks i.e., If my DAO and Facade/Service classes are configured with Spring how would I go about injecting these instances into a JSF backing bean? Well as it turns out I can't. Not yet anyway. There is a little project appropriately enough named "jsf-spring" that aims to transparently aggregate these two frameworks. It's in beta. But Spring has a supporting class called FacesContextUtils which allows me to fetch an instance of WebApplicationContext (with the current FacesContext as a parameter). I can then use that Spring context object to fetch the DAO (or more typically a facade class) to do the work I need. Given all this dependency injection stuff this manual fetching of context objects and service objects seems like a very odd hack and is more like calling a singleton getInstance method. But it works and I was able to tie the business layer to the presentation layer.

Summary

So there you go, a display-only Spring/Hibernate/JSF application. It was a good lesson in making all the pieces work together. In the end I look at all this plumbing and I'm a bit surprised how simple and difficult it was to get everything going. The Spring stuff is well documented on the web and was easy to get going with Hibernate. But answers to my questions about adding JSF to the mix were a little harder to come by. I suspect the future holds a stronger integration for Spring and JSF (perhaps you can just use Spring as a replacement for the JSF injection framework) and I can see Java 5 annotations becoming more prevalent in Spring so that you don't have to write all that XML. Annotations work great for Hibernate so I don't see why they wouldn't work well for Spring too.

Wednesday, August 10, 2005

EJB3 Presentation

It seems like EJB3 information is coming fast and furious now. The Server Side is hosting a new EJB3 presentation recorded at the Belgium Java Users Group. One of the speakers is an Oracle Toplink developer. It gives a very good overview of the EntityManager API that I was talking about the other day. Check it out.

Monday, August 08, 2005

EJB3 EntityManager

Since my first post about Entity EJBs with Hibernate, the Hibernate team put out a new beta implementation of javax.persistence.EntityManager. So I wondered what exactly it would take to jettison all the hibernate imports from my class. Well it turned out to be pretty simple. First I substituted the hibernate.cfg.xml file for a META-INF/persistence.xml file that looks like this:

<entity-manager>
<name>manager1</name>
<properties>
<property
name="hibernate.connection.driver_class"
value="org.postgresql.Driver"/>
<property
name="hibernate.connection.url"
value="jdbc:postgresql://127.0.0.1:5432/myDatabase"/>
<property
name="hibernate.connection.username"
value="darcy"/>
<property
name="hibernate.connection.password"
value="darcy"/>
<property
name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect"/>
</properties>
</entity-manager>

The interesting thing about this is that it autodiscovers the annotated classes. No longer do I have to individually list each persistent class. Secondly, I changed my main method to look like this:

public static void main(String[] args) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("manager1");

EntityManager em = emf.createEntityManager();
try{
Brand b = (Brand)em.createQuery("select b from Brand as b")
.setMaxResults(1)
.getSingleResult();
System.out.println(b.getName());
}finally{
em.close();
}
}

You can see that this code is very similar to the Hibernate code that I posted earlier. Obviously the class names and some of the methods are different (like getSingleResult() instead of uniqueResult()) but at first glance it looks like getting started is pretty easy. It'll be interesting to see some of the differences between Session and EntityManager.

Friday, July 29, 2005

EJB3

With the use of Java 5's new metadata support and Hibernate 3's early annotation tools I decided to see what it would take to make an EJB3 Entity Bean. Well it's quite a bit simpler than Entity EJBs used to be and I don't need a big nasty EJB container either! It's just a plain old Java object (POJO). And as you can see in the main method's source code, I can still use the same Hibernate code that I'm familiar with.

@Entity(access=AccessType.FIELD)
@Table(name="my_brand", schema="ds")
public class Brand {
@Id(generate=GeneratorType.NONE)
@Column(name="brand_code")
private String id;

@Column(name="brand_name")
private String name;

/**
* @param args
*/
public static void main(String[] args) {
Configuration cfg = new AnnotationConfiguration()
.configure();
SessionFactory factory = cfg.buildSessionFactory();

Session session = factory.openSession();
try{
Brand b = (Brand)session.createQuery(
"select b from Brand as b")
.setMaxResults(1)
.uniqueResult();
System.out.println(b.getName());
}finally{
session.close();
}
}
//getters and setters
}

Wednesday, April 06, 2005

Hibernate lets me down...

Well the new version of Hibernate is out there and apparently version 3.0 has been seriously worked over by the Hibernate team. Specifically I'm referring to the brand-new ANTLR-based HQL/SQL query translator... but back to that in a second.

I generally keep up with the latest version of Hibernate and up until I tried 3.0 it was a no-brainer. You just downloaded it and everything just worked. Not this time:

First of all, the packages all changed from net.sf.hibernate to org.hibernate. While it's nice that the package reflects Hibernate's domain I don't think this change really needed to be inflicted on its users. TopLink did that to me when it changed hands from The Object People to WebGain and then to Oracle. It's a pain in the ass.

Secondly, "Since it is best practice to map almost all classes and collections using lazy="true", that is now the default." While I agree with the point, I was a little annoyed to discover that much of my second level caching stopped working. Easy enough to fix but still...

Thirdly, back to the new HQL/SQL Query translator. It fails to parse several of my existing queries. Damn. Worse is that the documentation says I can set the hibernate.query.factory_class property to use the ClassicQueryTranslatorFactory but that doesn't work either. So I'm forced to use native JDBC calls instead. That's what Hibernate is supposed to help me avoid!

Finally, Hibernate 3.0 has a "revamped Query API". This was my whole reason for trying Hibernate 3.0 and unfortunately when I use criteria.createCriteria() or criteria.createAlias() the alias for the joined table doesn't show up in my generated SQL!!

Agghhh! I still like Hibernate (most of it still works) and I'm going to stick with v3 but this was not what I've come to expect of the Hibernate team. It sounds like the HQL/SQL parser thing was the right choice but this release needed a little more time in the oven.