dedlfix: Offline Datenbankaktivität

Beitrag lesen

Hi!

Ein Spieler "verdient" pro Sekunde 5 Geld. Der Spieler geht offline, 20 Minuten danach wird er von einem anderen Spieler angegriffen. Jetzt soll der angreifende Spieler das Geld erhalten, was der angegriffene Spieler hat. Wie kann ich das verwirklichen?
Einfach umbuchen :-)

Wenn nichts stattgefunden hat, seit der Spieler offline gegangen ist, kann man auch von dessen nicht vorhandenem Ergebnis nichts umbuchen. Der angreifende Spieler kann nur das Geld bekommen, dass der angegriffene beim Abmelden hatte. Wo die Differenz herkommt ist ja gerade das Problem. Das ist aber ein grundlegendes und hat nichts mit dem Angriff zu tun. Die Einkünfte müssten ja auch wenn der Spieler online ist, regelmäßig berechnet werden.

Cronjobs wurden schon erwähnt, aber die halte ich ebenfalls für ungeeignet. Einerseits dass das kleinste Intervall 1 Minute ist, kann anderseits so eine Ausführung wegen $grund ja auch mal ausfallen. Als besser sehe ich es an, wenn zum Zeitpunkt wo jemand abfragt, wieviel Geld da ist, dieses aus dem gespeicherten Kontostand zum ebenfalls gespeicherten Zeitpunkt X und der Differenz zu jetzt plus dem zu errechnenden Zuwachs in der Zeit, ermittelt wird. Das Ergebnis kann man ja nun mit einem Buchungsdatensatz zu den Kontobewegungen hinzufügen:

Datum: Zeitstempel; Buchungsvorgangstext: Einkünfte für Y Zeiteinheiten seit X; Betrag: + Z Geld

Dann der Angriff:
Datum: Zeitstempel; Buchungsvorgangstext: Angreifer Foo plünderte; Betrag: - SUM() Geld

Wenn man über die Betrag-Spalte ein SUM() laufen lässt, muss nun 0 rauskommen, beziehungsweise der jeweilige Kontostand.

Damit nicht zu viele Buchungsdatensätze für Mini-Zeiträume stattfinden, in denen eigentlich nichts passiert als dass jemand wisen will, wie der Stand ist, kann man ja einfach nur rechnen und einen Differenzdatensatz erst bei wichtigen Ereignissen erstellen.

Das Belasten kann dagegen ein Nebenläufigkeitsproblem bereiten, da zuerst abgefragt werden muss, wieviel Geld der Spieler besitzt um dieses dann mit dem nächsten Insert zu belasten (wegzunehmen).
Die Abfrage und der Insert müssen als atomares Statement gekapselt werden.

Es bietet sich hier an, das volle Ballett von MySQL zu nutzen: Stored Procedures/Functions und Transaktionen (oder zumindest Table Locking).

Hier möchte ich mal die (My-)SQL-Profis bitten, Stellung zu nehmen. Kann man ein Insert auf dieselbe Tabelle ausführen, auf dem zuvor (im selben Statement) ein select (sum) stattgefunden hat, bzw. das Select als Subquery des Insert ausführen auf dieselbe Tabelle?

Ich bin kein Profi, ich habe nur Erfahrung und weiß wo es steht. Man kann kein Update auf eine Tabelle machen, wenn man die Daten mit einem Subselect aus der selben Tabelle holt (vorletzter Satz der verlinkten Stelle). Bei den Subquerys (vorletzter Abschnitt) steht, dass es generell nicht bei Daten ändernden Operationen geht. Es gibt aber eine Ausnahme und das ist INSERT ... SELECT, denn das verwendet implizit eine temporäre Tabelle (dritter Punkt zweiter Absatz).

Lo!