Мне нужно реализовать решение для генерации серийных номеров для объектов разных видов, но одного и того же типа (тот же класс, та же таблица). Более того, правила генерации серийных номеров определяются во время выполнения (начальный серийный номер, максимальное количество и т. д.). Я использую MySQL, спящий режим MySQL5Dialect не поддерживает генерацию последовательности, поэтому я решил реализовать эту функцию с помощью таблицы последовательности, где каждая строка представляет собой последовательность для разных типов объектов:
+--------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| seqenceName | varchar(255) | NO | PRI | NULL | |
| nextVal | bigint(20) | NO | | NULL | |
+--------------------+--------------+------+-----+---------+-------+
Я создал дао, который увеличивает значение:
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;
}
И это вызывается из сервисного уровня как:
@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;
}
Я пробовал все: установил уровень изоляции Isolation.SERIALIZABLE
, чтобы программно зафиксировать транзакцию внутри метода, добавив к нему ключевое слово synchronized
, также добавил запрос на блокировку, но я думаю, что он устарел, поскольку уровень изоляции уже установлен.
Тем не менее, если я создам 100 потоков и вызову этот метод 60 раз из каждого, в результате значение столбца nextVal
будет около 4000 вместо 6000.
Я подозреваю, что здесь мне не хватает какой-то очень простой вещи, но я не могу понять, что нужно для того, чтобы это работало должным образом.
Спасибо за любые подсказки!