Kurzantwort. Füge aiomysql zu deinem discord.py-Bot hinzu, erstelle in setup_hook einen Pool mit autocommit=True und führe jede Abfrage darüber mit %s-Platzhaltern aus. Ohne autocommit=True (oder ein commit() nach jedem Schreibzugriff) speichert aiomysql deine INSERTs nicht. Bei PlayNHost enthält jeder Bot-Tarif eine MySQL-Datenbank: Lege sie auf der Seite Datenbanken an, füge ihre Zugangsdaten im Bereich Umgebung ein, und der Code unten funktioniert so, wie er ist. Die Datenbank nimmt Verbindungen von deinen PlayNHost-Servern und von phpMyAdmin an, nicht von deinem eigenen Rechner. Wir haben den Code am 6. November 2026 mit discord.py 2.7.1, aiomysql 0.3.2 und Python 3.12 getestet, gegen MariaDB 10.11 mit einem Datenbankkonto, das wie unseres eingerichtet ist (20 Verbindungen, 120 Sekunden Abfragelimit): Start, Tabelle und den Befehl /warn, aber keinen echten Discord-Login.
Ein PlayNHost-Bot-Tarif vom Typ Python Bot. Jeder Tarif enthält eine Datenbank.
1. Die Datenbank erstellen
Öffne deinen Bot-Server im Panel und klicke auf Datenbanken.
Klicke auf Neue Datenbank. Eine Bezeichnung ist optional; unter Wird erstellt als siehst du den vollständigen Namen. Klicke auf Datenbank erstellen.
Die Seite der neuen Datenbank öffnet sich (später klickst du sie unter Deine Datenbanken an). Ihre Karte Verbindung zeigt Host, Port, Datenbank, Benutzername und Passwort. Unter Fertige Config bietet Config für einen Ausschnitt Python (aiomysql) mit denselben, bereits eingetragenen Werten.
2. Die Zugangsdaten in „Umgebung“ eintragen
Öffne die Seite Bot, den Bereich Umgebung, und klicke auf Eine .env-Datei einfügen.
Füge diese fünf Zeilen mit den Werten aus der Karte Verbindung ein:
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"])
So funktioniert es: discord.py führt setup_hook einmal aus, während der Anmeldung und bevor ein Event eintrifft, sodass der Pool und die Tabelle warnings existieren, bevor der erste Befehl ankommt. Danach registriert es /warn bei Discord. @app_commands.guild_only() hält den Befehl aus Direktnachrichten heraus, wo es keinen Server zum Speichern gibt. Discord-IDs passen in BIGINT UNSIGNED. Die %s-Platzhalter füllt der Treiber aus, sodass ein Grund wie '); DROP TABLE warnings; -- als einfacher Text gespeichert wird. Baue das SQL niemals mit einem f-String zusammen.
4. Starten
Lade bot.py und requirements.txt unter Dateien hoch.
Klicke auf Starten und öffne Konsole. Beim Start werden die Pakete aus requirements.txt installiert, danach erscheinen [PlayNHost] Starting your bot und Database ready.
Tippe in Discord /warn ein. Um die Zeilen anzusehen, öffne die Seite der Datenbank und klicke auf In phpMyAdmin öffnen.
Die autocommit-Falle
aiomysql öffnet Verbindungen mit ausgeschaltetem autocommit. Ein INSERT bleibt dann in einer offenen Transaktion. Geht die Verbindung mit noch offener Transaktion zurück in den Pool, schließt aiomysql sie, und MariaDB wirft die nicht bestätigte Zeile weg. In unserem Test sahen 0 andere Verbindungen eine Zeile, die auf einem Pool ohne autocommit=True eingefügt wurde. Übergib entweder autocommit=True an create_pool, wie oben, oder rufe nach deinen Schreibzugriffen await conn.commit() auf.
Limits, die für deinen Pool wichtig sind
20 gleichzeitige Verbindungen pro Datenbankbenutzer. Jeder Prozess mit demselben Login zählt mit. Verbindung 21 wird mit (1226, "User '...' has exceeded the 'max_user_connections' resource (current value: 20)") abgelehnt. maxsize=5 hält den Bot deutlich darunter.
Eine Abfrage, die länger als 120 Sekunden läuft, wird abgebrochen. MariaDB beendet sie mit dem Fehler 1969, Query execution was interrupted (max_statement_time exceeded). In unserem Test kam das nach 120.03 Sekunden. Die Abfragen eines Bots dauern normalerweise Millisekunden, das trifft also nur eine außer Kontrolle geratene Abfrage.
500 MB pro Datenbank. Die Seite Datenbanken zeigt, wie viel belegt ist. Bei 500 MB werden Schreibzugriffe gestoppt, bis du Zeilen löschst.
Server-Backups enthalten die Datenbank nicht. Exportiere sie ab und zu aus phpMyAdmin.
Fehler und was sie bedeuten
Das sind die genauen Fehler, die aiomysql in unserem Test lieferte (sie stammen von PyMySQL, das aiomysql darunter verwendet):
pymysql.err.OperationalError (1045, "Access denied for user ..."): falscher Wert bei DB_USER oder DB_PASSWORD. Nach Passwort zurücksetzen auf der Karte Verbindung funktioniert das alte Passwort sofort nicht mehr: Ersetze DB_PASSWORD und starte den Bot neu.
pymysql.err.OperationalError (2003, "Can't connect to MySQL server on ..."): falscher Host oder Port, oder eine Verbindung von außerhalb von PlayNHost. Die Datenbank nimmt nur Verbindungen von PlayNHost-Servern und phpMyAdmin an, deshalb bekommst du diesen Fehler auch auf deinem eigenen Rechner.
(1226, ... 'max_user_connections' ...): zu viele offene Verbindungen, siehe die Limits oben.
Eine Variable, die in Umgebung fehlt, stoppt den Bot vor dem Verbindungsaufbau, mit KeyError: 'DB_HOST' oder dem Namen der fehlenden Variable, weil der Code jeden Wert mit os.environ[...] liest. Füge sie hinzu und starte den Bot neu: Variablen gelten ab dem nächsten Start.
Die Installation von discord.py und aiomysql mit pip von Grund auf erreichte in unserem Test einen Spitzenwert von 78 MB Arbeitsspeicher, in einem Container mit 512 MB Limit wie bei unserem kleinsten Bot-Tarif. Wie viel der laufende Bot braucht, hängt vor allem davon ab, auf wie vielen Servern er ist: Wie viel RAM braucht ein Discord-Bot?
Wir verwenden Cookies, damit die Website funktioniert, um ihre Nutzung zu verstehen und unser Marketing zu messen. Du kannst alles akzeptieren, nur essenzielle Cookies akzeptieren oder pro Kategorie wählen.Wir verwenden Cookies, damit die Website funktioniert, um ihre Nutzung zu verstehen und unser Marketing zu messen. Sie sind hier standardmäßig aktiv. Du kannst alles abschalten, was du nicht möchtest.Datenschutzerklärung lesen