Berkeley Bits

January 26, 2007

Transactions, Hibernate Sessions, and Spring initialization

Filed under: Hard-Won Wisdom — jholtzman @ 5:03 pm

Sakai’s CM service is very chatty. In particular, there are two places that make many small calls to CM. The first is Sakai’s CM-based GroupProvider. The second is a data loader to populate CM with a sample university SIS.

In both the GroupProvider and the data loader, I’ve been noticing some pretty poor performance. After reading a lot of spring source code and hacking in some extra logging, I realized why. If I call the CM service from outside of its transaction boundary, I get a new hibernate session for each CM call. When each method call uses a unique hibernate sessions, we get no L1 caching at all. And without a properly configured second level cache in Sakai, this means that there’s no object caching at all, and CM — due to the shape of the api — is just going to perform horribly.

Fortunately, there’s a way around performance bottleneck. If I make the CM calls from within one of the global transaction manager’s transactions, all of the hibernate activity will share the same session and will thus take advantage of hibernate’s L1 object caching.

Well, this worked pretty well for the GroupProvider. I noticed much less DB activity after I wrapped the GroupProvider impl in a transaction proxy. But what about the data loader? Well, the data loader does its thing during startup, with an init() called by spring after the bean has been instantiated and its dependencies set. That means that the data load occurs becore the current thread has a transaction bound to it. So even though the loader is wrapped in a transaction proxy, the init() isn’t transactional.

Of course, this didn’t deter me. I just need another spring bean to do the initialization, so it’s init() calls the dataloader’s init() through the transaction proxy! Brilliant, no?

No.

I believe the reason why this didn’t work is because the transaction proxies are set up with bean post processors, and my init() was run before the post-processing. Oh well, I guess having a slow sample data load (which is only for demo purposes) is better than having slow runtime performance.

Powered by WordPress