aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord Botları

Discord Bot SQLite Entegrasyonu: better-sqlite3 Rehberi

Bir Discord bot SQLite kurulumu, küçük ve orta ölçekli botlar için fazlasıyla yeterli bir veritabanı çözümüdür. Ayrı bir veritabanı sunucusu kurmadan, tek bir dosyada bütün verinizi tutabilir; seviye sistemleri, ekonomi, uyarı kayıtları veya ayarlar gibi kalıcı verileri saniyeler içinde saklayabilirsiniz. Bu yazıda Node.js ve discord.js kullanan bir bota better-sqlite3 ile yerel bir veritabanı eklemeyi, tabloları kurmayı ve hızlı, güvenli sorgular yazmayı adım adım anlatıyorum.

Neden SQLite ve neden better-sqlite3?

SQLite, sunucusuz çalışan, dosya tabanlı bir ilişkisel veritabanıdır. Bir bot için bu birçok avantaj demek:

  • Sıfır kurulum: MySQL veya PostgreSQL gibi ayrı bir servis çalıştırmanıza gerek yok. Veritabanı tek bir .sqlite dosyasıdır.
  • Taşınabilirlik: Botu başka bir VPS'e taşırken sadece o dosyayı kopyalamak yeterlidir.
  • Hız: Veri uygulamayla aynı süreçte, diskte okunur. Ağ gecikmesi yoktur.

Node.js tarafında iki popüler sürücü var: node:sqlite (Node 22+ ile gelen yerleşik modül) ve better-sqlite3. Bu yazıda better-sqlite3'ü tercih ediyorum çünkü senkron API'ye sahiptir. Bu kulağa ters gelebilir ama SQLite çağrıları çok hızlı tamamlandığı için async/await zincirleriyle uğraşmadan, doğrudan ve okunaklı kod yazarsınız. Olgun, iyi test edilmiş ve hazır sorguları (prepared statement) verimli yöneten bir kütüphanedir.

Kurulum ve proje yapısı

Önce bağımlılıkları ekleyelim. better-sqlite3 yerel (native) bir modüldür, kurulurken derlenir; bu yüzden makinenizde derleme araçlarının bulunması gerekir.

npm install discord.js better-sqlite3

Basit ve düzenli bir yapı şöyle görünebilir:

my-bot/
  index.js        # botun giriş noktası
  db.js           # veritabanı bağlantısı ve şema
  data/
    bot.sqlite    # SQLite dosyası (otomatik oluşur)
  .gitignore

Önemli: data/bot.sqlite dosyasını mutlaka .gitignore'a ekleyin. Veritabanınız sürüm kontrolüne girmemeli.

Veritabanı bağlantısı ve şemayı kurmak

Bağlantıyı tek bir yerde açıp dışa aktarmak en temiz yaklaşımdır. Böylece tüm dosyalar aynı bağlantıyı paylaşır. db.js içinde:

const Database = require('better-sqlite3');
const path = require('node:path');

const db = new Database(path.join(__dirname, 'data', 'bot.sqlite'));

// Performans ve dayanıklılık için önerilen ayarlar
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');

// Tablo yoksa oluştur (uygulama her açıldığında güvenli)
db.exec(`
  CREATE TABLE IF NOT EXISTS users (
    user_id   TEXT PRIMARY KEY,
    guild_id  TEXT NOT NULL,
    xp        INTEGER NOT NULL DEFAULT 0,
    level     INTEGER NOT NULL DEFAULT 1,
    coins     INTEGER NOT NULL DEFAULT 0
  );
`);

module.exports = db;

journal_mode = WAL (Write-Ahead Logging), eşzamanlı okuma ve yazmayı çok daha iyi yönettiği için bir bot için neredeyse her zaman doğru tercihtir. CREATE TABLE IF NOT EXISTS sayesinde botu her başlattığınızda tabloyu güvenle hazırlayabilirsiniz.

Hazır sorgularla güvenli veri okuma ve yazma

better-sqlite3'te en doğru yöntem prepared statement kullanmaktır. Bu hem daha hızlıdır hem de değerleri parametre olarak geçirdiğiniz için SQL injection'a karşı korur. Asla kullanıcı girdisini string birleştirmeyle sorguya gömmeyin.

const db = require('./db');

// Sorguları bir kez hazırlayıp tekrar tekrar kullanın
const getUser = db.prepare(
  'SELECT * FROM users WHERE user_id = ? AND guild_id = ?'
);

const upsertXp = db.prepare(`
  INSERT INTO users (user_id, guild_id, xp)
  VALUES (@userId, @guildId, @amount)
  ON CONFLICT(user_id) DO UPDATE SET xp = xp + @amount
`);

function addXp(userId, guildId, amount) {
  upsertXp.run({ userId, guildId, amount });
  return getUser.get(userId, guildId);
}

Burada birkaç önemli nokta var:

  • .get() tek bir satır döndürür, .all() tüm satırları dizi olarak verir, .run() ise INSERT/UPDATE/DELETE için kullanılır.
  • ? ile sıralı, @isim ile adlandırılmış parametreler kullanabilirsiniz.
  • ON CONFLICT ... DO UPDATE (yani "upsert"), kayıt yoksa ekler, varsa günceller. Seviye sistemleri için ideal.

Bir mesaj olayını veritabanına bağlamak

Şimdi bunu discord.js tarafındaki gerçek bir olaya bağlayalım. Kullanıcı her mesaj attığında biraz XP versin:

const { Client, GatewayIntentBits } = require('discord.js');
const { addXp } = require('./xp');

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

client.on('messageCreate', (message) => {
  if (message.author.bot || !message.guild) return;

  const user = addXp(message.author.id, message.guild.id, 5);

  // Basit seviye atlama kontrolü
  const needed = user.level * 100;
  if (user.xp >= needed) {
    db.prepare('UPDATE users SET level = level + 1 WHERE user_id = ?')
      .run(message.author.id);
    message.reply(`Tebrikler, seviye ${user.level + 1}!`);
  }
});

client.login(process.env.DISCORD_TOKEN);

Dikkat: MessageContent ayrıcalıklı bir niyettir (privileged intent) ve mesaj içeriğine erişmek için Discord Developer Portal'dan açmanız gerekir.

Toplu işlemler ve performans

Çok sayıda yazma işlemini tek tek yapmak diske çok sık erişir. Bunları bir transaction içine almak hem çok daha hızlıdır hem de ya hep ya hiç güvencesi verir:

const insertMany = db.transaction((rows) => {
  for (const row of rows) upsertXp.run(row);
});

// Tek bir disk işleminde yüzlerce satır
insertMany(buyukVeriListesi);

Birkaç ek tavsiye: veritabanını sık kapatıp açmayın, tek bağlantıyı tüm uygulama boyunca kullanın; sık aradığınız sütunlara CREATE INDEX ile indeks ekleyin; ve düzenli olarak bot.sqlite dosyasının bir yedeğini alın çünkü tüm veriniz o tek dosyadadır.

Sık Sorulan Sorular

SQLite büyük bir bot için yeterli mi?

Tek bir süreçten erişilen, on binlerce kullanıcıya kadar olan botlarda SQLite gayet rahat çalışır. Çok sayıda eşzamanlı yazma yapan veya botu birden çok süreç/sunucuya yatay ölçeklemeniz gereken devasa projelerde PostgreSQL gibi bir sunucu veritabanına geçmek daha mantıklı olur.

better-sqlite3 senkron, botu bloklamaz mı?

SQLite sorguları genellikle mikrosaniyeler sürer, dolayısıyla pratikte olay döngüsünü hissedilir biçimde bloklamaz. Yine de çok büyük toplu işlemleri transaction içinde toplu yapın; tek tek binlerce sorgu çalıştırmaktan kaçının.

Veritabanı dosyası bozulursa ne olur?

WAL modu ani kapanmalara karşı dayanıklılığı artırır, ama yine de düzenli yedek şarttır. Bot çalışırken dosyayı kopyalamak yerine better-sqlite3'ün sunduğu yedekleme yöntemini veya botu durdurup dosyayı kopyalamayı tercih edin.

Botunuza sağlam bir veritabanı altyapısı mı lazım? Seviye sistemi, ekonomi veya moderasyon kayıtları için ölçeklenebilir bir Discord botu tasarlamak istiyorsanız benimle iletişime geçin — projenize uygun en doğru çözümü birlikte kuralım.

Devamı için