[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[eclipselink-users] session handling for multi-threaded fat client
|
Dear all,
I have the following problem and would greatly appreciate any feedback to my
proposed solutions. I am leaning towards "Solution 2" but possibly there is
another easier way?
Thanks a lot in advance!
--
Tony
== Problem description ==
* Two-tiered (fat client) application with heavy DB access on the main UI
thread.
* Application has a low-priority background thread which needs DB access as
well
My current approach to providing DB access in the code follows and is
incorrect:
* Once during application startup I create a DatabaseSession and keep it as
a static variable in my utility class (ApplicationDataConnector).
* Anywhere in the application I access this session via getSession() method
which results in different threads accessing the same session possibly at
the same time. (I did get a ConcurrentModificationException just by calling
readAllObjects())
class ApplicationDataConnector
{
private static Session globalSession;
public static init()
{
globalSession = project.createDatabaseSession();
}
public static Session getSession()
{
return globalSession;
}
}
== Possible Solution 1 ==
Create a ServerSession and provide ClientSession instances upon request.
Unfortunately I was not able to configure the ServerSession to only open one
connection. It insists on creating a readOnlyPool in addition to a regular
pool and at a minimum creates 2 connections to the DB. In my case this
defeats the purpose as I could have just as well allocated a separate
connection to my background thread. Maintaining 2 connections is not an
option in my opinion. Any help here is appreciated. Maybe there is a way to
limit a ServerSession to one connection?
class ApplicationDataConnector
{
private static ServerSession globalSession;
public static init()
{
globalSession = project.createServerSession();
}
public static Session getSession()
{
return globalSession.acquireClientSession();
}
}
== Possible Solution 2 ==
Extend a DatabaseSessionImpl and manually perform synchronization, which
should not be a bottle-neck in my scenario.
For the UnitOfWork I had to copy the acquireNonSynchronizedUnitOfWork method
to inject my UnitofWork extension.
I really need some feedback in this scenario. Is it a good idea? Any
problems I am missing?
class ApplicationDataConnector
{
private static SynchronizedSession globalSession;
public static init()
{
globalSession = new SynchronizedSession(project);
}
public static Session getSession()
{
return globalSession
}
}
public static class SynchronizedSession extends DatabaseSessionImpl
{
public UnitOfWorkImpl acquireNonSynchronizedUnitOfWork(ReferenceMode
referenceMode) {
setNumberOfActiveUnitsOfWork(getNumberOfActiveUnitsOfWork() +
1);
UnitOfWorkImpl unitOfWork = new UnitOfWorkImpl(this,
referenceMode)
{
public void commit() throws DatabaseException,
OptimisticLockException
{
synchronized(SynchronizedSession.class)
{
super.commit();
}
}
// Override and "synchronize" more UnitOfWorkImpl methods as
needed
};
if (shouldLog(SessionLog.FINER, SessionLog.TRANSACTION)) {
log(SessionLog.FINER, SessionLog.TRANSACTION,
"acquire_unit_of_work_with_argument",
String.valueOf(System.identityHashCode(unitOfWork)));
}
return unitOfWork;
}
public synchronized Vector readAllObjects(Class domainClass,
Expression selectionCriteria) throws DatabaseException
{
return readAllObjects(domainClass, selectionCriteria);
}
public synchronized Object executeQuery(DatabaseQuery query) throws
EclipseLinkException
{
return executeQuery(query);
}
// Override and "synchronize" more methods as needed
}