Guia de consultas oxmysql: MySQL.query.await, single, scalar, insert
Como usar oxmysql em Lua do FiveM: MySQL.query.await, single, scalar, insert, update, prepare, parâmetros ? seguros, a importação MySQL.lua, evitar loops e transações.
Você precisa ler ou escrever no banco de dados de um server script, e exemplos online misturam chamadas antigas de MySQL.Async, callbacks e exports.oxmysql em estilos diferentes. Este artigo mostra as funções atuais de MySQL, qual usar para qual resultado, e como manter queries seguras e eficientes.
Carregue o objeto MySQL
Para usar o MySQL global, importe o wrapper Lua do oxmysql no manifesto do recurso, antes dos seus próprios server scripts:
-- fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
}
dependency 'oxmysql'Sem essa linha, MySQL é nil e você recebe attempt to index a nil value (global 'MySQL'). O arquivo só funciona no servidor. Se o oxmysql em si não conseguir conectar, veja oxmysql connection errors.
As funções e o que elas retornam
Cada função tem uma forma .await que espera pelo resultado e o retorna. Ela deve rodar em uma thread ou um event handler, que é onde a maioria do seu código já roda.
| Função | Retorna | Use para |
|---|---|---|
MySQL.query.await |
Uma tabela de linhas (vazia se nenhuma) | SELECT com muitas linhas |
MySQL.single.await |
Uma linha, ou nil |
SELECT para um registro |
MySQL.scalar.await |
Um valor, ou nil |
COUNT, SUM, uma coluna |
MySQL.insert.await |
O novo id auto-incremento | INSERT |
MySQL.update.await |
Número de linhas afetadas | 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 })Verifique os resultados. Uma query single ou scalar que não encontra nada retorna nil, e usá-la sem uma verificação é a fonte de muitos erros attempt to index a nil value.
Parâmetros com ?
Sempre passe valores através de placeholders ? e do segundo argumento, uma tabela na mesma ordem:
-- safe
MySQL.query.await('SELECT * FROM users WHERE name = ?', { name })
-- dangerous: SQL injection
MySQL.query.await('SELECT * FROM users WHERE name = "' .. name .. '"')Na versão insegura, um nome como x" OR 1=1 -- reescreve sua query. Com placeholders, oxmysql envia os valores separadamente, então eles nunca podem virar SQL. Isso se aplica a todo valor que vem de um jogador, um argumento de evento ou um comando.
Atenção: placeholders só funcionam para valores, não para nomes de tabelas ou colunas. Se um nome de coluna vem de fora, verifique-o contra uma lista fixa de nomes permitidos em vez de colar diretamente.
Estilo callback
As mesmas funções aceitam um callback se você não quiser esperar. Isso é útil fora de uma thread:
MySQL.query('SELECT * FROM users WHERE job = ?', { 'police' }, function(rows)
print(#rows)
end).await é mais legível e funciona bem dentro de eventos. Use o estilo callback quando quiser que o código que segue continue rodando sem esperar pelo banco de dados.
MySQL.prepare
MySQL.prepare executa um prepared statement, que o banco de dados pode reutilizar quando você executa a mesma query repetidamente. Usa os mesmos parâmetros ?:
local row = MySQL.prepare.await('SELECT * FROM users WHERE identifier = ?', { identifier })O que ele retorna depende do resultado: uma única linha volta como uma tabela, e uma query com uma coluna e uma linha pode voltar como um valor. Para código onde a forma do resultado importa, single e scalar são mais previsíveis, então use prepare quando tiver uma query quente que roda frequentemente.
Não faça query em um loop
Cada query é uma ida e volta ao banco de dados. Um loop que roda uma query por item fica lento rapidamente, e bloqueia a thread enquanto espera:
-- one query per player
for _, id in ipairs(ids) do
local row = MySQL.single.await('SELECT * FROM users WHERE id = ?', { id })
endBusque tudo em uma única query, depois faça um loop sobre o resultado em Lua:
local rows = MySQL.query.await('SELECT * FROM users WHERE job = ?', { 'police' })Para muitos inserts, construa uma única declaração com várias linhas, ou execute-as juntas em uma transação. Também evite fazer query a cada tick ou a cada frame: leia um valor uma vez e mantenha-o em uma tabela Lua. Se uma query é lenta, adicione um índice na coluna que você busca. Queries lentas aparecem como server thread hitch warnings.
Transações
Quando várias escritas devem todas ter sucesso ou todas falhar, como tirar dinheiro de uma linha e dar para outra, use uma transação:
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 qualquer declaração falhar, o banco de dados desfaz todas elas. Retorna true quando tudo passou.
Tabelas devem existir primeiro
Uma query contra uma tabela que não existe dá Table 'x' doesn't exist. Crie a tabela com um arquivo SQL quando você instalar o script, ou no resource start com MySQL.query.await('CREATE TABLE IF NOT EXISTS …'). Mais em SQL table doesn't exist.
Checklist
| Sintoma | Solução |
|---|---|
MySQL é nil |
Adicione '@oxmysql/lib/MySQL.lua' a server_scripts, antes dos seus arquivos |
| Resultado é nil e o script gera erro | single e scalar retornam nil quando nada é encontrado: verifique |
| Valores vêm de jogadores | Use ? e uma tabela de parâmetros, nunca concatenação |
| Server trava em um comando | Sem query em um loop: busque uma vez, faça loop em Lua |
| Duas escritas devem ir juntas | MySQL.transaction.await |
| A mesma query roda constantemente | MySQL.prepare, um índice, ou cache do valor em Lua |
Respostas rápidas
Como uso MySQL.query.await no meu script?
Adicione server_script '@oxmysql/lib/MySQL.lua' antes dos seus server scripts em fxmanifest.lua, depois chame MySQL.query.await('SELECT * FROM users WHERE id = ?', { id }) dentro de uma thread ou event handler.
Como prevenho SQL injection com oxmysql?
Nunca construa a query com concatenação de strings. Coloque placeholders ? na query e passe os valores em uma tabela, assim oxmysql os envia separadamente.
Qual é a diferença entre query, single e scalar?
query retorna todas as linhas, single retorna a primeira linha ou nil, e scalar retorna a primeira coluna da primeira linha, como um count.
Scripts sem esse problema
Shop CreatorMonte uma loja em menos de um minuto — donos, funcionários, cofres e assaltos inclusos.Ver script →
Item Creator V2Crie itens usáveis com animações, props, efeitos e muito mais — sem escrever código.Ver script →
Crypto MiningCompre um galpão, monte rigs peça por peça e minere moedas num mercado que se mexe.Ver script →