Resposta curta. Adicione aiomysql ao seu bot discord.py, crie um único pool em setup_hook com autocommit=True e execute toda consulta por ele, com marcadores %s. Sem autocommit=True (ou um commit() depois de cada gravação), o aiomysql não salva seus INSERTs. Na PlayNHost, todo plano de bot inclui um banco de dados MySQL: crie-o na página Bancos de dados, cole os dados dele no painel Ambiente e o código abaixo funciona como está. O banco aceita conexões dos seus servidores PlayNHost e do phpMyAdmin, não do seu próprio computador. Testamos este código em 6 de novembro de 2026 com discord.py 2.7.1, aiomysql 0.3.2 e Python 3.12, contra o MariaDB 10.11 com uma conta de banco configurada como a nossa (20 conexões, limite de consulta de 120 segundos): a inicialização, a tabela e o comando /warn, mas não um login real no Discord.
Abra seu servidor de bot no painel e clique em Bancos de dados.
Clique em Novo banco de dados. O Rótulo é opcional; Será criado como mostra o nome completo. Clique em Criar banco de dados.
A página do novo banco de dados abre (depois, clique nele em Seus bancos de dados). O cartão Conexão mostra Host, Porta, Banco de dados, Nome de usuário e Senha. Em Config pronta para usar, Config para tem um trecho Python (aiomysql) com os mesmos valores já preenchidos.
2. Coloque os dados em Ambiente
Abra a página Bot, o painel Ambiente, e clique em Colar um arquivo .env.
Cole estas cinco linhas com os valores do cartão Conexão:
import os
import aiomysql
import discord
from discord import app_commands
class Bot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
self.pool = None
async def setup_hook(self):
# One pool for the whole bot. The values come from the Environment pane.
self.pool = await aiomysql.create_pool(
host=os.environ["DB_HOST"],
port=int(os.environ["DB_PORT"]),
user=os.environ["DB_USER"],
password=os.environ["DB_PASSWORD"],
db=os.environ["DB_NAME"],
autocommit=True,
maxsize=5,
)
async with self.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(
"CREATE TABLE IF NOT EXISTS warnings ("
"id INT AUTO_INCREMENT PRIMARY KEY, "
"guild_id BIGINT UNSIGNED NOT NULL, "
"user_id BIGINT UNSIGNED NOT NULL, "
"reason VARCHAR(200) NOT NULL, "
"created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
"KEY guild_user (guild_id, user_id))"
)
print("Database ready")
await self.tree.sync()
async def close(self):
if self.pool is not None:
self.pool.close()
await self.pool.wait_closed()
await super().close()
bot = Bot()
@bot.tree.command(description="Warn a member and count their warnings")
@app_commands.guild_only()
@app_commands.describe(user="Who to warn", reason="Why")
async def warn(interaction: discord.Interaction, user: discord.Member, reason: app_commands.Range[str, 1, 200]):
async with bot.pool.acquire() as conn:
async with conn.cursor() as cur:
await cur.execute(
"INSERT INTO warnings (guild_id, user_id, reason) VALUES (%s, %s, %s)",
(interaction.guild_id, user.id, reason),
)
await cur.execute(
"SELECT COUNT(*) FROM warnings WHERE guild_id = %s AND user_id = %s",
(interaction.guild_id, user.id),
)
(total,) = await cur.fetchone()
await interaction.response.send_message(f"{user.mention} has {total} warning(s).")
@bot.event
async def on_ready():
print(f"Logged in as {bot.user}")
bot.run(os.environ["DISCORD_TOKEN"])
O que ele faz: o discord.py executa setup_hook uma vez, durante o login e antes de qualquer evento chegar, então o pool e a tabela warnings existem antes de o primeiro comando chegar. Depois ele registra /warn no Discord. @app_commands.guild_only() mantém o comando fora das mensagens diretas, onde não há servidor para associar o aviso. Os IDs do Discord cabem em BIGINT UNSIGNED. Os marcadores %s são preenchidos pelo driver, então um motivo como '); DROP TABLE warnings; -- é salvo como texto simples. Nunca monte o SQL com uma f-string.
4. Execute
Envie bot.py e requirements.txt em Files.
Clique em Iniciar e abra Console. A inicialização instala os pacotes de requirements.txt e depois mostra [PlayNHost] Starting your bot e Database ready.
No Discord, digite /warn. Para ver as linhas, abra a página do banco de dados e clique em Abrir no phpMyAdmin.
A armadilha do autocommit
O aiomysql abre conexões com o autocommit desligado. Um INSERT então fica dentro de uma transação aberta. Quando a conexão volta ao pool com essa transação ainda aberta, o aiomysql a fecha, e o MariaDB descarta a linha não confirmada. No nosso teste, uma linha inserida em um pool sem autocommit=True foi vista por 0 outras conexões. Passe autocommit=True para create_pool, como acima, ou chame await conn.commit() depois das suas gravações.
Limites que importam para o seu pool
20 conexões ao mesmo tempo por usuário do banco. Todo processo que usa o mesmo login conta. A conexão 21 é recusada com (1226, "User '...' has exceeded the 'max_user_connections' resource (current value: 20)"). maxsize=5 mantém o bot bem abaixo disso.
Uma consulta que roda por mais de 120 segundos é interrompida. O MariaDB a encerra com o erro 1969, Query execution was interrupted (max_statement_time exceeded). No nosso teste isso aconteceu após 120.03 segundos. As consultas de um bot normalmente levam milissegundos, então isso só atinge uma consulta descontrolada.
500 MB por banco de dados. A página Bancos de dados mostra quanto está em uso. Ao chegar a 500 MB, as gravações são bloqueadas até você apagar linhas.
Os backups do servidor não incluem o banco de dados. Exporte-o do phpMyAdmin de vez em quando.
Erros e o que significam
Estes são os erros exatos que o aiomysql deu no nosso teste (eles vêm do PyMySQL, que o aiomysql usa por baixo):
pymysql.err.OperationalError (1045, "Access denied for user ..."): DB_USER ou DB_PASSWORD incorreto. Depois de Redefinir senha no cartão Conexão, a senha antiga para de funcionar na hora: troque DB_PASSWORD e reinicie o bot.
pymysql.err.OperationalError (2003, "Can't connect to MySQL server on ..."): host ou porta errados, ou uma conexão de fora da PlayNHost. O banco só aceita conexões de servidores PlayNHost e do phpMyAdmin, então é isso também que você recebe no seu próprio computador.
Uma variável ausente em Ambiente para o bot antes de ele se conectar, com KeyError: 'DB_HOST' ou o nome da que está faltando, porque o código lê cada valor com os.environ[...]. Adicione-a e reinicie o bot: as variáveis valem na próxima vez que ele iniciar.
Instalar discord.py e aiomysql com pip do zero chegou a um pico de 78 MB de memória no nosso teste, em um contêiner limitado a 512 MB como o nosso menor plano de bot. Quanto o bot em execução precisa depende principalmente de em quantos servidores ele está: De quanta RAM um bot do Discord precisa?
Usamos cookies para manter o site funcionando, entender como ele é usado e medir nosso marketing. Você pode aceitar tudo, aceitar apenas os cookies essenciais ou escolher por categoria.Usamos cookies para manter o site funcionando, entender como ele é usado e medir nosso marketing. Eles estão ativos por padrão. Você pode desativar o que não quiser.Leia nossa política de privacidade