Sejauh ini bagus, ini setidaknya akan mencegah pengguna melakukan checkout dalam beberapa sesi (berkali-kali mencoba checkout kartu yang sama - bagus untuk menangani klik ganda.)
Bagaimana Anda memeriksa? Dengan standar SELECT
atau dengan SELECT ... FOR UPDATE
? Berdasarkan langkah 5, saya kira Anda memeriksa kolom yang dipesan pada item, atau yang serupa.
Masalahnya di sini adalah bahwa SELECT ... FOR UPDATE
pada langkah 2 TIDAK akan menerapkan FOR UPDATE
mengunci segala sesuatu yang lain. Itu hanya berlaku untuk apa yang SELECT
ed:cart-item
meja. Berdasarkan namanya, itu akan menjadi catatan yang berbeda untuk setiap keranjang/pengguna. Ini berarti bahwa transaksi lain TIDAK akan diblokir untuk melanjutkan.
Mengikuti di atas, berdasarkan informasi yang Anda berikan, Anda mungkin berakhir dengan beberapa orang membeli item yang sama, jika Anda tidak menggunakan SELECT ... FOR UPDATE
pada langkah 3.
Solusi yang Disarankan
- Mulai transaksi
SELECT ... FOR UPDATE
cart-item
tabel.
Ini akan mengunci klik dua kali agar tidak berjalan. Apa yang Anda pilih di sini harus menjadi semacam kolom "pesanan keranjang". Jika Anda melakukan ini, transaksi kedua akan berhenti di sini dan menunggu yang pertama selesai, lalu membaca hasilnya apa yang pertama disimpan ke database.
Pastikan untuk mengakhiri proses checkout di sini jika cart-item
tabel mengatakan sudah dipesan.
SELECT ... FOR UPDATE
tabel tempat Anda mencatat jika suatu item telah dipesan.
Ini akan mengunci troli/pengguna LAIN agar tidak dapat membaca item tersebut.
Berdasarkan hasil, jika barang tidak dipesan, lanjutkan:
-
UPDATE ...
tabel di langkah 3, menandai item sebagai dipesan. LakukanINSERT
lainnya s danUPDATE
yang Anda butuhkan juga. -
Melakukan pembayaran. Lakukan rollback jika layanan pembayaran mengatakan pembayaran tidak berhasil.
-
Catat pembayaran, jika berhasil.
-
Lakukan transaksi
Pastikan Anda tidak melakukan apa pun yang mungkin gagal antara langkah 5 dan 7 (seperti mengirim email), jika tidak, Anda mungkin berakhir dengan mereka melakukan pembayaran tanpa dicatat, jika transaksi dibatalkan.
Langkah 3 adalah langkah penting untuk memastikan dua (atau lebih) orang tidak mencoba memesan barang yang sama. Jika dua orang mencoba, orang kedua akan membuat halaman web mereka "hang" saat memproses yang pertama. Kemudian ketika yang pertama selesai, yang kedua akan membaca kolom "reserved", dan Anda dapat mengembalikan pesan kepada pengguna bahwa seseorang telah membeli item tersebut.
Pembayaran dalam transaksi atau tidak
Ini subjektif. Umumnya, Anda ingin menutup transaksi secepat mungkin, untuk menghindari beberapa orang terkunci dari interaksi dengan database sekaligus.
Namun, dalam kasus ini, Anda sebenarnya ingin mereka menunggu. Ini hanya masalah berapa lama.
Jika Anda memilih untuk melakukan transaksi sebelum pembayaran, Anda harus mencatat kemajuan Anda di beberapa tabel perantara, menjalankan pembayaran, dan kemudian mencatat hasilnya. Ketahuilah bahwa jika pembayaran gagal, Anda harus secara manual membatalkan catatan reservasi item yang Anda perbarui.
PILIH ... UNTUK PEMBARUAN pada baris yang tidak ada
Sekedar peringatan, jika desain tabel Anda melibatkan penyisipan baris di mana Anda perlu SELECT ... FOR UPDATE
sebelumnya :Jika baris tidak ada, transaksi tersebut TIDAK akan menyebabkan transaksi lain menunggu, jika mereka juga SELECT ... FOR UPDATE
baris yang sama tidak ada.
Jadi, pastikan untuk selalu membuat serial permintaan Anda dengan melakukan SELECT ... FOR UPDATE
pada baris yang Anda tahu ada terlebih dahulu. Kemudian Anda dapat SELECT ... FOR UPDATE
pada baris yang mungkin atau mungkin belum ada. (Jangan mencoba melakukan SELECT
pada baris yang mungkin atau mungkin tidak ada, karena Anda akan membaca status baris pada saat transaksi dimulai, bukan pada saat Anda menjalankan SELECT
. Jadi, SELECT ... FOR UPDATE
pada baris yang tidak ada masih merupakan sesuatu yang perlu Anda lakukan untuk mendapatkan informasi terbaru, perlu diketahui bahwa itu tidak akan menyebabkan transaksi lain menunggu.)