2013-09-13 2 views
1

Я пишу систему, которая держит спящего режима управляемого объект под названием Voucher, который имеет поле с именем serialNumber, который содержит уникальный номер для единственного существующего действительного копию ваучера экземпляра , В таблице базы данных могут быть старые и недопустимые копии, что означает, что поле базы данных может не быть объявлено уникальным. Операция, которая сохраняет новый действительный экземпляр ваучера (который будет нуждаться в новом серийном номере), в первую очередь синхронизируется с соответствующим объектом. После этого вся процедура инкапсулируется в транзакции, то новое значение извлекается с помощью JPQLОбеспечение уникальных серийных номеров в сеансе Hibernate

SELECT MAX(serialNumber) + 1 FROM Voucher 

поле получает результат из запроса, экземпляр после этого сохраняется, сеанс сбрасывается, транзакция совершается и код, наконец, покидает синхронизированный блок.

Несмотря на все это, база данных иногда (если редко) заканчивается ваучерами с повторяющимися серийными номерами.

Мой вопрос: учитывая, что я довольно уверен в синхронизации и обработке транзакций, есть ли что-то более или менее очевидное, что я должен знать о спящем режиме, который я пропустил, или мне нужно вернуться к еще одному сеансу отладки, пытаясь найти что-нибудь еще, что вызвало проблему?

Служба, выполняющая процесс сохранения, представляет собой веб-приложение, работающее на tomcat6, и управляется Spring HttpRequestHandlerServlet. Соединения db объединяются с помощью C3P0, при этом выполняется очень большая настройка по умолчанию.

Я ценю любое предложение,

Благодарности

+0

Какие СУБД вы используете? –

+0

Обычный старый MySQL – TompaBompa

ответ

0

Вы можете использовать MultipleHiLoPerTableGenerator: он генерирует @Id вне текущей транзакции.

+0

Использование этого класса для меня очень незнакомо. Может ли кто-нибудь, пожалуйста, привести мне пример, насколько это возможно? – TompaBompa

+0

http://ibookmate.blogspot.com/2010/02/hibernate-annotation-and.html http://blog.eyallupu.com/2011/01/hibernatejpa-identity-generators.html http://alvinalexander.com /java/jwarehouse/hibernate/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java.shtml –

0

Вам не нужно отлаживать, чтобы найти причину. В многопоточной среде это, скорее всего, произойдет. Вы выбираете max из своей таблицы. Предположим, что TX1 считывает максимальное значение, которое равно a, и вставляет строку с серийным номером a+1; на этом этапе, если какой-либо TX2 считывает DB, максимальное значение остается a, поскольку TX1 не передал свои данные. Поэтому TX2 может вставить строку с серийным номером a+1.

Чтобы избежать этой проблемы, вы можете решить изменить уровень изоляции своей базы данных или изменить способ получения серийных номеров (это полностью зависит от обстоятельств вашего проекта). Но обычно я не рекомендую менять уровни изоляции, так как это слишком много усилий для такой проблемы.

+0

Но чтение MAX из таблицы является частью синхронизированного кода. Для этой цели не должно быть другого потока, читающего эту таблицу, прежде чем будет записано и зафиксировано новое значение MAX. – TompaBompa

Смежные вопросы