Przewodnik zapytań oxmysql: MySQL.query.await, single, scalar, insert
Jak używać oxmysql w FiveM Lua: MySQL.query.await, single, scalar, insert, update, prepare, bezpieczne ? parametry, import MySQL.lua, unikanie pętli i transakcji.
Musisz czytać lub pisać do bazy danych ze skryptu serwerowego, a przykłady w internecie mieszają stare wywołania MySQL.Async, callbacki i exports.oxmysql w różnych stylach. Ten artykuł pokazuje obecne funkcje MySQL, która z nich użyć dla jakiego wyniku i jak utrzymać zapytania bezpieczne i tanie.
Załaduj obiekt MySQL
Aby użyć globalnego MySQL, zaimportuj wrapper Lua oxmysql w manifeście zasobu, przed własnymi skryptami serwerowymi:
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
}
dependency 'oxmysql'Bez tej linii MySQL to nil i otrzymasz attempt to index a nil value (global 'MySQL'). Plik działa tylko na serwerze. Jeśli sam oxmysql nie może się połączyć, zobacz błędy połączenia oxmysql.
Funkcje i to co zwracają
Każda funkcja ma formę .await, która czeka na wynik i go zwraca. Musi działać w wątku lub procedurze obsługi zdarzenia, gdzie większość twojego kodu już działa.
| Funkcja | Zwraca | Użyj dla |
|---|---|---|
MySQL.query.await |
Tabela wierszy (pusta jeśli brak) | SELECT z wieloma wierszami |
MySQL.single.await |
Jeden wiersz, lub nil |
SELECT dla jednego rekordu |
MySQL.scalar.await |
Jedna wartość, lub nil |
COUNT, SUM, jedna kolumna |
MySQL.insert.await |
Nowy id auto-increment | INSERT |
MySQL.update.await |
Liczba zmienionych wierszy | 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 })Sprawdź wyniki. Zapytanie single lub scalar, które nic nie znajduje, zwraca nil, a jego użycie bez sprawdzenia jest źródłem wielu błędów attempt to index a nil value.
Parametry z ?
Zawsze przekazuj wartości poprzez symbole zastępcze ? i drugi argument, tabelę w tej samej kolejności:
-- safe
MySQL.query.await('SELECT * FROM users WHERE name = ?', { name })
-- dangerous: SQL injection
MySQL.query.await('SELECT * FROM users WHERE name = "' .. name .. '"')W niezabezpieczonej wersji nazwa taka jak x" OR 1=1 -- przepisuje twoje zapytanie. Z symbolami zastępczymi oxmysql wysyła wartości oddzielnie, więc nigdy nie mogą stać się SQL. Dotyczy to każdej wartości pochodzącej od gracza, argumentu zdarzenia lub polecenia.
Ostrzeżenie: symbole zastępcze działają tylko dla wartości, nie dla nazw tabel ani kolumn. Jeśli nazwa kolumny pochodzi z zewnątrz, sprawdź ją na liście dozwolonych nazw zamiast wklejać ją.
Styl callback
Te same funkcje przyjmują callback, jeśli nie chcesz czekać. Jest to przydatne poza wątkiem:
MySQL.query('SELECT * FROM users WHERE job = ?', { 'police' }, function(rows)
print(#rows)
end).await czyta się lepiej i jest w porządku wewnątrz zdarzeń. Użyj stylu callback, gdy chcesz, aby kod, który następuje, ciągle działał bez czekania na bazę danych.
MySQL.prepare
MySQL.prepare uruchamia przygotowane zapytanie, które baza danych może ponownie użyć, gdy uruchamiasz to samo zapytanie raz za razem. Używa tych samych parametrów ?:
local row = MySQL.prepare.await('SELECT * FROM users WHERE identifier = ?', { identifier })To co zwraca zależy od wyniku: pojedynczy wiersz wraca jako tabela, a zapytanie z jedną kolumną i jednym wierszem może wrócić jako wartość. Do kodu, gdzie kształt wyniku ma znaczenie, single i scalar są bardziej przewidywalne, więc sięgaj po prepare, gdy masz gorące zapytanie, które działa często.
Nie odpytuj w pętli
Każde zapytanie to przejazd w obie strony do bazy danych. Pętla, która uruchamia jedno zapytanie na element, szybko się spowalnia i blokuje wątek podczas czekania:
-- one query per player
for _, id in ipairs(ids) do
local row = MySQL.single.await('SELECT * FROM users WHERE id = ?', { id })
endPobierz wszystko w jednym zapytaniu, a następnie pętl po wyniku w Lua:
local rows = MySQL.query.await('SELECT * FROM users WHERE job = ?', { 'police' })W przypadku wielu wstawień zbuduj jedno zapytanie z kilkoma wierszami lub uruchom je razem w transakcji. Unikaj też odpytywania co każdy tick lub każdą klatkę: przeczytaj wartość raz i przechowuj ją w tabeli Lua. Jeśli zapytanie jest wolne, dodaj indeks do kolumny, którą przeszukujesz. Wolne zapytania pojawiają się jako ostrzeżenia o zacinaniu się wątku serwera.
Transakcje
Gdy kilka zapisów musi albo wszystkie się powiększać albo wszystkie się nie powiększać, na przykład biorąc pieniądze z jednego wiersza i dając je do drugiego, użyj transakcji:
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')
endJeśli którekolwiek zapytanie się nie powiedzie, baza danych cofa wszystkie z nich. Zwraca true, gdy wszystko przeszło.
Tabele muszą istnieć najpierw
Zapytanie do tabeli, której nie ma, daje Table 'x' doesn't exist. Utwórz tabelę za pomocą pliku SQL, gdy instalujesz skrypt, lub przy starcie zasobu za pomocą MySQL.query.await('CREATE TABLE IF NOT EXISTS …'). Więcej w SQL table doesn't exist.
Lista kontrolna
| Symptom | Naprawa |
|---|---|
MySQL to nil |
Dodaj '@oxmysql/lib/MySQL.lua' do server_scripts, przed swoimi plikami |
| Wynik to nil i skrypt się nie powiedzie | single i scalar zwracają nil, gdy nic nie zostanie znalezione: sprawdź to |
| Wartości pochodzą od graczy | Użyj ? i tabeli parametrów, nigdy łączenia |
| Server zacinanie się na poleceniu | Brak zapytania w pętli: pobierz raz, pętl w Lua |
| Dwa zapisy muszą działać razem | MySQL.transaction.await |
| To samo zapytanie stale się działa | MySQL.prepare, indeks, lub buforuj wartość w Lua |
Szybkie odpowiedzi
Jak użyć MySQL.query.await w moim skrypcie?
Dodaj server_script '@oxmysql/lib/MySQL.lua' przed swoimi skryptami serwerowymi w fxmanifest.lua, a następnie wywołaj MySQL.query.await('SELECT * FROM users WHERE id = ?', { id }) wewnątrz wątku lub procedury obsługi zdarzenia.
Jak zapobiec SQL injection za pomocą oxmysql?
Nigdy nie buduj zapytania poprzez łączenie ciągów znaków. Umieść symbole zastępcze ? w zapytaniu i przekaż wartości w tabeli, dzięki czemu oxmysql wysyła je oddzielnie.
Jaka jest różnica między query, single i scalar?
query zwraca wszystkie wiersze, single zwraca pierwszy wiersz lub nil, a scalar zwraca pierwszą kolumnę pierwszego wiersza, taką jak licznik.
Skrypty bez tego problemu
Shop CreatorZbuduj sklep w niecałą minutę — właściciele, pracownicy, sejfy i napady w zestawie.Zobacz skrypt →
Item Creator V2Twórz używalne przedmioty z animacjami, propami, efektami i nie tylko — bez pisania kodu.Zobacz skrypt →
Crypto MiningKup magazyn, składaj koparki część po części i kop monety na żywym rynku.Zobacz skrypt →