Guida alle query oxmysql: MySQL.query.await, single, scalar, insert
Come usare oxmysql in FiveM Lua: MySQL.query.await, single, scalar, insert, update, prepare, parametri safe ?, l'import MySQL.lua, evitare loop e transazioni.
Hai bisogno di leggere o scrivere il database da uno script server, e gli esempi online mescolano vecchie chiamate MySQL.Async, callback e exports.oxmysql in stili diversi. Questo articolo mostra le funzioni MySQL attuali, quale usare per quale risultato, e come mantenere le query sicure e efficienti.
Carica l'oggetto MySQL
Per usare il MySQL globale, importa il wrapper Lua di oxmysql nel manifest della risorsa, prima dei tuoi script server:
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
}
dependency 'oxmysql'Senza quella riga, MySQL è nil e ottieni attempt to index a nil value (global 'MySQL'). Il file funziona solo sul server. Se oxmysql stesso non riesce a connettersi, vedi errori di connessione oxmysql.
Le funzioni e cosa ritornano
Ogni funzione ha una forma .await che aspetta il risultato e lo ritorna. Deve girare in un thread o un event handler, che è dove gira già la maggior parte del tuo codice.
| Funzione | Ritorna | Usala per |
|---|---|---|
MySQL.query.await |
Una tabella di righe (vuota se nessuna) | SELECT con molte righe |
MySQL.single.await |
Una riga, o nil |
SELECT per un record |
MySQL.scalar.await |
Un valore, o nil |
COUNT, SUM, una colonna |
MySQL.insert.await |
Il nuovo id auto-increment | INSERT |
MySQL.update.await |
Numero di righe interessate | 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 })Controlla i risultati. Una query single o scalar che non trova nulla dà nil, e usarla senza un controllo è la fonte di molti errori attempt to index a nil value.
Parametri con ?
Passa sempre i valori attraverso i placeholder ? e il secondo argomento, una tabella nello stesso ordine:
-- safe
MySQL.query.await('SELECT * FROM users WHERE name = ?', { name })
-- dangerous: SQL injection
MySQL.query.await('SELECT * FROM users WHERE name = "' .. name .. '"')Con la versione non sicura, un nome come x" OR 1=1 -- riscrive la tua query. Con i placeholder, oxmysql invia i valori separatamente, quindi non possono mai diventare SQL. Questo vale per ogni valore che viene da un giocatore, da un argomento di evento o da un comando.
Attenzione: i placeholder funzionano solo per i valori, non per i nomi di tabelle o colonne. Se un nome di colonna viene da fuori, controllalo contro una lista fissa di nomi consentiti invece di incollarlo.
Stile con callback
Le stesse funzioni accettano un callback se non vuoi aspettare. Questo è utile fuori da un thread:
MySQL.query('SELECT * FROM users WHERE job = ?', { 'police' }, function(rows)
print(#rows)
end).await è più leggibile ed è fine dentro gli eventi. Usa lo stile callback quando vuoi che il codice che segue continui a girare senza aspettare il database.
MySQL.prepare
MySQL.prepare esegue un prepared statement, che il database può riusare quando esegui la stessa query più e più volte. Usa gli stessi parametri ?:
local row = MySQL.prepare.await('SELECT * FROM users WHERE identifier = ?', { identifier })Cosa ritorna dipende dal risultato: una singola riga ritorna come una tabella, e una query con una colonna e una riga può ritornare come un valore. Per il codice dove la forma del risultato conta, single e scalar sono più prevedibili, quindi usa prepare quando hai una query hot che gira spesso.
Non fare query in un loop
Ogni query è un round trip al database. Un loop che esegue una query per elemento diventa lento velocemente, e blocca il thread mentre aspetta:
-- one query per player
for _, id in ipairs(ids) do
local row = MySQL.single.await('SELECT * FROM users WHERE id = ?', { id })
endPrendi tutto in una singola query, poi fai un loop sul risultato in Lua:
local rows = MySQL.query.await('SELECT * FROM users WHERE job = ?', { 'police' })Per molti insert, costruisci un'istruzione con più righe, o eseguile insieme in una transazione. Evita anche di fare query ogni tick o ogni frame: leggi un valore una volta e tienilo in una tabella Lua. Se una query è lenta, aggiungi un indice sulla colonna che cerchi. Le query lente compaiono come avvisi di server thread hitch.
Transazioni
Quando più scritte devono tutte riuscire o tutte fallire, come prendere soldi da una riga e darli a un'altra, usa una transazione:
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')
endSe qualche istruzione fallisce, il database annulla tutte loro. Ritorna true quando tutto è andato bene.
Le tabelle devono esistere prima
Una query contro una tabella che non esiste dà Table 'x' doesn't exist. Crea la tabella con un file SQL quando installi lo script, o all'avvio della risorsa con MySQL.query.await('CREATE TABLE IF NOT EXISTS …'). Di più in la tabella SQL non esiste.
Checklist
| Sintomo | Soluzione |
|---|---|
MySQL è nil |
Aggiungi '@oxmysql/lib/MySQL.lua' a server_scripts, prima dei tuoi file |
| Il risultato è nil e lo script dà errore | single e scalar ritornano nil quando non trovano nulla: controllalo |
| I valori vengono da giocatori | Usa ? e una tabella di parametri, mai concatenazione |
| Server hitch su un comando | Nessuna query in un loop: prendi una volta, fai loop in Lua |
| Due scritte devono andare insieme | MySQL.transaction.await |
| La stessa query gira costantemente | MySQL.prepare, un indice, o cachea il valore in Lua |
Risposte rapide
Come posso usare MySQL.query.await nel mio script?
Aggiungi server_script '@oxmysql/lib/MySQL.lua' prima dei tuoi script server in fxmanifest.lua, poi chiama MySQL.query.await('SELECT * FROM users WHERE id = ?', { id }) dentro un thread o event handler.
Come posso prevenire SQL injection con oxmysql?
Non costruire mai la query con concatenazione di stringhe. Metti i placeholder ? nella query e passa i valori in una tabella, così oxmysql li invia separatamente.
Qual è la differenza tra query, single e scalar?
query ritorna tutte le righe, single ritorna la prima riga o nil, e scalar ritorna la prima colonna della prima riga, come un count.
Script senza questo problema
Shop CreatorCrea un negozio in meno di un minuto — proprietari, dipendenti, casseforti e rapine inclusi.Vedi script →
Item Creator V2Crea oggetti utilizzabili con animazioni, props, effetti e altro — senza scrivere codice.Vedi script →
Crypto MiningCompra un magazzino, costruisci rig pezzo per pezzo e mina monete su un mercato che si muove.Vedi script →