YENİ 📢 Sınırlı lansman teklifi: Tüm oyunlarda ilk aya %70'e varan indirim!Paketleri görün

grammY botuyla MySQL veritabanı nasıl kullanılır (mysql2)

Telegram botlarıUpdated Nov 6, 202610 min read

Kısa yanıt. grammY botunuza mysql2 ekleyin, bot başlarken ortam değişkenlerinden tek bir bağlantı havuzu oluşturun, tablolarınızı bot.start() çağrısından önce oluşturun ve her sorguyu havuz üzerinden çalıştırın. ? yer tutucularını kullanın ve Telegram kimliklerini BIGINT olarak saklayın, INT olarak değil. PlayNHost'ta her bot planı bir MySQL veritabanı içerir: bunu Veritabanları sayfasında oluşturun, bilgilerini Ortam bölmesine yapıştırın; aşağıdaki kod olduğu gibi çalışır. Veritabanı, PlayNHost sunucularınızdan ve phpMyAdmin'den gelen bağlantıları kabul eder, kendi bilgisayarınızdan gelenleri kabul etmez. Bu kodu 6 Kasım 2026 tarihinde grammY 1.46.0, mysql2 3.24.6 ve Node.js 22 ile, bizimki gibi kurulmuş bir veritabanı hesabıyla (20 bağlantı, 120 saniyelik sorgu sınırı) MariaDB 10.11 üzerinde ve Telegram'ın Bot API sunucusunun yerine geçen bir vekille test ettik: 8 komut girdi, 8 yanıt çıktı, notlar veritabanına kaydedildi. Gerçek bir Telegram girişi testin parçası değildi.

İhtiyacınız olanlar

1. Veritabanını oluşturun

  1. Bot sunucunuzu panel içinde açın ve Veritabanları sayfasına tıklayın.
  2. Yeni veritabanı düğmesine tıklayın. Etiket isteğe bağlıdır; Şu adla oluşturulacak: tam adı gösterir. Veritabanı oluştur düğmesine tıklayın.
  3. Yeni veritabanının sayfası açılır (sonradan Veritabanlarınız bölümünden ona tıklayın). Bağlantı kartı şunları gösterir: Sunucu adresi, Port, Veritabanı, Kullanıcı Adı ve Şifre. Hazır yapılandırma altında, Şunun için yapılandırma bölümünde Node.js (mysql2) parçacığı, aynı değerler doldurulmuş olarak yer alır.

2. Bilgileri Ortam bölümüne girin

  1. Bot sayfasını açın, Ortam bölmesinde .env dosyası yapıştır düğmesine tıklayın.
  2. Bağlantı kartındaki değerlerle bu beş satırı yapıştırın:
    DB_HOST=your-host
    DB_PORT=3306
    DB_NAME=your-database
    DB_USER=your-username
    DB_PASSWORD=your-password
  3. DB_PASSWORD için Gizli rozeti gösterilir: yalnızca yazma yönlü kaydedilir ve bir daha gösterilmez. 5 değişkeni içe aktar düğmesine tıklayın.

Bağlantı kartındaki gerçek portu kullanın. Bot token'ı bu satırlardan biri değildir: Bot sayfasında Telegram bölmesine kaydettiğiniz token, kodunuza zaten TELEGRAM_BOT_TOKEN adıyla ulaşır; aşağıdaki kodun okuduğu ad budur (ayrıca BOT_TOKEN, TOKEN, TELEGRAM_TOKEN ve TELOXIDE_TOKEN adlarıyla da). .env dosyanızda bir token satırı varsa, pencere onu atlar. Bu bölme hakkında daha fazlası: Discord botunuz için ortam değişkenleri ve gizli değerler nasıl ayarlanır.

3. Kod

Küçük bir not botu: /note buy milk bir not kaydeder, /notes son beş notunuzu gösterir.

package.json

{
  "name": "my-grammy-bot",
  "private": true,
  "main": "index.js",
  "dependencies": {
    "grammy": "^1.46.0",
    "mysql2": "^3.24.6"
  }
}

index.js

const { Bot } = require("grammy");
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),
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  connectionLimit: 5,
});

const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN);

bot.command("note", async (ctx) => {
  const text = ctx.match.trim();
  if (!text) return ctx.reply("Write your note after the command, for example: /note buy milk");
  if (text.length > 500) return ctx.reply("A note can be up to 500 characters.");
  await pool.execute("INSERT INTO notes (user_id, text) VALUES (?, ?)", [ctx.from.id, text]);
  await ctx.reply("Saved. Send /notes to see your last five.");
});

bot.command("notes", async (ctx) => {
  const [rows] = await pool.execute(
    "SELECT text FROM notes WHERE user_id = ? ORDER BY id DESC LIMIT 5",
    [ctx.from.id],
  );
  if (rows.length === 0) return ctx.reply("You have no notes yet.");
  await ctx.reply(rows.map((row) => `- ${row.text}`).join("\n"));
});

// Without this, an error in one command stops the whole bot.
bot.catch((err) => {
  console.error(`Error while handling update ${err.ctx.update.update_id}:`, err.error);
});

async function main() {
  await pool.query(
    "CREATE TABLE IF NOT EXISTS notes (" +
      "id INT AUTO_INCREMENT PRIMARY KEY, " +
      "user_id BIGINT NOT NULL, " +
      "text VARCHAR(500) NOT NULL, " +
      "created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
      "KEY user_id (user_id))",
  );
  console.log("Database ready");
  // bot.start() only returns when the bot stops, so the ready line goes in onStart.
  await bot.start({ onStart: (me) => console.log(`Logged in as @${me.username}`) });
}

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

Ne yapar: main() eksikse notes tablosunu oluşturur ve Database ready yazdırır; bu, bot.start() Telegram'dan mesaj istemeden önce gerçekleşir. Havuz dosyanın en üstünde bir kez oluşturulur ve her komut onu kullanır: pool.execute() bir bağlantı ödünç alır, sorguyu çalıştırır ve bağlantıyı geri verir. ctx.match komuttan sonraki metindir: grammY önündeki boşlukları kaldırır, geri kalanı satır sonları dahil yazıldığı gibi tutar. bot.catch() burada önemlidir: grammY belgelerine göre, hata işleyicisi yoksa bir işleyicideki hata bot.start() ile başlatılmış botu durdurur ve bir veritabanı hatası tam olarak bu tür bir hatadır.

? yer tutucuları notu SQL'den ayrı olarak veritabanına gönderir; bu yüzden '); DROP TABLE notes; -- gibi bir not düz metin olarak saklanır. Testimizde 2. satır olarak kaydedildi ve tablo yerinde kaldı. SQL'i asla şablon dizgesiyle oluşturmayın.

Telegram kimliklerini BIGINT olarak saklayın

Telegram'ın Bot API belgeleri, bir kullanıcı veya sohbet kimliğinin “32 bitten fazla anlamlı bit içerebileceğini” ama en fazla 52 bit olduğunu söyler, dolayısıyla 64 bitlik bir tam sayı güvenlidir. Kimlikler sayfası aralıkları verir: kullanıcı kimlikleri 1.099.511.627.775'e kadar çıkar, grup, süper grup ve kanal kimlikleri ise negatiftir. Süper gruplar ve kanallar -1.000.000.000.001 ile -1.997.852.516.352 arasında yer alır (örneğin -1001234567890). MySQL'de INT 2.147.483.647'de durur. Testimizde, veritabanı sunucumuzun kullandığı aynı katı SQL kipiyle, 7.000.000.001 kullanıcı kimliğini bir INT sütununa kaydetmek başarısız oldu. mysql2 şu hata kodunu verdi: ER_WARN_DATA_OUT_OF_RANGE (errno 1264), ileti şuydu:

Out of range value for column 'user_id' at row 1

Bir BIGINT sütunu bunu sakladı, -1001234567890 değerini de. Düz BIGINT kullanın, BIGINT UNSIGNED değil; böylece sohbet kimlikleri de sığar.

4. Çalıştırın

  1. index.js ve package.json dosyalarını Dosyalar bölümünden yükleyin. node_modules klasörünü yüklemeyin.
  2. Başlat düğmesine basın ve Konsol bölümünü açın. Başlatınca package.json içindeki paketler kurulur, ardından [PlayNHost] Starting your bot, Database ready ve Logged in as @your_bot satırları görünür. Bu son satır, Genel bakış bölümündeki durumu Telegram’da çevrimiçi yapar.
  3. Telegram'da botunuza /note buy milk ve ardından /notes gönderin. Satırlara bakmak için veritabanının sayfasını açın ve phpMyAdmin’de aç düğmesine tıklayın.

Testimizde Telegram'ın yerine geçen vekil şu komutları gönderdi ve şu yanıtları aldı:

GönderilenYanıt
/note buy milkSaved. Send /notes to see your last five.
/noteWrite your note after the command, for example: /note buy milk
/note ve 501 karakterA note can be up to 500 characters.
/notesKaydedilen notlar, en yeniler başta
/notes ikinci bir kullanıcıdanYou have no notes yet.

Aynı anda çok mesaj

grammY belgeleri bot.start() çağrısının tüm güncellemeleri sırayla işlediğini söyler: bir komut, sonrakinden önce biter. Testimizde bot, 8 komutu yanıtladıktan sonra 1 açık bağlantı tuttu. connectionLimit: 5 ayarı, kodunuz sorguları paralel çalıştırdığında ya da güncellemeleri eşzamanlı işleyen grammY runner'a geçtiğinizde önem kazanır: havuz hiçbir zaman 5'ten fazla bağlantı açmaz, fazladan bir sorgu boş bir bağlantıyı bekler.

Başarısız bir sorgu botu durdurmaz

Testimizde bot çalışırken tabloyu sildik ve /notes gönderdik. bot.catch() şunu yazdırdı: Error while handling update 500001: Error: Table '...notes' doesn't exist; ayrıca code: 'ER_NO_SUCH_TABLE' vardı. Bot o komuta yanıt göndermedi ve çalışmaya devam etti: tablo geri gelince sonraki /note kaydedildi. Komutu gönderen kişi hiçbir şey görmez; bu yüzden bir sorgu başarısız olabiliyorsa, işleyicide onu try/catch içine alın ve kısa bir mesajla yanıt verin.

Sessiz bir gece havuzu bozmaz

Veritabanı sunucumuz 8 saat boşta kalan bir bağlantıyı kapatır. O kadar uzun süre mesaj almayan bir bot, örneğin gece boyunca, havuzdaki bağlantılarını kapalı bulur. mysql2'nin havuzu bunu kendi başına halleder. Boşta kalma sınırını 5 saniyeye indirerek denedik: 7 sessiz saniye sonra sonraki /note hatasız kaydedildi.

Havuzunuz için önemli sınırlar

  • Veritabanı kullanıcısı başına aynı anda 20 bağlantı. Aynı girişi kullanan her işlem sayılır. 21. bağlantı ER_USER_LIMIT_REACHED ile reddedilir. Testimizde connectionLimit: 30 olan bir havuz, 30 sorgu aynı anda çalışınca bu hatayla başarısız oldu. 5'lik bir havuz botu sınırın çok altında tutar.
  • 120 saniyeden uzun süren bir sorgu durdurulur. MariaDB bunu 1969 hatasıyla sonlandırır: Query execution was interrupted (max_statement_time exceeded). Daha önceki bir testimizde, aynı şekilde kurulmuş bir hesapta bu 120,03 saniye sonra oldu. Bir botun sorguları normalde milisaniyeler sürer, bu yüzden bu yalnızca kontrolden çıkmış bir sorguyu etkiler.
  • Veritabanı başına 500 MB. Veritabanları sayfası ne kadarının kullanıldığını gösterir. 500 MB'a ulaşınca, siz satır silene kadar yazma işlemleri durdurulur.
  • Sunucu yedekleri veritabanını içermez. Onu zaman zaman phpMyAdmin'den dışa aktarın.

Hatalar ve ne anlama geldikleri

mysql2'nin testimizde verdiği hata kodları şunlar:

  • ER_ACCESS_DENIED_ERROR ... Access denied for user: DB_USER veya DB_PASSWORD yanlış. Şifreyi sıfırla düğmesine (Bağlantı kartı) bastıktan sonra eski şifre hemen geçersiz olur: DB_PASSWORD değerini değiştirin ve botu yeniden başlatın.
  • ECONNREFUSED: o host ve portta hiçbir şey bağlantıyı kabul etmedi. DB_HOST ve DB_PORT değerlerini kontrol edin. DB_HOST eksikse de buraya düşersiniz, çünkü mysql2 o zaman localhost adresine bağlanır, orada veritabanı çalışmaz: değişken Ortam bölümünde eksiktir ya da eklendikten sonra bot yeniden başlatılmamıştır.
  • ENOTFOUND: DB_HOST yanlış yazılmış, bu yüzden böyle bir ad yok.
  • ETIMEDOUT: zamanında hiçbir yanıt gelmedi. İleti ne olursa olsun, kendi bilgisayarınızdan bağlantı başarısız olur: veritabanı yalnızca PlayNHost sunucularından ve phpMyAdmin'den gelen bağlantıları kabul eder.
  • ER_USER_LIMIT_REACHED ... has exceeded the 'max_user_connections' resource (current value: 20): çok fazla bağlantı açık, yukarıdaki sınırlara bakın. Örneğin botun ikinci bir kopyası ya da her mesaj için oluşturulan bir havuz.
  • ER_WARN_DATA_OUT_OF_RANGE (errno 1264, Out of range value for column 'user_id' at row 1): bir kimlik sütunu INT türünde. Bunu BIGINT yapın.
  • ER_NO_SUCH_TABLE (errno 1146): tablo eksik. Yukarıdaki kod onu başlangıçta oluşturur; elle yaptıysanız adını kontrol edin.

Yanlış bir token, veritabanı bölümünden sonra ortaya çıkar. Sahte tokenimizle gerçek Telegram'a bağlanınca bot Database ready yazdırdı, ardından yaklaşık çeyrek saniye sonra GrammyError: Call to 'deleteWebhook' failed! (401: Unauthorized) hatasıyla durdu. Token'ı @BotFather'dan yeniden kopyalayın ve Bot sayfasında Telegram bölmesine yapıştırın. Daha fazla Telegram hatası: Telegram botu 409 Conflict hatasını düzeltin.

Ne kadar bellek kullanır

Testimizde çalışan bot, 8 komutu yanıtladıktan sonra havuzu açıkken, en küçük bot planımız gibi 512 MB ile sınırlı bir konteynerde 67,6 MB bellek (resident) kullandı. Daha önceki barındırma testimizde grammY tek başına 60 MB ölçüldü (o bot reddedilen bir token'da durdu, hiçbir mesajı işlemeden), bu yüzden yaklaşık 8 MB'lık fark mysql2'yi, havuzu ve işlenen komutları kapsar. grammY ve mysql2'yi npm ile sıfırdan kurmak, dosya önbelleği dahil 140 MB'ta zirve yaptı.

Başka bir kütüphaneyle aynı şey

Telegram botunuz için veritabanı dahil bir sunucuya mı ihtiyacınız var? Telegram bot planlarına göz atın.

Botun başka bir yerde mi? Bize taşı

EN YENİ BLOG YAZILARIMIZ