n8n ile MySQL ve PostgreSQL Veritabanı Otomasyonu

Veritabanı yönetiminde tekrarlayan işler en can sıkıcı kısımdır. Her gece aynı sorguyu çalıştırmak, belirli eşiği geçen kayıtları temizlemek, iki farklı veritabanı arasında veri senkronizasyonu yapmak… Bunları script yazarak çözebilirsiniz elbette, ama n8n bu işleri hem görsel hem de çok daha esnek bir şekilde yapmanıza imkan tanıyor. Bu yazıda hem MySQL hem de PostgreSQL üzerinde gerçek dünyadan senaryolarla n8n’in veritabanı otomasyon yeteneklerini inceleyeceğiz.

Neden n8n ile Veritabanı Otomasyonu?

Bash scriptleri veya Python ile zaten veritabanı otomasyonu yapabiliyorsunuz. Peki n8n’in farkı ne? İşin özü şu: n8n size görsellik ve entegrasyon gücü sunuyor. Bir MySQL sorgusunun sonucunu alıp Slack’e gönderirken, aynı veriyi PostgreSQL’e yazıp bir HTTP endpoint’i tetiklemek istediğinizde, bash script yazmak yerine n8n workflow’unu birkaç dakikada kurabiliyorsunuz.

Özellikle şu durumlar için n8n tercih edilebilir:

  • Çok adımlı iş akışları: Veritabanından oku, dönüştür, başka yere yaz
  • Koşullu mantık: Belirli bir değer eşiği aşıldığında farklı aksiyonlar al
  • Bildirim entegrasyonları: Slack, e-posta, Telegram gibi kanallarla kolay entegrasyon
  • Zamanlama: Cron tabanlı tetikleyiciler ile zamanlanmış görevler
  • Hata yönetimi: Görsel hata akışları ile retry mekanizmaları

Kurulum ve Bağlantı Yapılandırması

n8n’i Docker ile çalıştırdığınızı varsayıyorum. Değilse şu şekilde hızlıca ayağa kaldırabilirsiniz:

docker run -it --rm 
  --name n8n 
  -p 5678:5678 
  -e N8N_BASIC_AUTH_ACTIVE=true 
  -e N8N_BASIC_AUTH_USER=admin 
  -e N8N_BASIC_AUTH_PASSWORD=guclu_sifre 
  -v ~/.n8n:/home/node/.n8n 
  n8nio/n8n

Eğer veritabanı sunucularınız ayrı bir ağda ya da Docker network’ünde çalışıyorsa, n8n container’ının bu sunuculara erişebildiğinden emin olun. Production ortamlarda docker-compose kullanmak daha mantıklı:

version: '3.8'
services:
  n8n:
    image: n8nio/n8n
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=${N8N_PASSWORD}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n_user
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - n8n_network

  postgres:
    image: postgres:15
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n_user
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - n8n_network

networks:
  n8n_network:

volumes:
  n8n_data:
  postgres_data:

n8n arayüzüne girdikten sonra MySQL ve PostgreSQL bağlantılarını Credentials menüsünden tanımlıyorsunuz. MySQL için gerekli bilgiler: host, port, database, user, password. PostgreSQL için bunlara ek olarak SSL ayarları da mevcut, production’da mutlaka SSL aktif edin.

Senaryo 1: MySQL’den Günlük Rapor Oluşturma

En klasik senaryo: Her sabah saat 08:00’de sipariş veritabanınızdan dünkü satış özetini çekip Slack kanalına göndermek. Workflow şöyle kurulur:

Schedule Trigger -> MySQL Node -> Code Node (formatlama) -> Slack Node

MySQL node’unda çalıştıracağınız sorgu:

SELECT 
  DATE(created_at) as tarih,
  COUNT(*) as toplam_siparis,
  SUM(tutar) as toplam_ciro,
  AVG(tutar) as ortalama_siparis,
  COUNT(DISTINCT musteri_id) as tekil_musteri
FROM siparisler
WHERE DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
  AND durum != 'iptal'
GROUP BY DATE(created_at);

n8n’in MySQL node’unda bu sorguyu Query alanına yazıyorsunuz. Sorgu parametrelerini dinamik olarak da verebilirsiniz. Örneğin tarihi hardcode yazmak yerine n8n’in expression engine’ini kullanabilirsiniz:

SELECT * FROM siparisler 
WHERE created_at >= '{{ $now.minus({days: 1}).startOf('day').toISO() }}'
  AND created_at < '{{ $now.startOf('day').toISO() }}'

Code node’unda bu veriyi Slack mesajı formatına dönüştürüyorsunuz:

const veri = $input.first().json;

const mesaj = `
*Günlük Satış Raporu - ${veri.tarih}*
Toplam Sipariş: *${veri.toplam_siparis}*
Toplam Ciro: *${parseFloat(veri.toplam_ciro).toLocaleString('tr-TR', {style: 'currency', currency: 'TRY'})}*
Ortalama Sipariş: *${parseFloat(veri.ortalama_siparis).toLocaleString('tr-TR', {style: 'currency', currency: 'TRY'})}*
Tekil Müşteri: *${veri.tekil_musteri}*
`;

return [{json: {text: mesaj}}];

Senaryo 2: PostgreSQL ile Stok Uyarı Sistemi

Bir e-ticaret ya da depo yönetim sistemi düşünün. Stok seviyesi belirli bir eşiğin altına düştüğünde anında bildirim göndermek istiyorsunuz. Bu senaryo için Schedule Trigger yerine daha sık çalışan bir kontrol mekanizması gerekiyor.

Workflow: Schedule Trigger (her 30 dakika) -> PostgreSQL Node -> IF Node -> Email/Slack Node

PostgreSQL sorgusu:

SELECT 
  u.urun_adi,
  u.sku,
  s.mevcut_miktar,
  s.minimum_stok,
  s.minimum_stok - s.mevcut_miktar as eksik_miktar,
  k.kategori_adi
FROM stok s
JOIN urunler u ON s.urun_id = u.id
JOIN kategoriler k ON u.kategori_id = k.id
WHERE s.mevcut_miktar <= s.minimum_stok
  AND u.aktif = true
ORDER BY eksik_miktar DESC;

IF Node’unda koşul şu şekilde: {{ $input.all().length > 0 }} – eğer kritik stok varsa devam et, yoksa workflow bitsin.

Birden fazla ürün varsa hepsini tek mesajda göndermek için Code node gerekiyor:

const urunler = $input.all();

if (urunler.length === 0) {
  return [{json: {gonder: false}}];
}

let mesajSatirlari = ['*KRİTİK STOK UYARISI*n'];

urunler.forEach(item => {
  const u = item.json;
  mesajSatirlari.push(
    `• ${u.urun_adi} (${u.sku}): Mevcut ${u.mevcut_miktar}, Min ${u.minimum_stok}, Eksik ${u.eksik_miktar}`
  );
});

mesajSatirlari.push(`nToplam ${urunler.length} ürün kritik stok seviyesinde!`);

return [{json: {
  text: mesajSatirlari.join('n'),
  gonder: true
}}];

Senaryo 3: MySQL’den PostgreSQL’e Veri Senkronizasyonu

Bu senaryo en sık karşılaştığım durumlardan biri: Legacy bir MySQL uygulaması var, yeni geliştirilen sistem PostgreSQL kullanıyor, ikisinin belirli tablolarının senkronize kalması gerekiyor.

Workflow: Schedule Trigger -> MySQL Node (kaynak) -> Code Node (dönüşüm) -> PostgreSQL Node (hedef)

MySQL’den veri çekme:

SELECT 
  id,
  musteri_adi,
  musteri_email,
  telefon,
  adres,
  updated_at
FROM musteriler
WHERE updated_at > NOW() - INTERVAL 1 HOUR
  AND senkronize_edildi = 0;

Dönüşüm ve PostgreSQL’e yazma adımları arasında bir Code node ile veriyi normalize ediyorsunuz:

const kayitlar = $input.all();

return kayitlar.map(item => {
  const m = item.json;
  
  return {
    json: {
      kaynak_id: m.id,
      tam_ad: m.musteri_adi.trim(),
      email: m.musteri_email.toLowerCase().trim(),
      telefon: m.telefon ? m.telefon.replace(/[^0-9+]/g, '') : null,
      adres: m.adres,
      guncelleme_zamani: m.updated_at,
      senkron_zamani: new Date().toISOString()
    }
  };
});

PostgreSQL node’unda Insert or Update (upsert) modunu kullanıyorsunuz. PostgreSQL’in native upsert özelliğini kullanmak için sorguyu şöyle yazabilirsiniz:

INSERT INTO musteriler_yeni (kaynak_id, tam_ad, email, telefon, adres, guncelleme_zamani, senkron_zamani)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (kaynak_id) 
DO UPDATE SET
  tam_ad = EXCLUDED.tam_ad,
  email = EXCLUDED.email,
  telefon = EXCLUDED.telefon,
  adres = EXCLUDED.adres,
  guncelleme_zamani = EXCLUDED.guncelleme_zamani,
  senkron_zamani = EXCLUDED.senkron_zamani;

Senkronizasyon tamamlandıktan sonra MySQL’de senkronize_edildi flag’ini güncellemeyi unutmayın. Bunun için workflow’un sonuna bir MySQL Update node daha ekliyorsunuz.

Senaryo 4: Otomatik Veritabanı Temizliği

Log tabloları, geçici kayıtlar, soft-deleted veriler… Zamanla veritabanınız şişiyor. n8n ile bu temizliği otomatize edip sonuçları da kayıt altına alabilirsiniz.

-- 90 günden eski log kayıtlarını sil (MySQL)
DELETE FROM uygulama_loglari 
WHERE olusturma_tarihi < DATE_SUB(NOW(), INTERVAL 90 DAY)
  AND seviye IN ('DEBUG', 'INFO')
LIMIT 10000;

LIMIT kullanmanız kritik. Milyonlarca kayıt içeren tablolarda limitsiz DELETE komutu çalıştırmak replikasyon lag’ına ve tablo kilitlenmelerine yol açar. n8n workflow’unu döngüsel çalıştırarak bu limiti aşarak silme yapabilirsiniz.

Silinen kayıt sayısını yakalamak ve raporlamak için:

// Code node - silme sonucunu raporla
const sonuc = $input.first().json;
const silinenKayit = sonuc.affectedRows || 0;

// Bu bilgiyi bir audit tablosuna yazmak için hazırla
return [{json: {
  islem: 'log_temizligi',
  silinen_kayit: silinenKayit,
  tarih: new Date().toISOString(),
  tablo: 'uygulama_loglari',
  durum: silinenKayit > 0 ? 'basarili' : 'temizlenecek_kayit_yok'
}}];

Hata Yönetimi ve Monitoring

n8n’de hata yönetimi için her node’un sağ üst köşesindeki hata akışını (error output) kullanabilirsiniz. Veritabanı işlemlerinde connection timeout, deadlock veya syntax hataları olabilir.

Error Trigger workflow’u ayrı tutun: Ana workflow’larınızdan gelen hataları yakalayan bağımsız bir workflow oluşturun.

Temel hata yönetimi pattern’i şöyle:

// Try-catch ile veritabanı işlemini sarmalayın (Function node)
try {
  const sonuc = $input.first().json;
  
  if (!sonuc || sonuc.error) {
    throw new Error(`Veritabanı hatası: ${sonuc?.error || 'Bilinmeyen hata'}`);
  }
  
  return [{json: {
    basarili: true,
    kayit_sayisi: sonuc.length || 0,
    zaman_damgasi: new Date().toISOString()
  }}];
  
} catch (hata) {
  // Hatayı loglayıp yönlendir
  return [{json: {
    basarili: false,
    hata_mesaji: hata.message,
    zaman_damgasi: new Date().toISOString(),
    workflow: 'veritabani_senkron'
  }}];
}

Workflow execution geçmişini n8n kendi veritabanında tutuyor ama production’da bunu harici bir sisteme de göndermek iyi pratik:

-- n8n audit log tablosu (PostgreSQL)
CREATE TABLE IF NOT EXISTS n8n_workflow_log (
  id SERIAL PRIMARY KEY,
  workflow_adi VARCHAR(200),
  islem_turu VARCHAR(50),
  basarili BOOLEAN,
  kayit_sayisi INTEGER DEFAULT 0,
  hata_mesaji TEXT,
  sure_ms INTEGER,
  calisma_zamani TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_workflow_log_zaman ON n8n_workflow_log(calisma_zamani);
CREATE INDEX idx_workflow_log_adi ON n8n_workflow_log(workflow_adi);

Performans ve Güvenlik İpuçları

Veritabanı otomasyonunda dikkat edilmesi gereken birkaç kritik nokta var:

Bağlantı havuzu yönetimi: n8n her workflow çalıştığında bağlantı açıp kapatıyor. Sık tetiklenen workflow’larda bu veritabanı sunucusuna yük bindirebilir. MySQL için max_connections değerini izleyin.

Sorgu optimizasyonu: n8n üzerinden çalıştırdığınız sorgular da index kullanıyor. WHERE updated_at > X gibi koşullar için ilgili sütunda index olduğundan emin olun:

-- MySQL için
CREATE INDEX idx_musteriler_updated ON musteriler(updated_at);
CREATE INDEX idx_stok_miktar ON stok(mevcut_miktar, minimum_stok);

-- PostgreSQL için
CREATE INDEX CONCURRENTLY idx_siparisler_created 
ON siparisler(created_at) 
WHERE durum != 'iptal';

Credentials güvenliği: n8n’de veritabanı bağlantılarını tanımlarken read-only kullanıcılar kullanın, yalnızca gerekli işlemler için izin verin:

-- MySQL - sadece okuma yetkisi olan kullanıcı
CREATE USER 'n8n_readonly'@'%' IDENTIFIED BY 'guclu_sifre';
GRANT SELECT ON uygulama_db.* TO 'n8n_readonly'@'%';

-- Yazma gereken workflow için ayrı kullanıcı
CREATE USER 'n8n_sync'@'%' IDENTIFIED BY 'baska_guclu_sifre';
GRANT SELECT, INSERT, UPDATE ON uygulama_db.musteriler TO 'n8n_sync'@'%';
FLUSH PRIVILEGES;
-- PostgreSQL - role bazlı yetkilendirme
CREATE ROLE n8n_reader;
GRANT CONNECT ON DATABASE uygulama_db TO n8n_reader;
GRANT USAGE ON SCHEMA public TO n8n_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO n8n_reader;

CREATE USER n8n_workflow WITH PASSWORD 'guclu_sifre';
GRANT n8n_reader TO n8n_workflow;

Büyük veri setleri: n8n bellek sınırlıdır. Çok büyük sonuç setleri döndüren sorgularda dikkatli olun. MySQL ve PostgreSQL node’larında pagination uygulayın:

-- Sayfalı sorgu örneği (PostgreSQL)
SELECT * FROM buyuk_tablo
WHERE islem_tarihi >= '2024-01-01'
ORDER BY id
LIMIT 1000 OFFSET {{ $json.offset || 0 }};

Webhook Tetiklemeli Veritabanı İşlemleri

Zaman bazlı tetikleyiciler dışında, harici sistemlerden gelen HTTP istekleriyle de veritabanı işlemi başlatabilirsiniz. Örneğin bir uygulama kayıt oluşturduğunda n8n webhook’una istek atıp ek işlemler başlatabilir.

n8n’de Webhook Node oluşturduğunuzda size benzersiz bir URL verilir:

# Webhook'u test etmek için
curl -X POST https://n8n.sirketiniz.com/webhook/musteri-kayit 
  -H "Content-Type: application/json" 
  -H "X-API-Key: webhook_gizli_anahtari" 
  -d '{
    "musteri_id": 12345,
    "islem": "yeni_kayit",
    "kayit_zamani": "2024-01-15T10:30:00Z"
  }'

Bu webhook geldiğinde workflow şunu yapabilir: PostgreSQL’den müşterinin detaylarını çek, MySQL’deki pazarlama veritabanına yaz, CRM sistemine REST API ile bildir, hoşgeldin emaili gönder.

Workflow Versiyonlama ve Backup

n8n workflow’larınızı JSON olarak export edip Git’te versiyonlayabilirsiniz. Bu production ortamlarda çok önemli:

# n8n CLI ile workflow export (self-hosted)
n8n export:workflow --all --output=./workflows/

# Git'e ekle
cd workflows
git add .
git commit -m "Stok uyari workflow guncellendi - esik degeri degistirildi"
git push

Alternatif olarak n8n’in API’sini kullanarak workflow’ları programatik olarak yedekleyebilirsiniz:

# Tüm workflow'ları API üzerinden çek
curl -u admin:sifre 
  http://localhost:5678/api/v1/workflows 
  -H "Accept: application/json" 
  | jq '.' > workflows_backup_$(date +%Y%m%d).json

Sonuç

n8n ile veritabanı otomasyonu başlangıçta “neden script yazmayayım ki” dedirtebilir. Ama birkaç hafta kullandıktan sonra görsel akışın, kolay entegrasyonun ve merkezi yönetimin ne kadar değerli olduğunu görüyorsunuz. Özellikle birden fazla sistemin birbirine bağlandığı, hata yönetiminin kritik olduğu ve ekip içinde şeffaflık gereken durumlarda n8n gerçek bir zaman kazandırıcı.

Şunu da söyleyeyim: n8n her şeyin çözümü değil. Çok karmaşık veri dönüşümleri, yüksek frekanslı işlemler veya özel kütüphane gerektiren senaryolarda yine script veya özel uygulama yazmak gerekebilir. Ama günlük raporlama, uyarı sistemleri, basit senkronizasyonlar ve veri temizliği gibi işler için n8n mükemmel bir araç.

En pratik tavsiyem: Küçük başlayın. Önce tek bir tekrarlayan görevi n8n’e taşıyın, nasıl davrandığını gözlemleyin, hata senaryolarını test edin. Güven oluştuktan sonra daha kritik işlemleri de otomatize etmeye başlayabilirsiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir