Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] session handling for multi-threaded fat client

If you use the same DatabaseSession for both threads, then they will be
sharing eachothers uncommitted data, and potentially committing/rolling back
each others changes (regardless of whether you make commit() synchronized). 
This is probably not good, but it depends on what the background thread is
doing exactly?  Is it read-only, what is it doing?

It is possible to create a ServerSession with a single connection (although
this may not be a good idea).  Just set the ServerSession readConnectionPool
and default writeConnectionPool to the same ConnectionPool objects that has
a single connection.  This however will require that one thread wait for the
other to finish using its connection before it can use it (query or commit).

i.e.
serverSession.setReadConnectionPool(serverSession.getDefaultConnectionPool());


Anthony Oganesian wrote:
> 
> 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
> 
>     }
> 
> 


-----
---
http://wiki.eclipse.org/User:James.sutherland.oracle.com James Sutherland 
http://www.eclipse.org/eclipselink/
 EclipseLink ,  http://www.oracle.com/technology/products/ias/toplink/
TopLink 
Wiki:  http://wiki.eclipse.org/EclipseLink EclipseLink , 
http://wiki.oracle.com/page/TopLink TopLink 
Forums:  http://forums.oracle.com/forums/forum.jspa?forumID=48 TopLink , 
http://www.nabble.com/EclipseLink-f26430.html EclipseLink 
Book:  http://en.wikibooks.org/wiki/Java_Persistence Java Persistence 
-- 
View this message in context: http://www.nabble.com/session-handling-for-multi-threaded-fat-client-tp22031861p22059498.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.



Back to the top