Monday, December 14, 2009

Eclipselink: table sequence generator and concurrency - Part Two, Custom Sequence generator

In my previous post I explained how EclipseLink TableGenerated primary keys have a problem with concurency. I'm not sure why and whether other people had the same problem, but what can you do? Well, we had to do something.

First, I cosidered possibility of different configuring of primary key generation straegy for different platforms, using master entity superclass and confguring with XML descriptors (actually combining XML descriptors and annotations).

The, I tried to find some solution that enables us to somehow make EclipseLink use some alternative method of primary key generation. Fortunately, it did not take long.

On EclipseLink wiki there is an example of custom sequencing using UUID. Now, UUID generation is something we came across while using Hibernate, who has some issues using HashMaps and identifying objects, so generating UUID used in isEqual methods for objects is very recommender. Using UUID as primary key sounded interesting, but, frankly, I did not feel like modifying database schema...

So I wondered, why not making my own, concurrency safe version of table sequencing? After all, it is very nice solution, takes my mind of thinking whether I use MS, Oracle or whatever DB and I dont bother worrying over whether identity columns will do just as good job as Oracle sequences...

Let's look into customizing sequencing.

You can extend Eclipselink classes Sequence and StandardSequence. You also have to implenent SessionCustomizer interface.

public class UUIDSequence extends Sequence implements SessionCustomizer{

Now, look into the class. For us important methods are

public Object getGeneratedValue(Accessor accessor,
AbstractSession writeSession, String seqName) {
return UUID.randomUUID().toString().toUpperCase();
}
and

public void customize(Session session) throws Exception {
UUIDSequence sequence = new UUIDSequence("system-uuid");

session.getLogin().addSequence(sequence);
}

getGeneratedValue method, well, returns the generated sequence value in whatever way we want. In the example UUID is used, so simply radnom generated uuid value is returned from the method.

But, how do we make Eclipselink use our sequence generator? customize method is used for this. As you can see, a new instance of our sequence class is created with our specific name given to constructor, and our sequence is added to session. To tell eclipselink that we are using our custom generator we add a property in the persistence unit

 name="eclipselink.session.customizer" 
value
="eclipselink.example.UUIDSequence"/>
Where value of the property is full qualified class name of our Sequencing class.

And that is it. I'm not really sure how this works, but persistence unit sees that it has customizable class, method customize is called and our sequence is set. When you want to use sequence in your JPA entities, you siply specify name you passed to constructor

@Id
@GeneratedValue(generator="system-uuid"/>
@Column(name="PROJ_ID")
private int id;

In the next post we will make similar class which will use our own table generated sequence. And yes, it is quite simple :)

Wow, not bad post after 10 days of flu...

3 comments:

  1. Any update on the "next post" which shows you custom sequence generator? I am in the middle of doing one myself so I am interested in looking at what you have done.

    Thanks.

    Brett

    ReplyDelete
  2. Post is 70% done for about month now, and for reasons unknown I havent wrote the rest of it :D
    Sure, I will post it in next few days. Thanks for reading!

    ReplyDelete
  3. Thanks. I am running into a problem using Derby with its Idenity generator (it has a bug where it hangs generating an ID for another thread until the main thread completes). So I am looking to use a Table Generator but the EclipseLink Table Generator in the 1.x line does not support allocating the next sequence of ID's in a separate unrelated transaction so that hangs until the main transaction is done. EclipseLink 2.x line does support this but is not supported in Glassfish V2.1 so I cannot use that either.

    So I am looking to write my own ID generator using the session customizer.

    Again, thanks in advance.

    Brett

    ReplyDelete