У меня есть приложение, написанное на Java, Spring, Hibernate, Postgres.Параллельные объекты, которые читают/обновляют с помощью Hibernate и Postgres
Он отслеживает попытки входа пользователя в систему. Если пользователь имеет более 5 недопустимых попыток с одного и того же IP-адреса менее чем за 1 час - этот IP-адрес будет заблокирован.
У меня есть следующий класс сущностей для хранения информации о попытках входа в систему:
@Entity
public class BlockedIp {
private String ipAddress;
private Date blockDate;
private Date unblockDate;
private Date lastAttemptDate;
private Integer wrongAttemptsCount;
...}
Во-первых, когда приложение получает логин запрос - он проверяет IP-адрес уже заблокирован (blockDate! = NULL). Затем в результате возвращается специальный код ответа пользователю.
Если приложение получает логин запрос и учетные данные неверны:
- , если последняя попытка была меньше, чем 1 час назад - он увеличивает wrongAttemptsCount и если (wrongAttemptsCount == 5) - устанавливает blockDate.
- , если последняя попытка была более чем 1 час назад - он устанавливает wrongAttemptsCount к 1.
Если приложение получает запрос входа в систему и учетные данные правильны - он сбрасывает wrongAttemptsCount к нулю, так что пользователь может сделать до 5 ошибок снова :)
Проблема в том, что некоторые пользователи пытаются одновременно войти в систему с одного и того же IP-адреса. Например, wrongAttemptsCount = 4, поэтому пользователь может иметь только одну последнюю попытку. И у нас есть 3 входящих запроса, и все они имеют неправильные учетные данные. Теоретически, только первый запрос будет проходить, но два других будут заблокированы. На практике, конечно, все ошибаются. Атрибут «Захват» равен 4 от базы данных, поэтому все они будут обрабатываться как незаблокированные.
Итак, какие варианты я должен решить эту проблему и с минимальными потерями производительности, если это возможно? Я думал о инструкции SELECT FOR UPDATE для моего запроса, но мой коллега сказал, что это серьезно ударит по производительности. Также он предложил посмотреть аннотацию @Version. Это действительно стоит? Это намного быстрее? Возможно, кто-то может предложить другие варианты?
позволяет обобщить. Что касается моего вопроса, я должен: 1) использовать аннотацию 'Version' (ввести в нее какое-то специальное поле в моей сущности), 2) catch' StaleStateException' во всех методах, которые сохраняют \ обновлять этот объект, 3), если такое исключение происходит - снова получить объект, чтобы получить его новое состояние и повторить все шаги моего алгоритма. Я прав? – kumade
Вы правы. Шаг 3 должен запускаться в новой транзакции/сеансе. –