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:

lua
-- 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
lua
-- 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:

lua
-- 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:

lua
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 ?:

lua
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:

lua
-- one query per player
for _, id in ipairs(ids) do
    local row = MySQL.single.await('SELECT * FROM users WHERE id = ?', { id })
end

Pobierz wszystko w jednym zapytaniu, a następnie pętl po wyniku w Lua:

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:

lua
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')
end

Jeś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 →

Czytaj dalej