Skip to content
Print

An Easier Java ORM Part 3

24
Jul
2007

As a continuation to part 1 and part 2, this article examines a slightly less interesting (though none-the-less important) feature, transactions in ActiveObjects.

I also figured I should give a minor update on the development status. Eelco Hillenius (of the Wicket project) has been contributing some code, fixing up areas where I messed up and cleaning up one of the sample projects (the DogfoodBlog sample, based on Wicket). We’ve also been looking into areas where Wicket and ActiveObjects could be more easily integrated (such as entity-specific models and lists). I’ve been keeping busy trying to stabilize some of other database providers. We now officially support (in the trunk/) the following databases:

  • Derby (standalone and embedded)
  • MySQL
  • PostgreSQL
  • Oracle (with the limitation that @AutoIncrement is only supported on primary keys)

We also have the following (almost untested) providers:

  • Microsoft SQL Server (Microsoft and JTDS providers)
  • HSQLDB (standalone and embedded)

I’m hardly an expert in any of the above databases, so I welcome any and all input on bugs/errors/etc…

Transactions

While I might qualify transactions as comparatively unimportant, anyone who’s written a multi-user web application knows how significant they can be in maintaining data integrity. An ORM which didn’t support transactions would be sorely crippled indeed.

Hibernate solves the problem of transactions by forcing every database action to be wrapped in a transaction and committed at the close. This works well, but the significant downside is that it increases code complexity and forces the developer to remember to explicitly close every transaction. As before, I’ve tried to take some inspiration from ActiveRecord’s implementation of concepts:

p = Person.find(1)
lc = LibraryCard.find(321)
 
transaction do
    p.first_name = 'Daniel'
    p.last_name = 'Spiewak'
    p.save
 
    lc.person_name = 'Daniel Spiewak'
    lc.save
end

As is typical of ActiveRecord, this is an amazingly intuitive syntax. Unfortunately, again in accordance with the ActiveRecord MO, it depends upon a very DSL-like syntax. We might not be able to match the syntax exactly in Java, but we can fairly close:

new Transaction(manager) {
    public void run() {
        Account david = getEntityManager().get(Account.class, 1);
        david.setValue(david.getValue() - 1000);
        david.save();
 
        Account mary = getEntityManager().get(Account.class, 2);
        mary.setValue(mary.getValue() + 1000);
        mary.save();
    }
}.execute();

Obviously, we could potentially have gone with the less verbose:

Transaction t = new Transaction(entityManager);
t.begin();
// blah
t.commit();

However, this syntax doesn’t have the major advantage of the ActiveRecord DSL which is ensuring the transaction is closed. Also, with our anonymous inner-class syntax, we can do something like this:

new Transaction(manager) {
    public void run() {
        // yadda yadda yadda
    }
}.executeConcurrently();

This will execute the transaction in a separate thread, rather than blocking the current one. I haven’t actually seen a proper use-case for this so far, but it’s bound to have some application. :-)

Limitations

The trick with transactions in JDBC is all queries must be run against the same Connection instance. To accommodate this, an internal abstraction class is used by the ActiveObjects interface proxy to ensure that if a transaction is in progress, a single Connection is used, rather than opening a new one from the database provider. This works quite well, but it has its limitations.

Specifically, any custom code executed within the transaction which uses a Connection instance directly will run its SQL statements outside of the transaction boundaries. Any EntityManager method (get, find, findWithSQL, count, etc…) will work within a transaction, but any direct use of a Connection instance will likely cause unexpected behavior. I have a plan to fix this problem, but I haven’t gotten around to implementing it yet. Hopefully in a shortly upcoming release…

Comments

  1. Is described transaction syntaxt already available in ActiveObject ot is it the proposal only?

    Thanks
    David

    David Marko Wednesday, July 25, 2007 at 11:56 pm
  2. It’s fully available and working (as far as I can tell). I don’t have any applications which explicitly test to see if they’re working.

    Daniel Spiewak Thursday, July 26, 2007 at 9:28 pm
  3. Hi Daniel,

    There is another interesting ORM framework called Ammentos:

    http://ammentos.biobytes.it/

    I find it very amazing..

    thanks

    Nicola

    Nicola Viragine Friday, July 27, 2007 at 7:52 am
  4. Ammentos is interesting, but it still relies upon the POJO model, Lists, etc… It doesn’t do migrations or schema generation, and it requires a *ton* of parameterized annotations to wire everything together. It’s kind of cool, but it seems like just an XML-less JPA.

    Daniel Spiewak Friday, July 27, 2007 at 11:17 am
  5. Hello!

    Do you have any idea why this do not work in beanshell?

    bsh % new Transaction(fimi.Main.em){
    public void run(){
    null;
    }
    }.execute();
    // Error: EvalError: Error constructing inner class instance: bsh.ReflectError: Can’t find constructor: global$2( net.java.ao.EntityManager ) in class: global$2 : at Line: 1 : in file: : new Transaction ( fimi .Main .em ) {

    bsh %

    The EntityManager should be OK:
    bsh % print(fimi.Main.em.toString());
    net.java.ao.EntityManager@16c9867
    bsh %

    Thank You
    Christian

    Christian Wednesday, February 27, 2008 at 11:17 am
  6. I’m going to take a wild guess and say that it’s probably got something to do with the way that BeanShell creates dynamic proxies for objects and such. I honestly don’t know though (don’t use BeanShell very much).

    Daniel Spiewak Wednesday, February 27, 2008 at 11:21 am
  7. Thanks for your fast Reply Daniel.
    It is enough for me to know that its is a Beanshell problem.

    Christian Thursday, February 28, 2008 at 12:21 am

Post a Comment

Comments are automatically formatted. Markup are either stripped or will cause large blocks of text to be eaten, depending on the phase of the moon. Code snippets should be wrapped in <pre>...</pre> tags. Indentation within pre tags will be preserved, and most instances of "<" and ">" will work without a problem.

Please note that first-time commenters are moderated, so don't panic if your comment doesn't appear immediately.

*
*