current situation: I have a service with several typical service methods like create(), remove(), findXy(), .. etc. Now I want to prevent two different service calls at the same time, meaning I want to lock my servicecall, after entering it the first time, so the second client (or same client again) will only enter the method as soon as first client is done.
For locking purposes we normally use ReentrantLocks. They work perfectly fine. But now i am doubting on how to implement these ReentrantLocks, since I dont want to insert them in every single method. Moreover our servicelayers define their Transaction context already on their own, which means, when I would integrate them in the method itself, a transaction is already started before the lock has happen.
public class WorkerServiceServerImpl implements WorkerServiceRemote
{
private static final ReentrantLock workerLock = new ReentrantLock( true );
@Autowired
private WorkerDao workerDao;
@Override
@Transactional
public int createWorker( int projectId ) throws RemoteException
{
workerLock.lock();//NO GOOD! Transaction already started!
try
{
workerDao.create( projectId );
//Do some more stuff...
}
finally
{
workerLock.unlock();//Unlock, next request can be handled!
}
}
...
}
Of course I could create a ServiceLayer above this WorkerServiceImpl class and just forward the calls to the original service, but since I have like 30 services I wonder, if there are any global solutions to solve this issue. Or is it possible to create an own annotation which fires before a transaction is started?
Any ideas are welcome, thanks in advance!
ymene
EDIT: I choose CRUD methods for simplicity. Of course those service calls are far more advanced and can call different CRUD-Methods within one call.
There are several points that can be made regarding this design:
The need to apply locks to service methods looks strange. If you have some problems with concurrent execution of service methods, perhaps it would be better to solve them by proper configuration of transactions when accessing an underlying database.
unlock()must be called inside afinallyblock.If your service is singleton, your use of
ReentrantLockis equivalent to marking your methodssynchronized.You can create an aspect to apply synchronization to your methods. See 7. Aspect Oriented Programming with Spring, especially 7.2.4.7 Advice ordering.