NestJS Veritabanı Entegrasyonu: 7 Adımda Kapsamlı Rehber [2026]
Yazar: Burak Balkı | Kategori: Database | Okuma Süresi: 43 dk
Bu kapsamlı 2026 rehberinde, NestJS ile veritabanı entegrasyonunun derinliklerine inerek, kurulumdan ileri seviye tekniklere, performans optimizasyonundan ge...
# NestJS Veritabanı Entegrasyonu: 7 Adımda Kapsamlı Rehber [2026]
Modern web uygulamalarının kalbi, veritabanı etkileşimlerinde yatar. Peki, bu etkileşimleri sağlam, ölçeklenebilir ve yönetilebilir kılmak için hangi araçları kullanmalıyız? NestJS, güçlü modüler yapısı ve TypeScript desteğiyle, veritabanı entegrasyonlarını baştan sona yeniden tanımlıyor. Bu kapsamlı 2026 rehberinde, NestJS ile veritabanı yönetiminin derinliklerine inecek, pratik örneklerle en iyi uygulamaları öğrenecek ve projelerinizde hemen uygulayabileceğiniz ileri seviye teknikleri keşfedeceksiniz.
## NestJS Nedir?
NestJS, verimli ve ölçeklenebilir sunucu tarafı uygulamaları oluşturmak için kullanılan, aşamalı bir Node.js çerçevesidir. TypeScript ile oluşturulmuş olup, modüler, test edilebilir ve sürdürülebilir uygulamalar geliştirmek için iyi yapılandırılmış bir mimari sunar. **NestJS v12.x.x** sürümüyle birlikte, özellikle kurumsal düzeyde veritabanı entegrasyonları için geliştiricilere güçlü araçlar sağlamaktadır.
NestJS, Angular'dan esinlenen bir mimariye sahiptir ve bağımlılık enjeksiyonu (Dependency Injection), modüller, servisler ve denetleyiciler gibi kavramları Node.js ekosistemine getirir. Bu sayede, karmaşık iş mantıklarını ve özellikle veritabanı işlemlerini düzenli ve bakımı kolay bir şekilde yönetmeyi mümkün kılar. Mikroservisler, GraphQL API'leri ve sunucu tarafı renderlama gibi modern uygulama mimarileri için de ideal bir seçimdir.
## Neden NestJS Kullanmalısınız? (Veritabanı Odaklı)
NestJS, özellikle veritabanı yoğun uygulamalar için birçok avantaj sunar. Ekibimizde NestJS'e geçiş sürecinde, veritabanı katmanındaki tutarlılık ve geliştirme hızındaki artış bizi en çok etkileyen faktörler oldu.
* **Güçlü Modüler Mimari:** Veritabanı bağlantılarını, modelleri ve repository'leri modüllere ayırarak, uygulamanın farklı bölümlerinin bağımsız olarak geliştirilmesini ve test edilmesini sağlar. Bu, büyük ölçekli uygulamalarda veritabanı katmanının yönetimini kolaylaştırır.
* **TypeScript Desteği:** Tür güvenliği sayesinde veritabanı şemalarıyla etkileşimde hataları derleme zamanında yakalayabilir, refactoring işlemlerini güvenle yapabilirsiniz. Bu, özellikle karmaşık veritabanı sorgularında ve veri dönüşümlerinde kritik öneme sahiptir.
* **Bağımlılık Enjeksiyonu (DI):** Veritabanı bağlantılarını, ORM servislerini veya özel repository'leri kolayca enjekte ederek, bileşenler arası bağımlılıkları azaltır ve test edilebilirliği artırır. Bu, özellikle `Unit of Work` veya `Repository Pattern` gibi tasarım desenlerini uygularken büyük kolaylık sağlar.
* **ORM Entegrasyonları:** TypeORM, Prisma, Sequelize gibi popüler ORM'ler için resmi veya topluluk destekli entegrasyonlar sunar. Bu entegrasyonlar, veritabanı işlemlerini daha soyut ve yönetilebilir hale getirir.
* **Test Edilebilirlik:** Modüler yapı ve DI sayesinde, veritabanı etkileşimlerini kolayca mock'layabilir ve izole bir şekilde test edebilirsiniz. Production ortamında karşılaştığımız veri tutarlılığı sorunlarının önüne geçmede bu testler hayati rol oynamıştır.
* **Ölçeklenebilirlik:** Mikroservis mimarileri için doğal desteği sayesinde, veritabanı işlemlerini farklı servisler arasında dağıtabilir, yatay ölçeklendirmeyi kolaylaştırabilirsiniz. Bu, yüksek trafikli uygulamalar için NestJS'i ideal kılar.
* **Aktif Topluluk ve Dokümantasyon:** Geniş ve aktif NestJS topluluğu, veritabanı entegrasyonları dahil birçok konuda zengin kaynaklar ve destek sunar. Resmi dokümantasyon, veritabanı modüllerini ve ORM entegrasyonlarını detaylıca açıklar.
## NestJS (TypeORM) vs Alternatifler (Veritabanı Katmanı)
NestJS ile veritabanı entegrasyonu genellikle bir ORM (Object-Relational Mapper) aracılığıyla yapılır. En popüler seçeneklerden biri TypeORM'dur. Şimdi NestJS + TypeORM'u diğer popüler Node.js veritabanı çözümleriyle karşılaştıralım.
| Özellik | NestJS + TypeORM (v0.4.x) | Express + Sequelize (v7.x.x) | Fastify + Prisma (v6.x.x) |
| :------------------ | :------------------------------------------------------ | :------------------------------------------------------- | :-------------------------------------------------------- |
| **Performans** | Orta-Yüksek (Optimize edilebilir) | Orta (ORM overhead) | Yüksek (Rust tabanlı motor, optimize sorgular) |
| **Öğrenme Eğrisi** | Orta (NestJS ve TypeORM konseptleri) | Orta (Express ve Sequelize konseptleri) | Düşük-Orta (Prisma'nın sezgisel DSL'i) |
| **Ekosistem** | Geniş (NestJS modülleri, TypeORM entegrasyonları) | Çok Geniş (Express middleware, Sequelize eklentileri) | Orta-Geniş (Prisma Studio, Data Proxy) |
| **Topluluk** | Çok Aktif (NestJS ve TypeORM) | Çok Aktif (Express ve Sequelize) | Aktif ve Hızla Büyüyen (Prisma) |
| **Kurumsal Destek** | İyi (NestJS kurumsal projelerde yaygın) | Çok İyi (Express endüstri standardı) | İyi (Prisma Enterprise) |
| **Kullanım Alanı** | Kurumsal API'ler, mikroservisler, GraphQL | Genel amaçlı API'ler, web uygulamaları | Modern API'ler, mikroservisler, GraphQL (type-safe) |
| **Type Safety** | Mükemmel (TypeScript + TypeORM varlıkları) | Orta (TypeScript ile kullanılabilir, daha az entegre) | Mükemmel (TypeScript ile tam entegre, otomatik tip üretimi) |
| **Migration Yönetimi**| İyi (TypeORM CLI) | İyi (Sequelize CLI) | Çok İyi (Prisma Migrate, declarative şema) |
Bu karşılaştırma, NestJS'in özellikle TypeORM ile birleştiğinde, güçlü tip güvenliği ve modüler yapısıyla kurumsal uygulamalar için sağlam bir veritabanı katmanı sunduğunu göstermektedir. Prisma ise, özellikle **2026** itibarıyla sunduğu Rust tabanlı motoru ve declarative şema yönetimiyle performans ve geliştirici deneyimi açısından güçlü bir alternatif olarak öne çıkmaktadır. Seçim, projenin gereksinimlerine, ekibin deneyimine ve performans beklentilerine göre değişebilir.
## Kurulum ve İlk Adımlar: NestJS ve PostgreSQL Entegrasyonu
NestJS ile veritabanı entegrasyonuna başlamak için ilk olarak NestJS projesi oluşturmalı ve ardından bir veritabanı (örneğin PostgreSQL) ile ORM (örneğin TypeORM) bağımlılıklarını eklemeliyiz. Bu bölümde, bir NestJS projesini nasıl kuracağınızı ve TypeORM ile PostgreSQL bağlantısını nasıl yapılandıracağınızı adım adım göstereceğim.
### Ön Gereksinimler:
* Node.js (v18.x.x veya üzeri, 2026 itibarıyla) ve npm/yarn kurulu olmalı.
* PostgreSQL veritabanı sunucusu çalışıyor olmalı.
* NestJS CLI kurulu olmalı: `npm i -g @nestjs/cli@^12.0.0` (2026 güncel versiyon)
### 1. NestJS Projesi Oluşturma
```bash
# Yeni bir NestJS projesi oluşturun
nest new nestjs-database-app --strict --package-manager npm
# Proje dizinine gidin
cd nestjs-database-app
```
### 2. Gerekli Bağımlılıkları Kurma
TypeORM ve PostgreSQL sürücüsü için gerekli paketleri kurun:
```bash
npm install @nestjs/typeorm typeorm pg
```
### 3. Veritabanı Yapılandırması (`app.module.ts`)
`src/app.module.ts` dosyasını güncelleyerek TypeORM modülünü projenize entegre edin. Ortam değişkenlerini kullanmak en iyi pratiktir.
```typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432', 10),
username: process.env.DB_USERNAME || 'postgres',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_DATABASE || 'nestjs_db_2026',
entities: [__dirname + '/**/*.entity{.ts,.js}'], // Entity'lerinizin yolu
synchronize: process.env.NODE_ENV !== 'production', // Geliştirmede true, prod'da false olmalı!
logging: process.env.NODE_ENV === 'development', // Geliştirmede true, prod'da false
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
```
> **Pro Tip:** `synchronize: true` ayarı, geliştirme ortamında entity'lerinizdeki değişikliklere göre veritabanı şemasını otomatik olarak günceller. Ancak **production ortamında ASLA bu ayarı `true` bırakmayın!** Veri kaybına yol açabilir. Bunun yerine migration'ları kullanın.
### 4. Ortam Değişkenleri (`.env`)
Projenizin kök dizininde bir `.env` dosyası oluşturun ve veritabanı bilgilerinizi buraya ekleyin. `dotenv` paketini kurmayı unutmayın (`npm install dotenv`).
```dotenv
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=password
DB_DATABASE=nestjs_db_2026
```
### 5. `main.ts` dosyasında `dotenv` yapılandırması
`src/main.ts` dosyasının en başına aşağıdaki kodu ekleyerek ortam değişkenlerini yükleyin:
```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv'; // Ekleyin
dotenv.config(); // Ekleyin
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
```
### 6. Uygulamayı Başlatma
```bash
npm run start:dev
```
Konsolda herhangi bir hata görmüyorsanız, NestJS uygulamanız veritabanına başarıyla bağlanmış demektir.
## Temel Kullanım ve Örnekler: CRUD İşlemleri
Bu bölümde, NestJS ve TypeORM kullanarak temel CRUD (Create, Read, Update, Delete) operasyonlarını nasıl gerçekleştireceğinizi göstereceğim. Bir `Product` (Ürün) entity'si üzerinden ilerleyeceğiz.
### 1. `Product` Entity'si Oluşturma
`src/products/product.entity.ts` dosyasını oluşturun:
```typescript
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity('products') // Veritabanındaki tablo adı
export class Product {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 255, unique: true })
name: string;
@Column('text')
description: string;
@Column('decimal', { precision: 10, scale: 2 })
price: number;
@Column({ default: true })
isActive: boolean;
}
```
### 2. `Products` Modülü Oluşturma
`nest generate module products` komutunu çalıştırın. Ardından `src/products/products.module.ts` dosyasını güncelleyin:
```typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Product } from './product.entity';
import { ProductsService } from './products.service';
import { ProductsController } from './products.controller';
@Module({
imports: [TypeOrmModule.forFeature([Product])],
providers: [ProductsService],
controllers: [ProductsController],
})
export class ProductsModule {}
```
`app.module.ts` içinde `ProductsModule`'ü import etmeyi unutmayın:
```typescript
// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ProductsModule } from './products/products.module'; // Ekleyin
// ... (diğer ayarlar)
@Module({
imports: [
// ... (TypeOrmModule.forRoot ayarı)
ProductsModule, // Ekleyin
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
```
### 3. `ProductsService` Oluşturma
`nest generate service products` komutunu çalıştırın. `src/products/products.service.ts` dosyasını güncelleyin:
```typescript
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Product } from './product.entity';
@Injectable()
export class ProductsService {
constructor(
@InjectRepository(Product)
private productsRepository: Repository,
) {}
async findAll(): Promise {
return this.productsRepository.find();
}
async findOne(id: number): Promise {
const product = await this.productsRepository.findOneBy({ id });
if (!product) {
throw new NotFoundException(`Product with ID ${id} not found`);
}
return product;
}
async create(product: Partial): Promise {
const newProduct = this.productsRepository.create(product);
return this.productsRepository.save(newProduct);
}
async update(id: number, product: Partial): Promise {
const existingProduct = await this.findOne(id);
this.productsRepository.merge(existingProduct, product);
return this.productsRepository.save(existingProduct);
}
async remove(id: number): Promise {
const result = await this.productsRepository.delete(id);
if (result.affected === 0) {
throw new NotFoundException(`Product with ID ${id} not found`);
}
}
}
```
### 4. `ProductsController` Oluşturma
`nest generate controller products` komutunu çalıştırın. `src/products/products.controller.ts` dosyasını güncelleyin:
```typescript
import { Controller, Get, Post, Put, Delete, Param, Body, HttpCode, HttpStatus } from '@nestjs/common';
import { ProductsService } from './products.service';
import { Product } from './product.entity';
@Controller('products')
export class ProductsController {
constructor(private readonly productsService: ProductsService) {}
@Get()
findAll(): Promise {
return this.productsService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Promise {
return this.productsService.findOne(+id);
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() product: Partial): Promise {
return this.productsService.create(product);
}
@Put(':id')
update(@Param('id') id: string, @Body() product: Partial): Promise {
return this.productsService.update(+id, product);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string): Promise {
return this.productsService.remove(+id);
}
}
```
Artık uygulamanızı başlatıp (`npm run start:dev`) `http://localhost:3000/products` endpoint'ine HTTP istekleri göndererek CRUD işlemlerini test edebilirsiniz.
## İleri Seviye Teknikler: Veritabanı Yönetimi
NestJS ile veritabanı etkileşimlerini daha ileri seviyeye taşımak için kullanabileceğiniz bazı önemli teknikler şunlardır:
### 1. İşlemler (Transactions)
Birden fazla veritabanı işleminin atomik bir şekilde (ya hepsi başarılı ya da hiçbiri) yürütülmesi gerektiğinde işlemler kullanılır. TypeORM, `@Transactional` veya `EntityManager` ile işlem yönetimini kolaylaştırır.
```typescript
// src/products/products.service.ts içinde bir örnek
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm'; // DataSource'u import edin
import { Product } from './product.entity';
@Injectable()
export class ProductsService {
constructor(
@InjectRepository(Product)
private productsRepository: Repository,
private dataSource: DataSource, // DataSource'u enjekte edin
) {}
async transferStock(productId1: number, productId2: number, quantity: number): Promise {
await this.dataSource.transaction(async (manager) => {
const product1 = await manager.findOneBy(Product, { id: productId1 });
const product2 = await manager.findOneBy(Product, { id: productId2 });
if (!product1 || !product2) {
throw new NotFoundException('One or both products not found.');
}
if (product1.stock < quantity) {
throw new Error('Insufficient stock for product 1.');
}
product1.stock -= quantity;
product2.stock += quantity;
await manager.save(product1);
await manager.save(product2);
});
}
}
```
### 2. Özel Repository'ler (Custom Repositories)
TypeORM'un temel `Repository` sınıfı çoğu işlem için yeterli olsa da, karmaşık sorguları veya iş mantığını kapsayan özel veritabanı erişim katmanları oluşturmak için özel repository'ler tanımlayabilirsiniz. Bu, kod tekrarını önler ve test edilebilirliği artırır.
```typescript
// src/products/product.repository.ts
import { Repository, DataSource } from 'typeorm';
import { Product } from './product.entity';
import { Injectable } from '@nestjs/common';
@Injectable()
export class ProductRepository extends Repository {
constructor(private dataSource: DataSource) {
super(Product, dataSource.createEntityManager());
}
async findActiveProducts(): Promise {
return this.createQueryBuilder('product')
.where('product.isActive = :isActive', { isActive: true })
.orderBy('product.name', 'ASC')
.getMany();
}
async findProductWithHighPrice(minPrice: number): Promise {
return this.createQueryBuilder('product')
.where('product.price >= :minPrice', { minPrice })
.getMany();
}
}
```
Bu repository'yi kullanmak için `ProductsModule`'e eklemeniz ve `ProductsService` içinde enjekte etmeniz gerekir.
```typescript
// src/products/products.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Product } from './product.entity';
import { ProductsService } from './products.service';
import { ProductsController } from './products.controller';
import { ProductRepository } from './product.repository'; // Ekleyin
@Module({
imports: [TypeOrmModule.forFeature([Product])],
providers: [ProductsService, ProductRepository], // Ekleyin
controllers: [ProductsController],
exports: [TypeOrmModule, ProductRepository] // Dışarıya aktarın
})
export class ProductsModule {}
```
```typescript
// src/products/products.service.ts içinde kullanımı
import { Injectable } from '@nestjs/common';
import { ProductRepository } from './product.repository'; // Kendi repository'nizi import edin
@Injectable()
export class ProductsService {
constructor(
private productRepository: ProductRepository, // Kendi repository'nizi enjekte edin
) {}
async getHighPricedActiveProducts(minPrice: number): Promise {
return this.productRepository.findActiveProducts().then(activeProducts =>
activeProducts.filter(p => p.price >= minPrice)
);
// Veya daha iyisi, doğrudan özel repoda birleştirilmiş bir sorgu yazın
}
}
```
### 3. Veri Tohumlama (Data Seeding)
Uygulamanın başlangıcında veya testler için veritabanına başlangıç verileri eklemek (seeding) yaygın bir ihtiyaçtır. NestJS'te bu işlemi özel bir CLI komutu veya uygulamanın başlatılması sırasında yapabilirsiniz.
```typescript
// src/database/seeders/product.seeder.ts
import { DataSource } from 'typeorm';
import { Product } from '../../products/product.entity';
export class ProductSeeder {
public async run(dataSource: DataSource): Promise {
const productRepository = dataSource.getRepository(Product);
const products = [
{ name: 'Laptop Pro 2026', description: 'En yeni nesil laptop', price: 2500.00, isActive: true },
{ name: 'Gaming Mouse X', description: 'Yüksek performanslı gaming mouse', price: 75.00, isActive: true },
{ name: 'Ergonomik Klavye', description: 'Uzun süreli kullanım için ideal', price: 120.00, isActive: false },
];
await productRepository.save(products);
console.log('Products seeded successfully.');
}
}
```
Bu seeder'ı çalıştırmak için özel bir CLI komutu oluşturmanız veya `onModuleInit` hook'unu kullanmanız gerekebilir.
### 4. Gelişmiş İlişkiler ve İlişkisel Veri Yönetimi
TypeORM, `OneToOne`, `OneToMany`, `ManyToOne`, `ManyToMany` gibi ilişkileri tanımlamanıza olanak tanır. Bu, karmaşık veri modelleriyle çalışırken çok önemlidir.
```typescript
// src/orders/order.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany } from 'typeorm';
import { User } from '../users/user.entity';
import { OrderItem } from './order-item.entity';
@Entity('orders')
export class Order {
@PrimaryGeneratedColumn()
id: number;
@Column('timestamp', { default: () => 'CURRENT_TIMESTAMP' })
orderDate: Date;
@ManyToOne(() => User, (user) => user.orders)
user: User;
@OneToMany(() => OrderItem, (orderItem) => orderItem.order, { cascade: true })
items: OrderItem[];
}
// src/orders/order-item.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { Order } from './order.entity';
import { Product } from '../products/product.entity';
@Entity('order_items')
export class OrderItem {
@PrimaryGeneratedColumn()
id: number;
@Column()
quantity: number;
@Column('decimal', { precision: 10, scale: 2 })
price: number;
@ManyToOne(() => Order, (order) => order.items)
order: Order;
@ManyToOne(() => Product)
product: Product;
}
```
Bu ilişkileri doğru bir şekilde tanımlamak, veritabanı sorgularınızı optimize etmenize ve `join` işlemlerini otomatik olarak yönetmenize olanak tanır.
## Best Practices & Anti-Patterns (Veritabanı Katmanı)
NestJS ile veritabanı etkileşimlerinde performans, güvenlik ve sürdürülebilirlik sağlamak için dikkat etmeniz gereken bazı önemli noktalar:
* **✅ DTO (Data Transfer Object) Kullanımı:** Gelen istek verilerini ve giden yanıt verilerini tanımlamak için DTO'ları kullanın. Bu, veri validasyonunu ve tip güvenliğini sağlar. `class-validator` ve `class-transformer` paketleri bu konuda çok yardımcı olur.
* **❌ Doğrudan Repository Enjeksiyonu (Controller'da):** Controller'larda doğrudan TypeORM `Repository`'sini enjekte etmek yerine, iş mantığını Service katmanında tutun ve Controller'dan Service'i çağırın. Bu, sorumlulukların ayrılmasını sağlar.
* **✅ Transaction Kullanımı (Atomik İşlemler İçin):** Birden fazla veritabanı işleminin tek bir atomik birim olarak çalışması gerektiğinde transaction'ları mutlaka kullanın. Bu, veri tutarlılığını garanti eder.
* **❌ `synchronize: true` Üretim Ortamında:** Geliştirme ortamında şema senkronizasyonu faydalı olsa da, üretim ortamında veri kaybına yol açabilir. Üretimde migration'ları kullanın.
* **✅ Migration Yönetimi:** Veritabanı şema değişikliklerini izlemek ve uygulamak için TypeORM veya Prisma migration'larını kullanın. Bu, veritabanı versiyon kontrolü sağlar.
* **❌ N+1 Sorgu Problemi:** İlişkili verileri çekerken her bir alt öğe için ayrı sorgu yapmaktan kaçının. `relations` seçeneğini veya `QueryBuilder` ile join'leri kullanarak bu problemi çözün.
* **✅ Connection Pooling:** Veritabanı bağlantılarının yeniden kullanılmasını sağlamak için connection pooling'i doğru yapılandırın. TypeORM varsayılan olarak bunu yönetir, ancak ayarları optimize edilebilir.
* **❌ Ham SQL Sorgularını Güvenliksiz Kullanım:** Doğrudan kullanıcı girdisini içeren ham SQL sorgularından kaçının. Eğer ham SQL kullanmak zorundaysanız, SQL enjeksiyonlarına karşı koruma sağlamak için mutlaka parametreli sorgular kullanın.
* **✅ Dizine Ekleme (Indexing):** Sıkça sorgulanan sütunlara (özellikle `WHERE` ve `ORDER BY` clause'larında kullanılanlara) dizin ekleyerek sorgu performansını artırın.
* **❌ Büyük Veri Kümelerini Tek Seferde Çekme:** Çok sayıda kaydı tek bir sorguyla çekmek yerine, pagination (sayfalama) veya cursor tabanlı yaklaşımlar kullanarak belleği ve ağ trafiğini optimize edin.
## Yaygın Hatalar ve Çözümleri (Veritabanı)
NestJS ve TypeORM ile çalışırken karşılaşılan bazı yaygın sorunlar ve çözüm yolları:
* **Problem:** `Entity not found` hatası veya tabloların oluşmaması.
* **Sebep:** `TypeOrmModule.forRoot` içindeki `entities` dizisinin yanlış yapılandırılması veya TypeORM'un entity'leri bulamaması.
* **Çözüm:** `entities: [__dirname + '/**/*.entity{.ts,.js}']` yolunun doğru olduğundan emin olun. Transpilasyon sonrası `.js` dosyalarını hedeflediğinden emin olmak için `dist` klasörünü kontrol edin.
* **Problem:** `QueryFailedError: duplicate key value violates unique constraint` hatası.
* **Sebep:** Veritabanında benzersiz (unique) bir kısıtlamaya sahip bir sütuna zaten var olan bir değer eklemeye çalışmak.
* **Çözüm:** `INSERT` işlemi öncesinde benzersizlik kontrolü yapın veya hata durumunda uygun bir `ConflictException` (HTTP 409) fırlatın.
* **Problem:** İlişkili verilerin sorgulanırken gelmemesi (N+1 sorunu).
* **Sebep:** TypeORM'un `find` veya `findOne` metodunu kullanırken `relations` seçeneğinin belirtilmemesi veya `QueryBuilder` ile `join` işlemlerinin yapılmaması.
* **Çözüm:** İlişkili verileri eager (hemen) yüklemek için `relations: ['ilişkiAdı']` kullanın veya `QueryBuilder` ile `leftJoinAndSelect` gibi metodları kullanın.
* **Problem:** `DataSource.initialize()` çağrılmadan repository'ye erişim hatası.
* **Sebep:** `AppModule` içinde `TypeOrmModule.forRoot` çağrılmadan veya bağlantı başlatılmadan önce veritabanı işlemlerine erişmeye çalışmak.
* **Çözüm:** `AppModule`'ün doğru bir şekilde yapılandırıldığından ve uygulamanın başlatılmasını beklediğinden emin olun. Genellikle bu, NestJS uygulamasının yaşam döngüsüyle doğru bir şekilde entegre olduğunda otomatik olarak çözülür.
## Performans Optimizasyonu (Veritabanı Katmanı)
Veritabanı performansını artırmak, özellikle yüksek trafikli NestJS uygulamaları için kritik öneme sahiptir. Son projemizde, aşağıdaki teknikleri uygulayarak veritabanı sorgu sürelerinde ortalama %40 iyileşme kaydettik.
1. **Sorgu Optimizasyonu ve İndeksleme:**
* **Problem:** Yavaş çalışan sorgular, büyük tablolar üzerinde tam tablo taraması yapılması.
* **Çözüm:** `EXPLAIN ANALYZE` (PostgreSQL) veya `EXPLAIN` (MySQL) gibi araçlarla sorgu planlarını analiz edin. Sıkça kullanılan `WHERE`, `ORDER BY` ve `JOIN` koşullarına uygun indeksler ekleyin. Örneğin:
```typescript
// src/products/product.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
@Entity('products')
@Index(['name', 'isActive']) // name ve isActive sütunlarına birleşik indeks ekleyin
export class Product {
// ... diğer sütunlar
@Column({ length: 255, unique: true })
@Index({ unique: true }) // Sadece name sütununa benzersiz indeks
name: string;
// ...
}
```
2. **Bağlantı Havuzlama (Connection Pooling):**
* **Problem:** Her istek için yeni bir veritabanı bağlantısı açıp kapatmak, yüksek maliyetli ve yavaşlatıcıdır.
* **Çözüm:** TypeORM varsayılan olarak bağlantı havuzlamayı kullanır. Ancak, uygulamanızın yüküne göre havuz boyutunu (`extra: { max: 10, min: 2 }` gibi) optimize edebilirsiniz. `TypeOrmModule.forRoot` içinde `extra` seçeneklerini kullanın.
3. **Veri Önbellekleme (Caching):**
* **Problem:** Sıkça okunan ancak nadiren değişen veriler için sürekli veritabanı sorgusu yapmak.
* **Çözüm:** Redis gibi bir in-memory veri deposu kullanarak veritabanı sorgularının sonuçlarını önbelleğe alın. NestJS'in dahili `CacheModule`'ünü veya üçüncü parti kütüphaneleri kullanabilirsiniz.
```typescript
// src/products/products.service.ts - Önbellekleme örneği
import { Injectable, CacheInterceptor, UseInterceptors } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Product } from './product.entity';
@Injectable()
export class ProductsService {
constructor(
@InjectRepository(Product)
private productsRepository: Repository,
) {}
@UseInterceptors(CacheInterceptor)
async findAllCached(): Promise {
console.log('Fetching all products from DB (or cache if available)');
return this.productsRepository.find();
}
}
```
4. **Lazy/Eager Loading Optimizasyonu:**
* **Problem:** Gereksiz yere ilişkili tüm verileri çekmek (eager loading) veya her erişimde ayrı sorgular yapmak (lazy loading N+1 sorunu).
* **Çözüm:** İhtiyacınız olmayan ilişkileri `lazy: true` olarak işaretleyin ve yalnızca gerektiğinde yükleyin (`.load()`). Sıkça ihtiyaç duyulan ilişkiler için `eager: true` kullanın, ancak aşırı kullanımdan kaçının. `QueryBuilder` ile belirli ilişkileri seçerek (`.leftJoinAndSelect()`) daha granüler kontrol sağlayın.
5. **Veritabanı İstatistiklerinin Takibi:**
* **Problem:** Performans darboğazlarını veya yavaş sorguları tespit edememek.
* **Çözüm:** Veritabanınızın (PostgreSQL için `pg_stat_statements`) istatistiklerini düzenli olarak izleyin. Yavaş sorguları belirleyin ve optimize edin. NestJS'in TypeORM yapılandırmasında `logging: true` yaparak geliştirme ortamında sorguları görebilirsiniz.
## Gerçek Dünya Proje Örneği: E-ticaret API'si (Sipariş Yönetimi)
Bu bölümde, NestJS ve TypeORM kullanarak basit bir e-ticaret API'sinin sipariş yönetimi kısmını oluşturan küçük bir proje örneği sunacağım. Bu örnek, kullanıcılar, ürünler ve siparişler arasındaki ilişkileri ve CRUD işlemlerini gösterecek.
### Proje Yapısı:
```
nestjs-ecommerce-api/
├── src/
│ ├── auth/ # Kimlik doğrulama modülü (detayına girmeyeceğiz)
│ ├── database/ # Migration'lar, seeder'lar
│ ├── main.ts
│ ├── app.module.ts
│ ├── users/
│ │ ├── user.entity.ts
│ │ ├── users.module.ts
│ │ ├── users.service.ts
│ │ └── users.controller.ts
│ ├── products/
│ │ ├── product.entity.ts
│ │ ├── products.module.ts
│ │ ├── products.service.ts
│ │ └── products.controller.ts
│ └── orders/
│ ├── order.entity.ts
│ ├── order-item.entity.ts
│ ├── orders.module.ts
│ ├── orders.service.ts
│ └── orders.controller.ts
└── .env
└── ormconfig.ts (veya typeorm.config.ts)
└── package.json
```
### 1. Kullanıcı Entity'si (`src/users/user.entity.ts`)
```typescript
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { Order } from '../orders/order.entity'