SQLite Nedir?
[!NOTE] Hızlı Karşılaştırma: SQLite vs MySQL Neden SQLite seçmelisiniz? İşte kısa bir özet:
Özellik SQLite MySQL / PostgreSQL Kurulum Gerektirmez (Tek Dosya) Sunucu Kurulumu Gerekir Depolama Tek bir .dbdosyasıKarmaşık Dosya Sistemi Kullanıcı Yönetimi Yok (Dosya İzinleri) Gelişmiş Kullanıcı Yönetimi En İyi Kullanım Mobil, IoT, Küçük Web Siteleri Büyük Web Siteleri, Kurumsal
SQLite, tamamen açık kaynak kodlu, hafif bir ilişkisel veritabanı yönetim sistemidir (RDBMS). En önemli özelliği, sunucu gerektirmemesi ve tamamen dosya tabanlı çalışmasıdır. Tüm veritabanı tek bir dosyada saklanır, bu da kurulum ve dağıtımı son derece kolaylaştırır.
SQLite’ın Temel Özellikleri
- Sıfır Konfigürasyon: Kurulum gerektirmez, sadece bir DLL veya native library yeterlidir
- Düşük Kaynak Kullanımı: Minimal bellek ve CPU kullanımı
- ACID Uyumlu: Transaction desteği ile veri bütünlüğü garantisi
- Platform Bağımsız: Windows, Linux, macOS, iOS, Android ve daha fazlasında çalışır
- Yüksek Performans: Küçük ve orta ölçekli uygulamalar için optimize edilmiştir
- SQL Standartlarına Uyum: SQL-92 standardının büyük bir kısmını destekler
SQLite’ın Kullanım Alanları
- Mobil Uygulamalar: iOS ve Android uygulamalarında yerel veri depolama
- Masaüstü Uygulamaları: Offline çalışan desktop uygulamaları
- Gömülü Sistemler: IoT cihazları ve embedded sistemler
- Prototipleme: Hızlı geliştirme ve test aşamaları
- Küçük Web Uygulamaları: Düşük trafikli web siteleri
- Cache Mekanizmaları: Geçici veri depolama çözümleri
Neden SQLite Tercih Edilmeli?
Gerçek Hayat Senaryosu
Bir bina ve ofis yönetim yazılımı geliştirme projesinde, müşteri mevcut sistemin çok yavaş olduğundan şikayetçiydi. Çözüm için birkaç seçenek vardı:
- Merkezi Sunucu: Intranet ağı gerektiriyordu, ekstra maliyet
- Local Sunucu: Eski makinelere yük olacaktı
- SQLite: Dosya tabanlı, düşük kaynak kullanımı, hızlı
SQLite seçimi sayesinde:
- Sunucu kurulum maliyeti ortadan kalktı
- Eski donanımlarda bile sorunsuz çalıştı
- Performans sorunları çözüldü
- Dağıtım ve bakım kolaylaştı
SQLite’ın Avantajları
1. Basitlik ve Hız
- Sunucu yönetimi yok
- Network gecikmesi yok
- Dosya sistemi üzerinden direkt erişim
2. Düşük Maliyet
- Sunucu lisansı gerekmez
- Hosting maliyeti yok
- Minimum sistem gereksinimleri
3. Güvenilirlik
- Yıllardır test edilmiş, stabil
- Büyük şirketler tarafından kullanılıyor (Google, Apple, Microsoft)
- Veri kaybı riski minimal
4. Esneklik
- Veritabanı dosyasını kolayca yedekleyebilirsiniz
- Farklı platformlar arasında taşınabilir
- Versiyon kontrol sistemlerine eklenebilir
SQLite’ın Sınırlamaları
SQLite her durum için uygun değildir:
- Eşzamanlı Yazma İşlemleri: Çok sayıda eşzamanlı yazma işlemi için uygun değil
- Büyük Veri Setleri: Terabayt seviyesinde veriler için önerilmez
- Network Erişimi: Ağ üzerinden erişim gerektiren durumlarda uygun değil
- Çok Kullanıcılı Sistemler: Merkezi bir veritabanı sunucusu gerektiren durumlar
SQLite Kurulumu ve Kullanımı
1. Veritabanı Editörü Seçimi
SQLite veritabanınızı yönetmek için bir editöre ihtiyacınız var:
Önerilen Araçlar:
- DB Browser for SQLite: Ücretsiz, açık kaynak, kullanıcı dostu
- SQLiteStudio: Platform bağımsız, güçlü özellikler
- DBeaver: Çoklu veritabanı desteği
- VS Code Eklentileri: SQLite Viewer, SQLite gibi eklentiler
2. NuGet Paket Kurulumu
.NET projelerinde SQLite kullanmak için birkaç seçenek var:
Seçenek 1: System.Data.SQLite (ADO.NET)
PM> Install-Package System.Data.SQLite
Seçenek 2: Microsoft.EntityFrameworkCore.Sqlite (Entity Framework Core)
PM> Install-Package Microsoft.EntityFrameworkCore.Sqlite
PM> Install-Package Microsoft.EntityFrameworkCore.Design
Seçenek 3: Microsoft.Data.Sqlite (.NET Core/5+)
PM> Install-Package Microsoft.Data.Sqlite
3. Veritabanı Dosyası Oluşturma
SQLite veritabanı dosyaları genellikle .db, .sqlite, veya .sqlite3 uzantısı kullanır. Modern uygulamalarda .db veya .sqlite3 tercih edilir.
C# ile SQLite Kullanım Örnekleri
Örnek 1: ADO.NET ile Temel İşlemler
using System.Data.SQLite;
using System.IO;
public class SQLiteHelper
{
private readonly string _connectionString;
public SQLiteHelper(string dbPath)
{
_connectionString = $"Data Source={dbPath};Version=3;";
// Veritabanı dosyası yoksa oluştur
if (!File.Exists(dbPath))
{
SQLiteConnection.CreateFile(dbPath);
}
}
// Veri Ekleme (Parametreli Sorgu - SQL Injection'a karşı güvenli)
public void InsertData(string name, string email)
{
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
const string query = @"
INSERT INTO Users (Name, Email, CreatedDate)
VALUES (@name, @email, @createdDate)";
using var command = new SQLiteCommand(query, connection);
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@email", email);
command.Parameters.AddWithValue("@createdDate", DateTime.Now);
command.ExecuteNonQuery();
}
// Veri Okuma
public List<User> GetAllUsers()
{
var users = new List<User>();
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
const string query = "SELECT Id, Name, Email, CreatedDate FROM Users";
using var command = new SQLiteCommand(query, connection);
using var reader = command.ExecuteReader();
while (reader.Read())
{
users.Add(new User
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Email = reader.GetString(2),
CreatedDate = reader.GetDateTime(3)
});
}
return users;
}
// Veri Güncelleme
public void UpdateUser(int id, string name, string email)
{
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
const string query = @"
UPDATE Users
SET Name = @name, Email = @email
WHERE Id = @id";
using var command = new SQLiteCommand(query, connection);
command.Parameters.AddWithValue("@id", id);
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@email", email);
command.ExecuteNonQuery();
}
// Veri Silme
public void DeleteUser(int id)
{
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
const string query = "DELETE FROM Users WHERE Id = @id";
using var command = new SQLiteCommand(query, connection);
command.Parameters.AddWithValue("@id", id);
command.ExecuteNonQuery();
}
// Transaction Örneği
public void InsertMultipleUsers(List<(string name, string email)> users)
{
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
using var transaction = connection.BeginTransaction();
try
{
const string query = @"
INSERT INTO Users (Name, Email, CreatedDate)
VALUES (@name, @email, @createdDate)";
foreach (var (name, email) in users)
{
using var command = new SQLiteCommand(query, connection, transaction);
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@email", email);
command.Parameters.AddWithValue("@createdDate", DateTime.Now);
command.ExecuteNonQuery();
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
// Tablo Oluşturma
public void CreateUsersTable()
{
using var connection = new SQLiteConnection(_connectionString);
connection.Open();
const string query = @"
CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Email TEXT NOT NULL UNIQUE,
CreatedDate DATETIME NOT NULL
)";
using var command = new SQLiteCommand(query, connection);
command.ExecuteNonQuery();
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public DateTime CreatedDate { get; set; }
}
Örnek 2: Async/Await ile Modern C# Kullanımı
using System.Data.SQLite;
using System.Threading.Tasks;
public class AsyncSQLiteHelper
{
private readonly string _connectionString;
public AsyncSQLiteHelper(string dbPath)
{
_connectionString = $"Data Source={dbPath};Version=3;";
}
// Async Veri Ekleme
public async Task<int> InsertUserAsync(string name, string email)
{
await using var connection = new SQLiteConnection(_connectionString);
await connection.OpenAsync();
const string query = @"
INSERT INTO Users (Name, Email, CreatedDate)
VALUES (@name, @email, @createdDate);
SELECT last_insert_rowid();";
await using var command = new SQLiteCommand(query, connection);
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@email", email);
command.Parameters.AddWithValue("@createdDate", DateTime.Now);
var result = await command.ExecuteScalarAsync();
return Convert.ToInt32(result);
}
// Async Veri Okuma
public async Task<List<User>> GetUsersAsync()
{
var users = new List<User>();
await using var connection = new SQLiteConnection(_connectionString);
await connection.OpenAsync();
const string query = "SELECT Id, Name, Email, CreatedDate FROM Users";
await using var command = new SQLiteCommand(query, connection);
await using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
users.Add(new User
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Email = reader.GetString(2),
CreatedDate = reader.GetDateTime(3)
});
}
return users;
}
}
Örnek 3: Entity Framework Core ile Kullanım
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
// DbContext Tanımı
public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=app.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Email).IsRequired().HasMaxLength(255);
entity.HasIndex(e => e.Email).IsUnique();
});
}
}
// Entity Sınıfı
[Table("Users")]
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; }
[Required]
[MaxLength(255)]
public string Email { get; set; }
public DateTime CreatedDate { get; set; }
}
// Kullanım Örnekleri
public class UserService
{
private readonly AppDbContext _context;
public UserService(AppDbContext context)
{
_context = context;
}
// Veri Ekleme
public async Task<User> CreateUserAsync(string name, string email)
{
var user = new User
{
Name = name,
Email = email,
CreatedDate = DateTime.Now
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
return user;
}
// Veri Okuma
public async Task<List<User>> GetAllUsersAsync()
{
return await _context.Users
.OrderBy(u => u.CreatedDate)
.ToListAsync();
}
// LINQ ile Sorgulama
public async Task<User> GetUserByEmailAsync(string email)
{
return await _context.Users
.FirstOrDefaultAsync(u => u.Email == email);
}
// Veri Güncelleme
public async Task UpdateUserAsync(int id, string name, string email)
{
var user = await _context.Users.FindAsync(id);
if (user != null)
{
user.Name = name;
user.Email = email;
await _context.SaveChangesAsync();
}
}
// Veri Silme
public async Task DeleteUserAsync(int id)
{
var user = await _context.Users.FindAsync(id);
if (user != null)
{
_context.Users.Remove(user);
await _context.SaveChangesAsync();
}
}
}
Örnek 4: Dependency Injection ile Kullanım (.NET Core/5+)
// Startup.cs veya Program.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options =>
options.UseSqlite("Data Source=app.db"));
services.AddScoped<UserService>();
}
// Controller veya Service
public class UserController : ControllerBase
{
private readonly UserService _userService;
public UserController(UserService userService)
{
_userService = userService;
}
[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] CreateUserDto dto)
{
var user = await _userService.CreateUserAsync(dto.Name, dto.Email);
return Ok(user);
}
}
Best Practices ve Öneriler
1. Connection String Yönetimi
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=app.db;Version=3;Cache=Shared;"
}
}
// Connection String Parametreleri
// Cache=Shared: Bellek cache'i paylaşır (performans artışı)
// Foreign Keys=True: Foreign key kısıtlamalarını aktif eder
// Journal Mode=WAL: Write-Ahead Logging modu (daha iyi performans)
2. Connection Pooling
SQLite connection pooling’i otomatik yönetir, ancak using statement kullanarak bağlantıları düzgün kapatmak önemlidir.
3. Performans İpuçları
- Index Kullanımı: Sık sorgulanan kolonlara index ekleyin
- Batch İşlemler: Çoklu insert için transaction kullanın
- WAL Modu: Write-Ahead Logging modunu aktif edin
- Prepared Statements: Parametreli sorgular kullanın (SQL Injection koruması + performans)
4. Güvenlik
- Parametreli Sorgular: Her zaman parametreli sorgular kullanın
- Input Validation: Kullanıcı girdilerini doğrulayın
- Backup: Düzenli olarak veritabanı dosyasını yedekleyin
5. Migration ve Schema Yönetimi
Entity Framework Core ile migration kullanın:
PM> Add-Migration InitialCreate
PM> Update-Database
Sonuç
SQLite, özellikle küçük ve orta ölçekli uygulamalar için mükemmel bir seçenektir. Sunucu gerektirmemesi, düşük kaynak kullanımı ve kolay dağıtım özellikleri sayesinde birçok senaryoda ideal çözümdür. Modern .NET uygulamalarında Entity Framework Core veya ADO.NET ile rahatlıkla kullanılabilir.
Ne Zaman SQLite Kullanmalı?
- Offline çalışan uygulamalar
- Prototip ve test projeleri
- Küçük ve orta ölçekli veri setleri
- Sunucu kurulumu yapılamayan ortamlar
- Mobil ve embedded uygulamalar
Ne Zaman Kullanmamalı?
- Çok sayıda eşzamanlı yazma işlemi gerektiren durumlar
- Network üzerinden erişim gerektiren sistemler
- Terabayt seviyesinde veri setleri
- Merkezi veritabanı sunucusu gerektiren kurumsal uygulamalar