How to do Database Transactions in Rails

June 4, 2007

It took me a surprsingly long to time learn how to do transactions in Rails. I assumed it would be dead simple (it is), but try googling for rails transactions. Useless. Especially when compared to something like hibernate transactions.

Anyway, this is how you do it:
transaction do
bob.withdrawal(100)
sally.deposit(100)
end

Source: http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html


Ruby ActiveRecord & Java Hibernate

May 25, 2007

This is the first in probably a bunch of posts about my experience transitioning from a Java mindset to a Ruby one.

So my first experience creating Hello World in Rails (which is really more like a fully functional blog application, complete with comments) really blew me away. The tiny amount of code required to get all your basic database operations was quite fantastic. A lot of the advantages come from the ‘convention over configuration’ and ‘sensible defaults’ mantra that the Ruby guys espouse.

There’s very little technical reason that can’t be done this simply using Java stuffs, so I set out to simplify my data access layer.

In Ruby, the process of creating database, ORM layer, and CRUD classes is as follows:

1. Create the database, either with DDL or a Rails migration

2. Create the ORM layer by creating an ActiveRecord class, aka simple mapping file
3. run generate/scaffold
4. Ok, that was pretty fast and easy

Ok, so I’m using the usual lightweight Java suspects: Spring & Hibernate. What I’m about to show took some work that you get for free with Rails, but I only had to write it once and I’m pretty pleased with the results.

I’ll start with the end product. Let’s say I want to create a Person class, with fields age and name. Also, let’s assume that I subscribe to the theory of class invariance, which assumes that an object is ALWAYS in a consistent state, thus eliminating the need to check for validity all the time. This is the number one aspect of Ruby (and javascript, php, etc) that I can’t get 100% behind.

(NB Let’s assume that a person’s name is invariant. If you’re writing code for a neonatal facility, that assumption might not stand, but for our application, let’s assume the person is named.)

public class Person {

private Integer id; //surrogate key
private Integer age;
private String name;

// can’t construct a person with no name
// this ensures it’s not implicitly called ever
// plus, hibernate like a (not necessarily public) default constructor
private Person() {}

// public constructor
public Person(final String name, final Integer age) {

// don’t actually assert in production! throw instead
assert name!=null && !name.isEmpty() : “Name can’t be null or blank”;
assert age > 0 : “name must be positive”

this.name = name;
this.age = age;

}

//accessors
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Integer getId() {
return id;
}

// no javabean style mutators!

// irrelevent business logic omitted

}

Ok, so that’s a pretty simple and straightforward class. Seems like a bunch of code, but don’t forget that eclipse can generate almost all of it for you (Source -> Constructor Using Fields & Source-> Generate Getters)

Next up, we need to map it to the database. That’s easy enough with a Hibernate mapping file.

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE hibernate-mapping PUBLIC “-//Hibernate/Hibernate Mapping DTD//EN”
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd”&gt;
<hibernate-mapping>
<!– map the class to the table –>
<class name=”com.company.Person” table=”person”>
<!– let mysql (or whatever) handle the autoincrement PK –>
<id name=”id” column=”id” access=”field”>
<generator class=”native”/>
</id>
<!– by default, field names map to table names and type is inferred –>
<property name=”shortcode” access=”field”/>
<property name=”aggregator” access=”field”/>
</class>
</hibernate-mapping>

Note the access=”field” attribute on each of the properties. Hibernate has a magical ability to set object member variables, even when they are private. That lets me keep my class invariant, but still allow object creation from the database. It just needs a hint so it knows to set the variable directly instead of trying to use a mutator. If you have setters, you don’t need that attribute.

It’s also worth noting that ActiveRecord syntax has Hibernate beat hands down. It’s actually quite unbelievable. It takes a massive amount of XML to do a simple mapping such as this one that in Rails requires literally no code at all. (Technically, since I have a non-conventional legacy database name, it would require one line: def self.table_name() “person” end).

OTOH, I love having a DTD to validate my mapping document against. Why? Because I have fat fingers and I make a lot of typos. In Rails, this is only apparent at runtime. That is the second piece I have trouble with: failing at runtime because of a typo just seems crazy.

NB I’ll save this for another post, but I’ve been having trouble with more complicated ActiveRecord mappings. Specifically, I can’t quite get multitable inheritance with a discriminator column to work properly. Also, I do a lot of composition in my class designs and all this lazy loading is killing me. Any way to do lazy-load=”false”?

OK, on to the Java DAO code. I created a (Java5) generic Dao interface with the basic CRUD operations and a generic implementation. When I say “generic”, I am referring to the class being accessed – not the actual data access later. It is certainly possible to use the pimpl idiom to abstract away the data access technology so you could plug in Hibernate, iBatis, JPA, JDBC, etc with no client code change. But I like Hibernate and have work to get done 🙂

Oh, and I like Spring a lot too, so I use their HibernateDaoSupport class to handle all the ugly Hibernate & database stuff. Tying the DAO to the implementation a little, but again, I got work to do 😉

Let’s say I don’t want any operations other than CRUD for now. (These aren’t coded – just showing you what I would ideally want by default):

Person findById(Integer id);
List<Person> findAll();
public List<Person> findByExample(Person person, String[] excludeProperty);
Person save(Person person);
void delete(Person person);

Here is my actual interface (yes, you should be coding to interfaces!)

public interface PersonDao extends GenericDao<Person> { }

Good. No code there. That’s perfect.

What about the implementation?

public class PersonHibernateDao extends GenericHibernateDao<Person> implements PersonDao {

// need a session. Just dependency inject it in the constructor
public PersonHibernateDao(SessionFactory sessionFactory) {
super(sessionFactory);
}
}

Good. No code there either. Let’s test it out (Spring context file omitted)

public static void main(String[] args) {

// just for testing – this would be injected in production, of course
String[] xml = { “DatabaseContext.xml”};
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( xml );
PersonDao dao = (PersonDao)ctx.getBean(“PersonDao”, PersonDao.class);

// try persisting a person
Person p = new Person(“ben”, 28);
dao.save(p);

// look them back up
System.out.println(“Looking up person with id=1”);
Person p1 = dao.findById(1);
System.out.println(“Found person ” + p1.getName());

// let’s assume we have more data
System.out.println(“Looking up all people”);
for (Person person : dao.findAll()) {
System.out.println(“FOUND ” + person.getPerson());
}

// lookup a person by example – poor mans criteria query
Person example = new Person(“”, 30);
System.out.println(“Looking up all 30 year olds, ignoring name”);
for (Person person : dao.findByExample(example, new String[]{“name”}) ) {
System.out.println(“FOUND ” + person.getName());
}

}

Excellent! That all worked like a charm without any actual code!

Of course it took some time to write the GenericDao, which I will present below, but it only had to be written the once. Very nice.

// the generic interface
public interface GenericDao<T> {
T findById(Integer id);
List<T> findAll();
public List<T> findByExample(T o, String[] excludeProperty);
T save(T o);
void delete(T o);
}

And the generic implementation:

// slightly tied to spring for convenience, but obviously not necessary
public class GenericHibernateDao<T> extends HibernateDaoSupport implements GenericDao<T> {
private final Class<T> persistentClass;
private final static Logger log = Logger.getLogger(GenericHibernateDao.class);

public GenericHibernateDao(final SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
this.persistentClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
// all the CRUD implementations
@SuppressWarnings(“unchecked”)
public T findById(Integer id) {
log.debug(“Finding by id ” + id);
return (T) super.getHibernateTemplate().get(getPersistentClass(), id);
}
public List<T> findAll() {
log.debug(“Finding all”);
return findByCriteria();
}
@SuppressWarnings(“unchecked”)
public List<T> findByExample(T o, String[] excludeProperty) {
log.debug(“Looking up ” + o);
Criteria crit = getSession().createCriteria(getPersistentClass());
Example example = Example.create(o);
for (String exclude : excludeProperty) {
example.excludeProperty(exclude);
}
crit.add(example);
return crit.list();
}

public T save(T o) {
log.debug(“Saving and returning ” + o);
super.getHibernateTemplate().saveOrUpdate(o);
return o;
}
public void delete(T o) {
log.debug(“Deleting ” + o);
super.getHibernateTemplate().delete(o);
}
// and the helper methods
private Class<T> getPersistentClass() {
return persistentClass;
}
@SuppressWarnings(“unchecked”)
protected List<T> findByCriteria(Criterion… criterion) {
Criteria crit = getSession().createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
}

Thanks to this Hibernate forum post and this blog post for the help. And screw wordpress for ruining my code formatting 😉 Sorry about that.