простой вопрос дизайна об оптимистичной блокировке в spring/jpa/hibernate

У меня есть объект GeneralKnowledgeTest, и он содержит множество полей статистики (ratingsCount, responsesCount, ratingStars...), которые обновляются каждый раз, когда пользователь проходит этот тест (takeTest() -> транзакционный метод).

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

Итак, внутри метода takeTest я всегда получаю новый экземпляр GeneralKnowledgeTest, например. entityManager.find(testId), а затем обновите его поля статистики. В случае возникновения оптимистичного исключения перехватчик просто повторяет попытку метода takeTest до тех пор, пока он не завершится успешно.

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

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


person Rem Ma    schedule 01.03.2011    source источник


Ответы (2)


Я предполагаю, что эта статистика обновляется только в конце теста, а тесты занимают разумное количество времени, поэтому это снизит вероятность сбоя оптимистичной блокировки. Кроме того, есть ли вероятность того, что пользователи будут выполнять тест в пакетном режиме, например, в результате запуска теста в установленное время? Это повысит вероятность того, что замок не сработает.

Если пропускная способность такова, что одновременные обновления все еще вероятны, то вам лучше агрегировать статистику в памяти (поточно-ориентированным способом) и периодически записывать ее в базу данных.

person Will    schedule 01.03.2011
comment
Очень вероятно, что тест может быть пройден и завершен в одно и то же время многими пользователями (например, тест дня и так далее...). Я читал, что с оптимистичной блокировкой все в порядке с точки зрения производительности, поэтому блокировки базы данных нет. (представьте, что 100 пользователей проходят/завершают один и тот же тест за одно и то же время, также учтите, что takeTest — это сложный метод, который создает много дополнительных объектов БД, что делает транзакцию немного дольше). Но вообще говоря, что-то не так с подходом, который я предложил? Есть ли ошибки или недостатки? заранее спасибо - person Rem Ma; 02.03.2011
comment
Нет, ошибок нет. Сбой оптимистической блокировки приведет к повторному чтению данных, что увеличит нагрузку на базу данных, а повторение логики проверки увеличит нагрузку на ЦП. В этом подходе нет ничего плохого, он просто зависит от того, как часто вы ожидаете, что блокировка выйдет из строя. - person Will; 02.03.2011

Это звучит как правильный подход:

Hibernate проверяет версии экземпляра во время сброса, выдавая исключение, если обнаруживается одновременная модификация. Разработчик должен поймать и обработать это исключение. Общие параметры — это возможность для пользователя объединить изменения или перезапустить деловой разговор с неустаревшими данными.

Вы также можете посмотреть, как установить для IsolationLevel значение SERIALIZED или заблокировать строку таблицы.

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

person Stijn Geukens    schedule 01.03.2011