Donnerstag, 5. März 2009

Avaje - Repeatable Read and Auto-Fetch

code hosted at copy-con-goodies

Today I'll tell you something about Avaje, my new best friend for database access.

First of all, one can not say that this library is bug-free, but Rob (as far as I know the main developer) makes a very good job in applying my patches ;-).
Seriously, it is an awesome piece of code which is just to young to work in each and every use-case JPA is designed for. What makes it my fav is, that I managed to dig into the code in just one weekend. Nicely structured!

Repeatable Reads

The first thing you have to take into account - compared to any other JPA implementation - is, that Avaje does not need a PersistenceContext, for an Web-Application this means, you do not have to make sure you issue each database request against the same PersistenceContext.
If you look at this example you can find the following lines of code:
    // read entity without transaction ... this automatically creates one just for this very statement
    TestEntity readEntity1 =
        server.find(TestEntity.class, 1L);

    // and again. We now read the same database row but got two independent instances
    TestEntity readEntity2 =
        server.find(TestEntity.class, 1L);
Withouth any provisioning you will get two instances of the same row. Sure, you have to keep in mind that, if you change and update readEntity1 and later on you do the same with readEntity2 you will face a concurrent modification and get an exception. But how often will you have to deal with that on a web-page?

Now, if you need the feature to get the same instance for the same entity you simply put a transaction around, so the code above becomes:
    // now lets start a transaction
    Transaction tx = server.beginTransaction();
    TestEntity readEntity1_1 =
        server.find(TestEntity.class, 1L);

    TestEntity readEntity2_1 =
        server.find(TestEntity.class, 1L);

    // we now got the same instance for the same row  
This effectively means you can have the best of both worlds. Normally you would not care about "repeatable reads" and simply use your entities, if (for example you start multiple processes to update various data) you need to ensure to get the same instance from an database access you simply put a transaction around.
And this is something you would do anyway as you will update data, no?


Another VERY nice concept of Avaje is auto-fetch.
I've added a little code to the exaple code above which allows you to dig into that feature.
I will see I access the property field1 and field2 from the various bean instances.
  readEntity1.getField1(); // read content of field1

  readEntity2.getField2(); // read content of field2
On the first run the sql for reading readEntity1 you will see Avaje will fetch (not very surprisingly) all the properties from the database
<sql summary='[TestEntity]'>
    select e.ID c0, e.FIELD_1 c1, e.FIELD_2 c2, e.VERSION c3 
    from TEST_ENTITY e
    where e.ID = ?  
But at the end Avaje will collect the statistics and persist them into a local file using the .autofetch extensions.
Now, on the second run the sql will look different
<sql summary='[TestEntity] autoFetchTuned[true]'>
    select e.ID c0, e.FIELD_1 c1, e.VERSION c2 
    from TEST_ENTITY e
    where e.ID = ?  
Do you notice? FIELD_2 is no longer fetched from the database.
It might happen that you change your code, or your programm takes other routes through the code and it requires FIELD_2 now, Avaje will fetch the field lazily and learn this fact. Next time it will prefetch it too.

This also works for e.g. OneToMany associations. This means, you no longer have to think about making an association lazy or not, it also frees you from making associations lazy - and then adding code to load them eager sometimes.
Avaje simply will learn that from your code by capturing the stack-trace and storing access information to these points.

Imagine what a performance boost this can be for your program!

You can find more infomation about this astounding feature here.

Keine Kommentare:

Kommentar veröffentlichen