Pular para o conteúdo

Banco de dados

Servidor

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 — para SELECT, 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)
end
end

Passar 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")
end

dbPoll 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á morto

Estas 6 funções existem somente no servidor. Chamá-las de um script de cliente resulta em erro de valor nulo.