First your lock Object always should be declared final
. This isn't fixing any problems, but it tells you if you did code something wrong (like setting the lock to a different lock somewhere).
One way to ensure fairness is to use a ReentrantLock initialized with true (fair scheduling). It will ensure that clients do not hang indefinitely, but are executed in a FIFO order. The good thing is that this requires only a minor change to your code, by replacing all those synchronized blocks with:
lock.lock();
try {
// previous code
} finally {
lock.unlock();
}
The finally is just a safety measure, should any part inside throw an exception.
Other than that your code looks perfectly fine, so the issue is most likely in the DB and not caused by using synchronized at all.