My old application following chain to query my database: Spring Tx -> Hibernate -> C3P0
. Now I need to implement new features based on the existing architecture.
I normally enter a transactional context by using either the @Transactional
annotation or manually invoking the PlatformTransactionManager
.
Sometimes, to perform asynchronous and big data operations, I open a stateless session using the SessionFactory
API. We never had any additional problem as our thread pool is well controlled
For the first time, my requirement is to perform several DB operations in parallel to speed up performance. I have a doubt about it, because I am extremely careful about multithreaded operations.
For each entity in the database, I can perform a reconciliation operation on a separate thread. But each reconciliation operation uses a pair of connections for each of the two threads it spawns. So there are basically 4 connections for each thread.
Multithreading class teaches students that in order to prevent a deadlock (eating philosophers issue), resources shall be acquired in a transactional way: once you have acquired a fork, if you cannot acquire the second in a reasonable time, release the first and try again.
My question is simple. Given the SessionFactory
API, how can I write code that won't wait indefinitely for 4 connections from c3p0 if the pool is full? I mean I need 4 StatelessSession
s only if there is room for 4, otherwise I can wait and retry.
As far as I know, the SessionFactory
API is blocking and does not allow to set a watchdog
Currently the idea is to use the plain old workaround.
In general, in Java world, if an API does not offer a watchdog method for acquiring a resource, you can delegate that to a Future
, which offers get(int timeout, TimeUnit timeUnit)
API to constrain the execution.
So basically, how do I get a stateless session within the bounds of a timeout?
private Future<StatelessSession> getStatelessSession(SessionFactory sessionFactory)
{
return asyncTaskExecutor.submit(new Callable<StatelessSession>()
{
@Override
public StatelessSession call() throws Exception
{
return sessionFactory.openStatelessSession();
}
});
}
try {
StatelessSession session = getStatelessSession(sessionFactory).get(3000,TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// go to step 2
}
As I said, my problem looks basically like the dining philosopher, except that we don't just have two forks but spoons and knives to take for a total of 4.
StatelessSession session1, session2, session3, session4;
for (int i=0; i<MAX_ATTEMPTS;i++) {
try {
session1 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
continue;
}
try {
session2 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session1.close();
continue;
}
try {
session3 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session2.close();
session1.close();
continue;
}
try {
session4 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session3.close();
session2.close();
session1.close();
continue;
}
}
What happens if you go beyond MAX_ATTEMPTS
is up to you, developer!