Banco de dados
O servidor conversa com dois tipos de banco, e as mesmas seis funções servem para os dois:
- SQLite — o banco inteiro é um arquivo só, dentro do servidor. Nada para instalar, nada para logar.
- MySQL / MariaDB — um servidor de banco acessado pela rede, com usuário e senha.
Os arquivos do SQLite ficam na pasta databases, criada automaticamente dentro da pasta onde o servidor é executado. O nome que você passa para dbConnect é um caminho relativo a essa pasta.
O dbConnect devolve um elemento de conexão. Ele se comporta como qualquer outro elemento: isElement responde true para ele, getElementType responde "db-connection" e destroyElement fecha a conexão. Ele existe apenas no servidor e nunca é enviado para os clientes. Já os handles de consulta continuam sendo números.
As consultas não rodam na hora. dbExec e dbQuery entregam o trabalho para um processo em segundo plano e retornam na mesma hora, então uma consulta lenta nunca trava o servidor. As linhas chegam depois, pelo dbPoll.
Existem dois caminhos para rodar SQL:
dbExec— para comandos em que você não precisa das linhas de volta:CREATE,INSERT,UPDATE,DELETE.dbQuery+dbPoll+dbFree— paraSELECT, quando você precisa das linhas.
Abrindo a conexão
local conexao
addEventHandler("onResourceStart", resourceRoot, function() conexao = dbConnect("sqlite", "contas.db") if not conexao then outputDebugString("não foi possível abrir o banco de dados") return end
dbExec(conexao, "CREATE TABLE IF NOT EXISTS contas (nome TEXT PRIMARY KEY, dinheiro INTEGER)")end)O mesmo contra um servidor MySQL — só os dois primeiros argumentos mudam de forma:
conexao = dbConnect("mysql", "host=127.0.0.1;port=3306;dbname=gameserver", "usuario", "a-senha")O fluxo de consulta — dbQuery, dbPoll e dbFree
function mostrarSaldo(jogador) -- 1. entrega a consulta; o handle volta na hora, antes de ela ter rodado local consulta = dbQuery(conexao, "SELECT nome, dinheiro FROM contas WHERE nome = ?", getPlayerName(jogador)) if not consulta then return -- o elemento de conexão não está utilizável end
-- 2. pede as linhas. -1 espera o tempo que a consulta precisar local linhas = dbPoll(consulta, -1) if not linhas then return -- a consulta falhou; o motivo está no console de debug end
for _, linha in ipairs(linhas) do outputDebugString(linha.nome .. " tem R$ " .. linha.dinheiro) endendPassar 0 no lugar do -1 é perguntar “já terminou?” sem esperar. Enquanto a consulta ainda está rodando você recebe nil e consulta de novo mais tarde:
local linhas = dbPoll(consulta, 0)if linhas == nil then outputDebugString("ainda rodando, verifico de novo daqui a pouco")enddbPoll já libera o resultado que devolveu. dbFree existe para o caso oposto: você disparou uma consulta e decidiu não ler o retorno.
dbFree(consulta) -- descarta o resultado; daqui em diante o handle está mortoEstas 6 funções existem somente no servidor. Chamá-las de um script de cliente resulta em erro de valor nulo.