Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak prawidłowo używać transakcji i blokad, aby zapewnić integralność bazy danych?

Jak dotąd, jest to dobre, przynajmniej uniemożliwi to użytkownikowi dokonywanie płatności w wielu sesjach (wielokrotne próby zakupu tej samej karty - dobrze radzić sobie z podwójnymi kliknięciami).

Jak sprawdzasz? Za pomocą standardowego SELECT lub z SELECT ... FOR UPDATE ? Na podstawie kroku 5 domyślam się, że sprawdzasz zarezerwowaną kolumnę w elemencie lub coś podobnego.

Problem polega na tym, że SELECT ... FOR UPDATE w kroku 2 NIE zastosuje FOR UPDATE zablokować wszystko inne. Ma zastosowanie tylko do tego, co jest SELECT ed:cart-item stół. Na podstawie nazwy będzie to inny rekord dla każdego koszyka/użytkownika. Oznacza to, że inne transakcje NIE zostaną zablokowane.

Zgodnie z powyższym, w oparciu o podane przez Ciebie informacje, możesz skończyć z wieloma osobami kupującymi ten sam przedmiot, jeśli nie używasz SELECT ... FOR UPDATE w kroku 3.

Sugerowane rozwiązanie

  1. Rozpocznij transakcję
  2. SELECT ... FOR UPDATE cart-item stół.

Spowoduje to zablokowanie podwójnego kliknięcia przed uruchomieniem. To, co tutaj wybierzesz, powinno być rodzajem kolumny „zamówione w koszyku”. Jeśli to zrobisz, druga transakcja zatrzyma się tutaj i poczeka na zakończenie pierwszej, a następnie odczyta wynik, który pierwsza zapisała w bazie danych.

Pamiętaj, aby zakończyć proces płatności tutaj, jeśli cart-item tabela mówi, że została już zamówiona.

  1. SELECT ... FOR UPDATE tabela, w której zapisujesz, czy przedmiot został zarezerwowany.

Uniemożliwi to INNYM koszykom/użytkownikom odczytanie tych elementów.

Na podstawie wyniku, jeśli pozycje nie są zarezerwowane, kontynuuj:

  1. UPDATE ... tabeli w kroku 3, oznaczając pozycję jako zastrzeżoną. Wykonaj dowolne inne INSERT s i UPDATE s ty też potrzebujesz.

  2. Dokonać płatności. Wycofaj, jeśli usługa płatności twierdzi, że płatność nie zadziałała.

  3. Zarejestruj płatność, jeśli się powiedzie.

  4. Zatwierdź transakcję

Upewnij się, że nie robisz niczego, co mogłoby się nie powieść między krokami 5 i 7 (np. wysyłanie e-maili), w przeciwnym razie możesz skończyć z dokonaniem płatności bez jej zarejestrowania, w przypadku cofnięcia transakcji.

Krok 3 jest ważnym krokiem, jeśli chodzi o upewnienie się, że dwie (lub więcej) osoby nie próbują zamówić tego samego przedmiotu. Jeśli dwie osoby spróbują, druga osoba zawiesi się na swojej stronie podczas przetwarzania pierwszej. Następnie, gdy skończy się pierwszy, drugi przeczyta kolumnę „zarezerwowane” i możesz zwrócić użytkownikowi wiadomość, że ktoś już kupił ten przedmiot.

Płatność w transakcji lub nie

To jest subiektywne. Ogólnie rzecz biorąc, chcesz zamykać transakcje tak szybko, jak to możliwe, aby uniknąć zablokowania wielu osób w jednoczesnej interakcji z bazą danych.

Jednak w tym przypadku naprawdę chcesz, aby poczekali. To tylko kwestia czasu.

Jeśli zdecydujesz się zatwierdzić transakcję przed dokonaniem płatności, będziesz musiał zapisać swój postęp w jakiejś tabeli pośredniej, uruchomić płatność, a następnie zapisać wynik. Pamiętaj, że jeśli płatność się nie powiedzie, będziesz musiał ręcznie cofnąć zaktualizowane rekordy rezerwacji pozycji.

WYBIERZ... DO AKTUALIZACJI w nieistniejących wierszach

Tylko słowo ostrzeżenia, na wypadek gdyby projekt tabeli wymagał wstawiania wierszy, w których trzeba wcześniej SELECT ... FOR UPDATE :Jeśli wiersz nie istnieje, ta transakcja NIE spowoduje, że inne transakcje będą czekać, jeśli również SELECT ... FOR UPDATE ten sam nieistniejący wiersz.

Dlatego upewnij się, że zawsze serializujesz swoje żądania, wykonując SELECT ... FOR UPDATE w rzędzie, o którym wiesz, że istnieje jako pierwszy. Następnie możesz SELECT ... FOR UPDATE w wierszu, który może jeszcze nie istnieć. (Nie próbuj robić tylko SELECT w wierszu, który może istnieć lub nie, ponieważ będziesz odczytywał stan wiersza w momencie rozpoczęcia transakcji, a nie w momencie uruchomienia SELECT . A więc SELECT ... FOR UPDATE w nieistniejących wierszach jest nadal czymś, co musisz zrobić, aby uzyskać najbardziej aktualne informacje, pamiętaj tylko, że nie spowoduje to, że inne transakcje będą czekać).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak wywołać echo instrukcji print podczas wykonywania skryptu sql?

  2. Pojedynczy model Django, wiele stołów?

  3. Jak przywrócić bazę danych mysql w XAMPP?

  4. PHP — jak sprawdzić, czy rekord został pomyślnie usunięty

  5. Grupa MySQL według identyfikatora i ostatniej daty