oxmysql-Abfragen-Anleitung: MySQL.query.await, single, scalar, insert
So verwendest du oxmysql in FiveM Lua: MySQL.query.await, single, scalar, insert, update, prepare, sichere ? Parameter, der MySQL.lua Import, Vermeiden von Schleifen und Transaktionen.
Du brauchst Daten aus der Datenbank zu lesen oder zu schreiben von einem Server-Script, und Beispiele im Internet vermischen alte MySQL.Async Aufrufe, Callbacks und exports.oxmysql in verschiedenen Stilen. Dieser Artikel zeigt die aktuellen MySQL Funktionen, welche man für welche Ergebnisse verwendet, und wie du Abfragen sicher und effizient hältst.
Lade das MySQL-Objekt
Um das globale MySQL zu verwenden, importiere oxmysqls Lua-Wrapper im Manifest der Ressource, vor deinen eigenen Server-Scripts:
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
}
dependency 'oxmysql'Ohne diese Zeile ist MySQL nil und du erhältst attempt to index a nil value (global 'MySQL'). Die Datei funktioniert nur auf dem Server. Wenn oxmysql selbst keine Verbindung herstellen kann, siehe oxmysql Verbindungsfehler.
Die Funktionen und was sie zurückgeben
Jede Funktion hat eine .await Form, die auf das Ergebnis wartet und es zurückgibt. Sie muss in einem Thread oder einem Event Handler laufen, wo der größte Teil deines Codes bereits läuft.
| Funktion | Rückgabe | Verwende es für |
|---|---|---|
MySQL.query.await |
Eine Tabelle mit Zeilen (leer wenn keine) | SELECT mit vielen Zeilen |
MySQL.single.await |
Eine Zeile oder nil |
SELECT für einen Datensatz |
MySQL.scalar.await |
Ein Wert oder nil |
COUNT, SUM, eine Spalte |
MySQL.insert.await |
Die neue Auto-Increment-ID | INSERT |
MySQL.update.await |
Anzahl betroffener Zeilen | UPDATE, DELETE |
-- all rows
local rows = MySQL.query.await('SELECT identifier, name FROM users WHERE job = ?', { 'police' })
for _, row in ipairs(rows) do
print(row.identifier, row.name)
end
-- one row
local user = MySQL.single.await('SELECT * FROM users WHERE identifier = ?', { identifier })
if not user then return end
-- one value
local count = MySQL.scalar.await('SELECT COUNT(*) FROM owned_vehicles WHERE owner = ?', { identifier })
-- insert
local id = MySQL.insert.await('INSERT INTO my_logs (identifier, action) VALUES (?, ?)', { identifier, 'login' })
-- update or delete
local changed = MySQL.update.await('UPDATE users SET job = ? WHERE identifier = ?', { 'unemployed', identifier })Überprüfe die Ergebnisse. Eine single oder scalar Abfrage, die nichts findet, gibt nil zurück, und sie ohne Überprüfung zu verwenden ist die Quelle vieler attempt to index a nil value Fehler.
Parameter mit ?
Übergebe Werte immer über ? Platzhalter und das zweite Argument, eine Tabelle in der gleichen Reihenfolge:
-- safe
MySQL.query.await('SELECT * FROM users WHERE name = ?', { name })
-- dangerous: SQL injection
MySQL.query.await('SELECT * FROM users WHERE name = "' .. name .. '"')Mit der unsicheren Version schreibt ein Name wie x" OR 1=1 -- deine Abfrage um. Mit Platzhaltern sendet oxmysql die Werte separat, daher können sie niemals zu SQL werden. Dies gilt für jeden Wert, der von einem Spieler, einem Event-Argument oder einem Befehl kommt.
Achtung: Platzhalter funktionieren nur für Werte, nicht für Tabellen- oder Spaltennamen. Wenn ein Spaltenname von außen kommt, überprüfe ihn gegen eine feste Liste erlaubter Namen, anstatt ihn einzufügen.
Callback-Stil
Die gleichen Funktionen akzeptieren einen Callback, wenn du nicht warten möchtest. Dies ist nützlich außerhalb eines Threads:
MySQL.query('SELECT * FROM users WHERE job = ?', { 'police' }, function(rows)
print(#rows)
end).await liest sich besser und ist in Events in Ordnung. Verwende den Callback-Stil, wenn du möchtest, dass der Code, der folgt, weiterlaufen kann, ohne auf die Datenbank zu warten.
MySQL.prepare
MySQL.prepare führt eine vorbereitete Anweisung aus, die die Datenbank wiederverwenden kann, wenn du die gleiche Abfrage immer wieder ausführst. Sie verwendet die gleichen ? Parameter:
local row = MySQL.prepare.await('SELECT * FROM users WHERE identifier = ?', { identifier })Was es zurückgibt, hängt vom Ergebnis ab: eine einzelne Zeile kommt als Tabelle zurück, und eine Abfrage mit einer Spalte und einer Zeile kann als Wert zurückkommen. Für Code, wo die Ergebnisform wichtig ist, sind single und scalar vorhersehbarer, also verwende prepare, wenn du eine häufig ausgeführte Abfrage hast.
Keine Abfrage in einer Schleife
Jede Abfrage ist eine Rundreise zur Datenbank. Eine Schleife, die eine Abfrage pro Element ausführt, wird schnell langsam, und sie blockiert den Thread, während sie wartet:
-- one query per player
for _, id in ipairs(ids) do
local row = MySQL.single.await('SELECT * FROM users WHERE id = ?', { id })
endHole alles in einer einzigen Abfrage, dann schleife über das Ergebnis in Lua:
local rows = MySQL.query.await('SELECT * FROM users WHERE job = ?', { 'police' })Für viele Inserts baue eine Anweisung mit mehreren Zeilen, oder führe sie zusammen in einer Transaktion aus. Vermeide auch, bei jedem Tick oder Frame abzufragen: Lies einen Wert einmal und behalte ihn in einer Lua-Tabelle. Wenn eine Abfrage langsam ist, füge einen Index auf der Spalte hinzu, die du durchsuchst. Langsame Abfragen erscheinen als Server-Thread-Hitch-Warnungen.
Transaktionen
Wenn mehrere Schreibvorgänge alle erfolgreich sein müssen oder alle fehlschlagen, z.B. Geld von einer Zeile nehmen und es einer anderen geben, verwende eine Transaktion:
local ok = MySQL.transaction.await({
{ query = 'UPDATE bank SET balance = balance - ? WHERE identifier = ?', values = { 100, fromId } },
{ query = 'UPDATE bank SET balance = balance + ? WHERE identifier = ?', values = { 100, toId } },
})
if not ok then
print('transfer failed, nothing was changed')
endWenn irgendeine Anweisung fehlschlägt, macht die Datenbank alle rückgängig. Sie gibt true zurück, wenn alles durchgegangen ist.
Tabellen müssen zuerst existieren
Eine Abfrage gegen eine Tabelle, die nicht existiert, gibt Table 'x' doesn't exist. Erstelle die Tabelle mit einer SQL-Datei, wenn du das Script installierst, oder beim Starten der Ressource mit MySQL.query.await('CREATE TABLE IF NOT EXISTS …'). Mehr in SQL-Tabelle existiert nicht.
Checkliste
| Symptom | Behebung |
|---|---|
MySQL ist nil |
Füge '@oxmysql/lib/MySQL.lua' zu server_scripts hinzu, vor deinen Dateien |
| Das Ergebnis ist nil und das Script bricht ab | single und scalar geben nil zurück, wenn nichts gefunden wird: überprüfe es |
| Werte kommen von Spielern | Verwende ? und eine Parametertabelle, niemals Verkettung |
| Server haftet bei einem Befehl | Keine Abfrage in einer Schleife: fetch einmal, Schleife in Lua |
| Zwei Schreibvorgänge müssen zusammen | MySQL.transaction.await |
| Gleiche Abfrage läuft ständig | MySQL.prepare, ein Index, oder cache den Wert in Lua |
Kurze Antworten
Wie verwende ich MySQL.query.await in meinem Script?
Füge server_script '@oxmysql/lib/MySQL.lua' vor deinen Server-Scripts in fxmanifest.lua hinzu, rufe dann MySQL.query.await('SELECT * FROM users WHERE id = ?', { id }) in einem Thread oder Event Handler auf.
Wie verhindere ich SQL-Injection mit oxmysql?
Konstruiere die Abfrage niemals durch String-Verkettung. Verwende ? Platzhalter in der Abfrage und übergebe die Werte in einer Tabelle, damit oxmysql sie separat sendet.
Was ist der Unterschied zwischen query, single und scalar?
query gibt alle Zeilen zurück, single gibt die erste Zeile oder nil zurück, und scalar gibt die erste Spalte der ersten Zeile zurück, wie z.B. eine Zählung.
Scripts ohne dieses Problem
Shop CreatorBau einen Shop in unter einer Minute — Besitzer, Angestellte, Tresore und Überfälle inklusive.Script ansehen →
Item Creator V2Erstelle nutzbare Items mit Animationen, Props, Effekten und mehr — ganz ohne Code.Script ansehen →
Crypto MiningKauf eine Lagerhalle, bau Rigs Teil für Teil und mine Coins auf einem Markt, der sich bewegt.Script ansehen →