Heim > Artikel > Backend-Entwicklung > PHP-Zahlungssystemdesign und typische Case-sharing_php-Beispiele
Aufgrund der geschäftlichen Anforderungen des Unternehmens dauerte die Implementierung eines kleinen Zahlungssystems. Obwohl es klein ist, sind alle erforderlichen Komponenten wie Kontosperrung, Transaktionsgarantie und Abgleich vollständig implementiert. Ich habe während des gesamten Entwicklungsprozesses viel Erfahrung gesammelt, und nach der Suche im Internet handelt es sich bei den meisten davon um Forschungsarbeiten mit geringem praktischen Wert. Deshalb teile ich sie dieses Mal speziell mit Ihnen.
Dieses System kann als kleines Zahlungssystem oder als Zahlungsflusssystem verwendet werden, wenn Anwendungen von Drittanbietern an die offene Plattform angeschlossen werden.
Die ursprüngliche Forderung ist verantwortungsvoller, ich werde sie etwas vereinfachen:
Für jede Anwendung müssen externe Anforderungen bereitgestellt werden Guthaben erhalten, Geräte bezahlen, aufladen Warten Sie auf die Schnittstelle
Es gibt ein Programm im Hintergrund und die Liquidation wird am Ersten eines jeden Monats durchgeführt
Konten können eingefroren werden
Es ist notwendig, den Ablauf jedes Vorgangs aufzuzeichnen , und der Tagesablauf muss mit dem Initiator abgeglichen werden
Als Reaktion auf die oben genannten Anforderungen haben wir die folgende Datenbank eingerichtet:
CREATE TABLE `app_margin`.`tb_status` ( `appid` int(10) UNSIGNED NOT NULL, `freeze` int(10) NOT NULL DEFAULT 0, `create_time` datetime NOT NULL, `change_time` datetime NOT NULL, PRIMARY KEY (`appid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `app_margin`.`tb_account_earn` ( `appid` int(10) UNSIGNED NOT NULL, `create_time` datetime NOT NULL, `balance` bigint(20) NOT NULL, `change_time` datetime NOT NULL, `seqid` int(10) NOT NULL DEFAULT 500000000, PRIMARY KEY (`appid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `app_margin`.`tb_bill` ( `id` int AUTO_INCREMENT NOT NULL, `bill_id` int(10) NOT NULL, `amt` bigint(20) NOT NULL, `bill_info` text, `bill_user` char(128), `bill_time` datetime NOT NULL, `bill_type` int(10) NOT NULL, `bill_channel` int(10) NOT NULL, `bill_ret` int(10) NOT NULL, `appid` int(10) UNSIGNED NOT NULL, `old_balance` bigint(20) NOT NULL, `price_info` text, `src_ip` char(128), PRIMARY KEY (`id`), UNIQUE KEY `unique_bill` (`bill_id`,`bill_channel`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `app_margin`.`tb_assign` ( `id` int AUTO_INCREMENT NOT NULL, `assign_time` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `app_margin`.`tb_price` ( `name` char(128) NOT NULL, `price` int(10) NOT NULL, `info` text NOT NULL, PRIMARY KEY (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `app_margin`.`tb_applock` ( `appid` int(10) UNSIGNED NOT NULL, `lock_mode` int(10) NOT NULL DEFAULT 0, `change_time` datetime NOT NULL, PRIMARY KEY (`appid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT `app_margin`.`tb_assign` (`id`,`assign_time`) VALUES (100000000,now());
Die ausführliche Erklärung lautet wie folgt:
tb_status Anwendungsstatustabelle. Verantwortlich dafür, ob das Konto eingefroren ist und um welche Art von Konto es sich handelt (die eigentliche Anforderung besteht darin, dass die Anwendung zwei Konten haben darf, daher wird sie der Einfachheit halber hier nicht aufgeführt)
Appid-Anwendungs-ID
einfrieren, ob eingefroren werden soll
create_time Erstellungszeit
change_time letzte Änderungszeit
tb_account_earn Anwendungskontostandstabelle
appid Anwendungs-ID
Saldosaldo (Einheit ist Cent, verwenden Sie keinen Dezimalspeicher, da die Dezimalzahl selbst nicht genau ist; Darüber hinaus muss sich PHP auf einem 64-Bit-Computer befinden, der Bigint unterstützen kann tb_assign-Tabelle, die die Seriennummer zuweist, die bill_id von tb_bill muss sein. Sie wird durch tb_assign
id automatisch inkrementierende ID
create_time Erstellungszeit
tb_bill-Flusstabelle zugewiesen. Verantwortlich für die Aufzeichnung jedes Vorgangsablaufs. Die bill_id ist hier nicht der Primärschlüssel, da dieselbe bill_id zwei Flüsse haben kann: Zahlung und Rollback Vorgang (dies ist notwendig, um zwischen positiv und negativ zu unterscheiden, hauptsächlich um die Änderung des Betrags während eines bestimmten Zeitraums direkt zu berechnen, wenn alle ausgewählt werden)
bill_info detaillierte Informationen des Vorgangs, z. B. 3 Webserver, 2 Datenbanken
bill_user Betriebsbenutzer
bill_time Die laufende Zeit
bill_type Der laufende Typ, der unterscheidet, ob Geld hinzugefügt oder abgezogen werden soll
bill_channel Die fließende Wasserquelle, wie Aufladen, Zahlung, Rollback, Abrechnung oder andere
bill_ret Der Rückgabecode des fließenden Wassers, einschließlich unverarbeitet und erfolgreich, ist fehlgeschlagen. Die Logik hier wird später erläutert Artikel, der bezahlt wird, wenn der Vorgang ausgeführt wird
src_ip Client-IP
tb_price-Einheitspreistabelle, zeichnet den Einheitspreis der Maschine auf
Name, eindeutige Kennung der Maschine
Preispreis
Info-Beschreibung
tb_applock-Sperre Tabelle, die speziell darauf ausgelegt ist, gleichzeitige Schreibvorgänge für eine Anwendung zu vermeiden. Der Code zeigt später den Sperrstatus
appid application id
lock_mode an. Wenn es 0 ist, ist es gesperrt, wenn es 1 ist, ist es gesperrt
change_time Letzte Änderungszeit
OK, nachdem die Bibliothekstabelle entworfen wurde, werfen wir einen Blick auf die typischsten Vorgänge.
1. Zahlungsvorgang
Ich liste nur auf, wie ich es derzeit umsetze. Es ist vielleicht nicht das Beste, aber es sollte das wirtschaftlichste sein und den Bedürfnissen entsprechen.
Lassen Sie uns zuerst über den Anrufer sprechen:
Häufig verwendete Fehlerrückgabecodes können wie folgt lauten:
Jeder Fehler größer als 0 wird als logischer Fehler betrachtet. Bei der Durchführung eines Zahlungsvorgangs muss der Anrufer die Transaktion nicht aufzeichnen. Weil sich das Konto nicht geändert hat.
Fehler kleiner als 0 sind interne Systemfehler. Da nicht bekannt ist, ob Datenänderungen aufgetreten sind, müssen sowohl der Anrufer als auch das Zahlungssystem den Fluss aufzeichnen.Bei einer Rendite von 0 bedeutet dies Erfolg, und beide Seiten müssen auch den Fluss erfassen.
Im Zahlungssystem gibt es einen Grund, warum die Transaktion zuerst geschrieben und dann das Konto aktualisiert wird. Einfach ausgedrückt geht es darum, den Verlust der Transaktion so weit wie möglich zu vermeiden.
$g_site_error = array( -1 => '服务器繁忙', -2 => '数据库读取错误', -3 => '数据库写入错误', 0 => '成功', 1 => '没有数据', 2 => '没有权限', 3 => '余额不足', 4 => '账户被冻结', 5 => '账户被锁定', 6 => '参数错误', );
2. Implementierung der Kontosperre
Der Sperrmechanismus der Datenbank wird hier nicht erwähnt. Der Code lautet wie folgt >
Um Deadlock-Probleme zu vermeiden, wurde der Logik zum Erwerb der Sperre eine Timeout-Beurteilung hinzugefügt. Sie sollten es verstehen können, indem Sie sich den Code ansehen
3. Abgleichslogik
Wenn es nach dem oben genannten System gestaltet ist, müssen Sie beim Abgleich des Kontos nur die erfolgreichen Transaktionen (d. h. bill_ret=0) auf beiden Seiten vergleichen, wenn sie vollständig konsistent sind Kein Problem mit dem Konto sein, wenn sie inkonsistent sind, dann habe ich das Problem überprüft.
Bezüglich der Sicherstellung der Richtigkeit des Kontos sagte mir ein Kollege auch, dass, als ich im Unternehmen arbeitete, vor jedem Schreibvorgang alle Transaktionsdatensätze in der Transaktionstabelle erfasst und die Werte von amt ermittelt wurden akkumuliert. Überprüfen Sie, ob das Ergebnis mit dem Saldo übereinstimmt. Wenn sie nicht gleich sind, stimmt etwas nicht.
select sum(amt) from tb_bill where appid=1;
Aus diesem Grund muss in meiner Flusstabelle das amt-Feld zwischen positiv und negativ unterscheiden.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).