Вот случай,
Участник должен выкупить токен, чтобы получить доступ (разблокировать) данный предмет. Соответствующие таблицы базы данных:
Таблица 1
Table MEMBER_BALANCE: MEMBER_ID, TOKEN_BALANCE
Таблица 2
Table UNLOCKED_ITEM: MEMBER_ID, DATE_UNLOCKED, ITEM_ID
Проверки или ограничения, которые мне нужно применить, являются
- TOKEN_BALANCE должно быть> 0, когда пользователь пытается разблокировать элемент, и
- Пользователь не разблокировал тот же элемент раньше.
Я склонен писать простой метод в MemberService.java:
.
@Transactional
public void unlockItem(Member member, Item item){
memberBalanceDAO.decrementBalance(member);
itemDAO.unlockItem(member, item);
}
Я выполнил второе требование, добавив ограничение unique
для пары MEMBER_ID
/ ITEM_ID
в таблице UNLOCKED_ITEM
.
Я думаю, единственное, о чем мне нужно позаботиться, это о том, чтобы пользователи пытались разблокировать множество элементов одновременно, при этом требование TOKEN_BALANCE
не выполнено. Например, TOKEN_BALANCE
равно 1, но пользователь щелкает, чтобы разблокировать два элемента практически одновременно.
Ниже мой MemberBalanceDAO.decrementBalance
метод:
@Transactional
public void decrementBalance(Member member) {
MemberBalance memberBalance = this.findMemberBalance(member);
if (memberBalance.getTokens() >= 1) {
memberBalance.setTokens(memberBalance.getTokens() - 1);
this.save(memberBalance);
} else {
throw new SomeCustomRTException("No balance");
}
}
Не думаю, что это защитит меня от TOKEN_BALANCE
= 1 варианта использования. Меня беспокоит несколько запросов на разблокировку одновременно. Если баланс равен 1, я мог бы получить два вызова на decrementBalance()
одновременно, оба зафиксировать баланс на 0, но затем также два успешных вызова на itemDAO.unlockItem(...)
, верно?
Как мне это реализовать? Должен ли я установить для транзакции метода уровня обслуживания значение isolation = Isolation.SERIALIZABLE
? Или есть более чистый / лучший способ приблизиться к этому?