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.js (mysql2)

Hosting botów DiscordUpdated Nov 6, 20268 min read

Krótka odpowiedź. Dodaj mysql2 do swojego bota discord.js, przy starcie bota utwórz jedną pulę połączeń ze zmiennych środowiskowych i wykonuj każde zapytanie przez nią, używając symboli zastępczych ?. 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.js 14.28.1, mysql2 3.24.6 i Node.js 22, na MariaDB 10.11 z kontem bazy skonfigurowanym jak nasze (20 połączeń, limit zapytania 120 sekund): start, tabelę i obsługę /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 Node.js (mysql2) 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. Trzymanie hasła poza kodem sprawia, że nigdy nie trafi do pliku ani do repozytorium Git. Więcej o tym panelu: Jak ustawić zmienne środowiskowe i sekrety dla bota Discord.

3. Kod

package.json

{
  "name": "my-discord-bot",
  "private": true,
  "main": "index.js",
  "dependencies": {
    "discord.js": "^14",
    "mysql2": "^3"
  }
}

index.js

const { Client, Events, GatewayIntentBits, InteractionContextType, MessageFlags, REST, Routes, SlashCommandBuilder } = require('discord.js');
const mysql = require('mysql2/promise');

// One pool for the whole bot. The values come from the Environment pane.
const pool = mysql.createPool({
  host: process.env.DB_HOST,
  port: Number(process.env.DB_PORT),
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  connectionLimit: 5,
});

const commands = [
  new SlashCommandBuilder()
    .setName('warn')
    .setDescription('Warn a member and count their warnings')
    .setContexts(InteractionContextType.Guild)
    .addUserOption((o) => o.setName('user').setDescription('Who to warn').setRequired(true))
    .addStringOption((o) => o.setName('reason').setDescription('Why').setRequired(true).setMaxLength(200))
    .toJSON(),
];

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once(Events.ClientReady, async () => {
  await new REST().setToken(process.env.DISCORD_TOKEN).put(Routes.applicationCommands(client.user.id), { body: commands });
  console.log(`Logged in as ${client.user.tag}`);
});

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand() || interaction.commandName !== 'warn' || !interaction.guildId) return;
  const user = interaction.options.getUser('user', true);
  const reason = interaction.options.getString('reason', true);
  try {
    await pool.execute('INSERT INTO warnings (guild_id, user_id, reason) VALUES (?, ?, ?)', [interaction.guildId, user.id, reason]);
    const [rows] = await pool.execute('SELECT COUNT(*) AS total FROM warnings WHERE guild_id = ? AND user_id = ?', [interaction.guildId, user.id]);
    await interaction.reply(`${user} has ${rows[0].total} warning(s).`);
  } catch (err) {
    console.error(err);
    if (!interaction.replied) await interaction.reply({ content: 'Could not save the warning. Try again later.', flags: MessageFlags.Ephemeral }).catch(console.error);
  }
});

async function main() {
  await pool.query(`CREATE TABLE IF NOT EXISTS warnings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    guild_id VARCHAR(20) NOT NULL,
    user_id VARCHAR(20) NOT NULL,
    reason VARCHAR(200) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    KEY guild_user (guild_id, user_id)
  )`);
  console.log('Database ready');
  await client.login(process.env.DISCORD_TOKEN);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

Co robi kod: przy starcie bot tworzy tabelę warnings, jeśli jej brakuje, wypisuje Database ready, a potem loguje się. /warn zapisuje ostrzeżenie i odpowiada łączną liczbą ostrzeżeń użytkownika. discord.js podaje identyfikatory Discorda jako ciągi znaków, bo są za duże na liczbę w JavaScript, więc zapisujemy je jako tekst. Symbole zastępcze ? wysyłają tekst użytkownika do bazy osobno od SQL, więc powód taki jak '); DROP TABLE warnings; -- zostaje zapisany jako zwykły tekst.

Dwie linie utrzymują bota przy życiu. setContexts(InteractionContextType.Guild) i sprawdzenie !interaction.guildId blokują /warn w wiadomości prywatnej, gdzie nie ma serwera, do którego można przypisać ostrzeżenie. Blok try/catch odpowiada krótką prywatną wiadomością, gdy zapytanie się nie powiedzie. Bez niego discord.js przekazuje błąd do zdarzenia error, a gdy nikt tam nie nasłuchuje, Node.js zatrzymuje bota. W naszym teście usunęliśmy tabelę i wykonaliśmy /warn: bot zalogował ER_NO_SUCH_TABLE, odpowiedział Could not save the warning. Try again later. i działał dalej.

4. Uruchom bota

  1. Wgraj index.js i package.json w sekcji Files. Nie wgrywaj node_modules.
  2. Naciśnij Uruchom i otwórz Console. Start instaluje pakiety, a potem pokazuje [PlayNHost] Starting your bot, Database ready i Logged in as ....
  3. W Discordzie wpisz /warn. Aby zobaczyć wiersze, otwórz stronę bazy i kliknij Otwórz w phpMyAdmin.

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: Twój bot, jego druga kopia, panel. Połączenie 21 zostaje odrzucone z błędem ER_USER_LIMIT_REACHED. W naszym teście pula z connectionLimit: 30 zakończyła się tym błędem, gdy tylko 30 zapytań działało naraz. Pula z 5 połączeniami nigdy nie otwiera więcej niż 5: dodatkowe zapytania czekają na wolne połączenie.
  • 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 komunikaty, które mysql2 zwrócił w naszym teście:

  • ER_ACCESS_DENIED_ERROR ... 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.
  • ECONNREFUSED: nic nie przyjęło połączenia pod tym hostem i portem. Sprawdź DB_HOST i DB_PORT. Brak DB_HOST też kończy się tutaj, bo mysql2 łączy się wtedy z localhost, gdzie nie działa żadna baza: zmiennej brakuje w Środowisko albo bot nie został uruchomiony ponownie po jej dodaniu.
  • ENOTFOUND: DB_HOST jest źle wpisany, więc taka nazwa nie istnieje.
  • ETIMEDOUT: nic nie odpowiedziało w ciągu 10 sekund, czyli domyślnego czasu oczekiwania mysql2. Niezależnie od komunikatu, połączenie z Twojego komputera zawiedzie: baza przyjmuje tylko połączenia z serwerów PlayNHost i z phpMyAdmin.
  • ER_USER_LIMIT_REACHED ... has exceeded the 'max_user_connections' resource (current value: 20): otwartych jest za dużo połączeń, patrz limity powyżej. Zwykle to nowe połączenie przy każdej komendzie, które nigdy nie jest zamykane, albo druga kopia bota.

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

Ile pamięci to dodaje

Instalacja discord.js i mysql2 od zera osiągnęła w naszym teście szczyt 147 MB pamięci (bez cache plików), w kontenerze z limitem 512 MB jak nasz najmniejszy plan dla botów. Od startu do chwili, gdy Discord odrzucił nasz testowy token, bot zużył najwyżej 31 MB; utworzył tabelę, ale nigdy się nie zalogował. Zalogowany bot na wielu serwerach zużywa więcej: Ile RAM potrzebuje bot Discord?

To samo w Pythonie 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