NOWOŚĆ 📢 Ograniczona oferta na start: do 70% zniżki na pierwszy miesiąc, na każdą grę!Zobacz plany

Jak używać bazy danych MySQL z botem discord.py (aiomysql)

Hosting botów DiscordUpdated Nov 6, 20267 min read

Krótka odpowiedź. Dodaj aiomysql do swojego bota discord.py, utwórz jedną pulę w setup_hook z autocommit=True i wykonuj każde zapytanie przez nią, używając symboli zastępczych %s. Bez autocommit=True (albo commit() po każdym zapisie) aiomysql nie zapisuje Twoich INSERT-ów. W PlayNHost każdy plan dla bota zawiera jedną bazę MySQL: utwórz ją na stronie Bazy danych, wklej jej dane w panelu Środowisko, a kod poniżej zadziała bez zmian. Baza przyjmuje połączenia z Twoich serwerów PlayNHost i z phpMyAdmin, a nie z Twojego komputera. Przetestowaliśmy ten kod 6 listopada 2026 z discord.py 2.7.1, aiomysql 0.3.2 i Python 3.12, na MariaDB 10.11 z kontem bazy skonfigurowanym jak nasze (20 połączeń, limit zapytania 120 sekund): start, tabelę i komendę /warn, ale nie prawdziwe logowanie do Discorda.

Czego potrzebujesz

1. Utwórz bazę danych

  1. Otwórz serwer swojego bota w panelu i kliknij Bazy danych.
  2. Kliknij Nowa baza danych. Pole Etykieta jest opcjonalne; w polu Zostanie utworzona jako zobaczysz pełną nazwę. Kliknij Utwórz bazę danych.
  3. Otworzy się strona nowej bazy (później kliknij ją w sekcji Twoje bazy danych). Karta Połączenie pokazuje Adres hosta, Port, Baza danych, Nazwa użytkownika i Hasło. W sekcji Gotowa konfiguracja pole Konfiguracja dla zawiera fragment Python (aiomysql) z tymi samymi, już wypełnionymi wartościami.

2. Wpisz dane w sekcji Środowisko

  1. Otwórz stronę Bot, panel Środowisko i kliknij Wklej plik .env.
  2. Wklej te pięć linii z wartościami z karty Połączenie:
    DB_HOST=your-host
    DB_PORT=3306
    DB_NAME=your-database
    DB_USER=your-username
    DB_PASSWORD=your-password
  3. DB_PASSWORD dostaje plakietkę Sekret: jest zapisywane tylko do zapisu i nigdy więcej nie jest pokazywane. Kliknij Importuj 5 zmiennych.

Użyj prawdziwego portu z karty Połączenie. Twój kod czyta wartości przez os.environ, więc hasło nigdy nie leży w plikach bota. Więcej o tym panelu: Jak ustawić zmienne środowiskowe i sekrety dla bota Discord.

3. Kod

requirements.txt

discord.py
aiomysql

bot.py

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"])

Co robi kod: discord.py uruchamia setup_hook jeden raz, podczas logowania i zanim nadejdzie jakiekolwiek zdarzenie, więc pula i tabela warnings istnieją, zanim pojawi się pierwsza komenda. Potem rejestruje /warn w Discordzie. @app_commands.guild_only() nie dopuszcza komendy w wiadomościach prywatnych, gdzie nie ma serwera, do którego można przypisać ostrzeżenie. Identyfikatory Discorda mieszczą się w BIGINT UNSIGNED. Symbole zastępcze %s wypełnia sterownik, więc powód taki jak '); DROP TABLE warnings; -- zostaje zapisany jako zwykły tekst. Nigdy nie składaj SQL za pomocą f-stringa.

4. Uruchom bota

  1. Wgraj bot.py i requirements.txt w sekcji Files.
  2. Naciśnij Uruchom i otwórz Console. Start instaluje pakiety z requirements.txt, a potem pokazuje [PlayNHost] Starting your bot i Database ready.
  3. W Discordzie wpisz /warn. Aby zobaczyć wiersze, otwórz stronę bazy i kliknij Otwórz w phpMyAdmin.

Pułapka autocommit

aiomysql otwiera połączenia z wyłączonym autocommit. INSERT zostaje wtedy w otwartej transakcji. Gdy połączenie wraca do puli z wciąż otwartą transakcją, aiomysql ją zamyka, a MariaDB odrzuca niezatwierdzony wiersz. W naszym teście wiersz wstawiony w puli bez autocommit=True widziało 0 innych połączeń. Albo przekaż autocommit=True do create_pool, jak wyżej, albo wywołaj await conn.commit() po zapisach.

Limity, które mają znaczenie dla puli

  • 20 jednoczesnych połączeń na użytkownika bazy. Liczy się każdy proces używający tego samego loginu. Połączenie 21 zostaje odrzucone z błędem (1226, "User '...' has exceeded the 'max_user_connections' resource (current value: 20)"). maxsize=5 trzyma bota wyraźnie poniżej limitu.
  • Zapytanie trwające dłużej niż 120 sekund zostaje przerwane. MariaDB kończy je błędem 1969, Query execution was interrupted (max_statement_time exceeded). W naszym teście stało się to po 120.03 sekundy. Zapytania bota zwykle trwają milisekundy, więc dotyczy to tylko zapytania, które wymknęło się spod kontroli.
  • 500 MB na bazę danych. Strona Bazy danych pokazuje, ile jest zajęte. Przy 500 MB zapisy są wstrzymywane, dopóki nie usuniesz wierszy.
  • Kopie zapasowe serwera nie obejmują bazy danych. Od czasu do czasu eksportuj ją z phpMyAdmin.

Błędy i co oznaczają

To dokładne błędy, które aiomysql zwrócił w naszym teście (pochodzą z PyMySQL, którego aiomysql używa pod spodem):

  • pymysql.err.OperationalError (1045, "Access denied for user ..."): błędny DB_USER lub DB_PASSWORD. Po Zresetuj hasło na karcie Połączenie stare hasło przestaje działać od razu: zmień DB_PASSWORD i uruchom bota ponownie.
  • pymysql.err.OperationalError (2003, "Can't connect to MySQL server on ..."): zły host lub port albo połączenie spoza PlayNHost. Baza przyjmuje tylko połączenia z serwerów PlayNHost i z phpMyAdmin, więc to samo dostaniesz na własnym komputerze.
  • (1226, ... 'max_user_connections' ...): otwartych jest za dużo połączeń, patrz limity powyżej.

Zmienna, której brakuje w Środowisko, zatrzymuje bota przed połączeniem, z komunikatem KeyError: 'DB_HOST' lub nazwą brakującej zmiennej, bo kod czyta każdą wartość przez os.environ[...]. Dodaj ją i uruchom bota ponownie: zmienne obowiązują od następnego startu.

Więcej błędów botów: Typowe błędy botów Discord i co oznaczają.

Ile pamięci to dodaje

Instalacja discord.py i aiomysql przez pip od zera osiągnęła w naszym teście szczyt 78 MB pamięci, w kontenerze z limitem 512 MB jak nasz najmniejszy plan dla botów. Ile potrzebuje działający bot, zależy głównie od tego, na ilu serwerach jest: Ile RAM potrzebuje bot Discord?

To samo w JavaScripcie albo z Prisma

Potrzebujesz serwera bota z wliczoną bazą danych? Zobacz plany dla botów.

Twój bot działa już gdzie indziej? Przenieś go do nas

NASZE OSTATNIE WPISY