Shop mit limitierter Auflage ohne Überbestellungen

slimox

Mitglied
Hallo zusammen,

Dieses Problem möchte ich lösen:
Es gibt 5 Bücher zu kaufen. Legt ein Kunde ein Buch in den Warenkorb, soll es für z.B. für 30 Minuten für Ihn reserviert sein.
Es kommen noch 8 weitere Kunden die gleichzeitig das gleiche Buch in den Warenkorb legen und reservieren möchten.
Da es nur 5 Bücher hat, dürfen es nur total 5 reservieren und kaufen können.

Meine Lösung sieht so aus:
Eine Tabelle mit den Büchern, eine für die Reservationen und eine für die Verkauften
Code:
CREATE TABLE IF NOT EXISTS `bucher` (
  `bucher_ID` int(11) NOT NULL,
  `Name` varchar(50) NOT NULL,
  `Anzahl` int(11) NOT NULL,
  KEY `ID` (`bucher_ID`)
);
INSERT INTO `bucher` (`bucher_ID`, `Name`, `Anzahl`) VALUES
(1, 'Buch 1', 5);

CREATE TABLE IF NOT EXISTS `bucher_reservation` (
  `bucher_ID` int(11) NOT NULL,
  `reservation_end_time` int(11) NOT NULL
);
INSERT INTO `bucher_reservation` (`bucher_ID`, `reservation_end_time`) VALUES
(1, 1366964769);
INSERT INTO `bucher_reservation` (`bucher_ID`, `reservation_end_time`) VALUES
(1, 1366964770);
CREATE TABLE IF NOT EXISTS `bucher_verkauft` (
  `bucher_ID` int(11) NOT NULL
);

INSERT INTO `bucher_verkauft` (`bucher_ID`) VALUES
(1),
(1)
Jetzt meine Frage, wie soll ich es Lösen, dass sicher kein Buch zu viel gekauft wird?
Mein Ansatz sieht so aus:
Code:
SET @c = (SELECT 
              (  b.Anzahl -
                (SELECT 
                    COUNT(*) 
                 FROM
                    bucher_reservation br
                 WHERE
                    br.bucher_ID = b.bucher_ID
                 AND
                    br.reservation_end_time  > 1366954769
                    ) -
                 (SELECT 
                    COUNT(*) 
                 FROM
                    bucher_verkauft bv
                 WHERE
                    bv.bucher_ID = b.bucher_ID
                 )
                ) AS Verfugbar_Anzahl_Bucher
            FROM 
                bucher b
            WHERE 
                b.bucher_ID = 1
            LIMIT 1);
            
IF(@c > 0);

INSERT INTO `bucher_reservation` (`bucher_ID`, `reservation_end_time`) VALUES
(1, 1366964771);
Jedoch funktionier die IF Abfrage nicht ;) Ist dieser Weg korrekt, dass es keine Überbestellungen gibt?
Vom Extremfall, dass 100 Kunden das gleiche Buch haben wollen und in der gleichen Millisekunde auf Kaufen klicken.
Wenn ich die Anzahl verfügbare Bücher mit einem SELECT an PHP gebe, und dann erst den INSERT erstelle. Besteht doch die Gefahr, dass die SELECT COUNT bei zu vielen noch verfügbare Bücher anzeigt? :rolleyes:

Hat jemand schon mal so was gemacht? Alle Ideen sind Willkommen! ;)
 
Zuletzt bearbeitet:
Hallo slimox,

Aus Verkäufersicht ist dieses Vorgehen nicht optimal.
Artikel die im Warenkorb liegen würde ich nicht reservieren und damit andere potentielle Käufer ausschließen. Denn als Verkäufer willst du ja in erster Linie verkaufen. An wen ist dir dabei erst mal egal. Und als Entwickler würdest du dir das Leben auch leichter machen, wenn du auf die Reservierungstabelle verzichtest.

Im Shop wird die Bestellung letztlich erst im letzten Bestellschritt abgeschlossen, also dann wenn der Kunde den berühmten "Jetzt kaufen"-Button geklickt hat. Nach diesem Klick kannst du die bestellte Menge von der aktuell verfügbaren Lagermenge abziehen und prüfen ob die verbliebene Menge kleiner Null ist.
Du könntest hier mit Transaktionen arbeiten und für den Fall, dass die Menge nun kleiner Null ist, einen Rollback auslösen, so dass auch für alle anderen Produkte des Warenkorbs, die ggf. bereits verarbeitet wurden, die Lagermengen wieder stimmen.
Nun musst du dem Kunden noch beichten, dass die gewünschte Menge nicht mehr verfügbar ist.
Er muss sich dann entscheiden, ob er den gesamten Kauf abbricht oder ob er den Warenkorb modifiziert und anschließend den Bestellvorgang erneut einleitet.


Schönen Gruß
 
Ja, ich könnte mir das Leben wirklich einfacher machen wenn es keine Zeitlich beschränkten Reservierungen gibt ;)
Zur Zeit läuft das System wie von dir beschrieben. Erst vor Abschluss, wird die Menge kontrolliert. (Der Shop und Buch dienen nur als Beispiel für meine Frage ;)


Das mit den Transaktionen habe ich mir gar noch nicht überlegt ;) Das würde bedeuten, ein SELECT gibt es noch Bücher, wenn ja ein INSERT in die Reservations-Tabelle, erneut ein SELECT COUNT ob die Anzahl verfügbarer Bücher grösser oder gleich 0 ist. Ist es kleiner Rollback.
Bin ich in der Annahme korrekt, dass mit START TRANSACTION die Tabelle für weitere INSERT ge’LOCKt ist? Bis ein Roollback oder Commit?
;)
 
Welches DBMS verwendest du denn?
Denk dran, dass bei MySQL nur InnoDB Transaktionen unterstützt!

Ich würde mir das erste SELECT sparen und gleich ein UPDATE mit anschließendem SELECT auf die bucher Tabelle machen
SQL:
UPDATE `bucher` SET `Anzahl` = `Anzahl` - 1 WHERE `bucher_ID` = 1 LIMIT 1;
SELECT (`Anzahl` >= 0) AS valid FROM `bucher` WHERE `bucher_ID` = 1;

Soweit ich weiß sperrt MySQL nur die betroffenen Objekte während einer Transaktion, nicht die ganze Tabelle. Aber sicher bin ich mir an dem Punkt nicht.
 
Zuletzt bearbeitet von einem Moderator:
Zurück