I need to implement a solution to generate serial numbers for objects of diferent kinds but same type (same class, same table). What's more the rules for serial generation are defined at runtime (starting serial, maximum number, etc.). I'm using MySQL, hibernate MySQL5Dialect does not support sequence generation, thus I chose to implement this feature using a sequence table where each row is a sequence for a different kind of objects:
+--------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| seqenceName | varchar(255) | NO | PRI | NULL | |
| nextVal | bigint(20) | NO | | NULL | |
+--------------------+--------------+------+-----+---------+-------+
I created a dao which increments the value:
public synchronized long getNextValue(String seqenceName) throws MySequenceNotFoundException {
MySequence seq = findByID(seqenceName);
if (seq == null) {
throw new MySequenceNotFoundException("Sequence does not exist with name: " + seqenceName);
}//if not exists
long nextVal = seq.getNextVal();
getCurrentSession().saveOrUpdate(seq);
return nextVal;
}
And this is called from the service layer as:
@Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE)
public synchronized long incSequence(String seqName) throws MySequenceNotFoundException {
getCurrentSession().getTransaction().begin();
MySequence seq = sequenceDao.findByID(seqName);
LockRequest lockRequest = getCurrentSession().buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE));
lockRequest.lock(seq);
long l = sequenceDao.getNextValue(seqName);
getCurrentSession().getTransaction().commit();
return l;
}
I tried everything: setting isolation level to Isolation.SERIALIZABLE
, to programmatically commit the transaction within the method, adding synchronized
keyword to it, also added a lock request but I think it's obsolete as the isolation level is already set.
Still if I create 100 threads and call this method 60 times from each, the result is that the value of the nextVal
column is around 4000 instead of 6000.
I suspect I missing some very basic thing here but cannot find out what is needed for this to work as expected.
Thanks for any hints!