Size: a a a

Django [ru] #STAY HOME

2020 September 13

S

Shodmon in Django [ru] #STAY HOME
Если написать последовательно, селекты фо апдейты, разве не будет так

Запись 1 Лок замена анлок,
Запись 2 Лок замена анлок,
А надо чтоб прошло одной зэтранзакцией
источник

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
всё что внутри transaction.atomic будет выполняться одним sql запросом, верно?
По идее, да, типо ты можешь написать 2 просто апдейта, внутри атомика
источник

S

Shodmon in Django [ru] #STAY HOME
Shodmon
По идее, да, типо ты можешь написать 2 просто апдейта, внутри атомика
И должна одна транзакция пройти
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
а в какой последовательности вызывать апдейты есть разница же?
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
может случиться же дедлок пойдее?
источник

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
а в какой последовательности вызывать апдейты есть разница же?
Да конечно, вы берете у одной, и даёте другой
источник

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
может случиться же дедлок пойдее?
Хмм, не вижу почему?
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
Есть два счета
acc_one = Account(1)
acc_two = Account(2)

начались две транзакции
acc_from=acc_one, acc_to=acc_two

acc_from=acc_two, acc_to=acc_one

Они будут внутри контекста транзакции делать сначала select_for_update по первой сущности acc_from, а затем будут делать select_for_update по acc_to.

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

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
Есть два счета
acc_one = Account(1)
acc_two = Account(2)

начались две транзакции
acc_from=acc_one, acc_to=acc_two

acc_from=acc_two, acc_to=acc_one

Они будут внутри контекста транзакции делать сначала select_for_update по первой сущности acc_from, а затем будут делать select_for_update по acc_to.

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

S

Shodmon in Django [ru] #STAY HOME
Shodmon
Не вы правы пока идёт транзакция поля будут локнуты, но после они будут анлокнуты, пойдут следующие запросы
Т.е если бд не имеет ожидания хоть какого-то то будет хана запросам
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
Первая транзакция заблочит acc_one, а вторая - acc_two. А для дальнейшнего выполнения перевода между аккаунтами нужно отпустить другой аккаунт, а этого не случится
источник

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
Первая транзакция заблочит acc_one, а вторая - acc_two. А для дальнейшнего выполнения перевода между аккаунтами нужно отпустить другой аккаунт, а этого не случится
Нет, вы забираете из одного и передаёте в другое, же
источник

S

Shodmon in Django [ru] #STAY HOME
Shodmon
Нет, вы забираете из одного и передаёте в другое, же
Т.е
1 локнулся, ему выставили -5
2 локнусля ему выставили +5


Тут ещё момент, а если нет столько единиц в первом аккаунте
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
а, то есть мне сделать select_for_update нужно сделать так
Entry.objects.select_for_update().filter(id__in=[acc_from_id, acc_to_id])
?
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
внутри transaction контекста
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
или это не имеет разницы?
источник

S

Shodmon in Django [ru] #STAY HOME
Дмитрий Шепелев
а, то есть мне сделать select_for_update нужно сделать так
Entry.objects.select_for_update().filter(id__in=[acc_from_id, acc_to_id])
?
А дальше?
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
Shodmon
Т.е
1 локнулся, ему выставили -5
2 локнусля ему выставили +5


Тут ещё момент, а если нет столько единиц в первом аккаунте
делаем проверку на уровне сущности, иначе выбрасываем ошибку
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
Shodmon
А дальше?
достаём from и to сущности и делаем уменьшение/увеличение баланса
источник

ДШ

Дмитрий Шепелев... in Django [ru] #STAY HOME
@transaction.atomic()
def transfer_currency(account_from_id, account_to_id, value):
   accounts = Account.objects.select_for_update().filter(id__in=[account_to_id, account_from_id]).all()
   if accounts[0].id == account_from_id:
       account_from = accounts[0]
       account_to = accounts[1]
   else:
       account_from = accounts[1]
       account_to = accounts[0]

   if account_from.balance < value:
       raise InvalidTransferException('Insufficient funds on the account')

   account_from.balance = F("balance") - value
   account_to.balance = F("balance") + value
   account_from.save()
   account_to.save()
источник