İşlemler
ACID uyumlu işlemlerle veri tutarlılığını sağlayın
İşlemler
İşlemler, birden fazla veritabanı operasyonunu tek bir atomik iş birimine toplar. Isar, otomatik geri alma sağlayan ACID uyumlu işlemler sunar.
Tüm Isar işlemleri ACID uyumludur: Atomic, Consistent, Isolated, Durable.
Genel Bakış
İşlemler veri tutarlılığını sağlar:
- Atomic - Tüm işlemler başarılı olur ya da hiçbiri olmaz
- Consistent - Veri geçerliliğini korur
- Isolated - Eşzamanlı işlemler birbirini etkilemez
- Durable - Commit edilen değişiklikler kalıcıdır
İşlem Türleri
| Tür | Sync Metodu | Async Metodu | Kullanım |
|---|---|---|---|
| Okuma | .read() | .readAsync() | Tutar lı okumalar |
| Yazma | .write() | .writeAsync() | Veri değişiklikleri |
Çoğu okuma işlemi otomatik olarak örtük transaction kullanır.
Okuma İşlemleri
Okuma işlemleri veritabanının tutarlı bir anlık görüntüsünü sağlar:
@collection
class Contact {
Id? id;
late String name;
late int age;
}// Açık async okuma işlemi
final result = await isar.readAsync((isar) async {
final contacts = await isar.contacts.where().findAll();
final count = isar.contacts.count();
return {
'contacts': contacts,
'count': count,
};
});// Senkron okuma işlemi
final result = isar.read((isar) {
final contacts = isar.contacts.where().findAll();
final count = isar.contacts.count();
return {
'contacts': contacts,
'count': count,
};
});// Örtük transaction (otomatik)
final contacts = await isar.contacts.where().findAll();
// Isar bunu otomatik bir transaction içinde çalıştırırAsync okuma işlemleri diğer işlemlerle paralel çalışır!
Yazma İşlemleri
Tüm yazma operasyonları açık bir transaction içinde olmalıdır:
await isar.writeAsync((isar) async {
final contact = Contact()
..name = 'John Doe'
..age = 25;
isar.contacts.put(contact);
});Otomatik Commit
İşlemler başarıyla tamamlanınca otomatik commit olur:
await isar.writeAsync((isar) async {
isar.contacts.put(contact1);
isar.contacts.put(contact2);
isar.contacts.put(contact3);
// Tüm değişiklikler birlikte commit edilir ✅
});Otomatik Rollback
Hata durumunda işlemler otomatik geri alınır:
try {
await isar.writeAsync((isar) async {
isar.contacts.put(contact1); // ✅ Çalıştı
isar.contacts.put(contact2); // ✅ Çalıştı
throw Exception('Error!');
isar.contacts.put(contact3); // ❌ Çalışmadı
});
} catch (e) {
// Tüm değişiklikler geri alındı ↩️
print('Transaction failed: $e');
}Bir transaction başarısız olduktan sonra, hatayı yakalasanız bile tekrar kullanmayın.
En İyi Uygulamalar
✅ Yapın: Toplu İşlemler
// ✅ İyi - Tek transaction
await isar.writeAsync((isar) async {
for (var contact in contacts) {
isar.contacts.put(contact);
}
});
// ✅ Daha iyi - Bulk
await isar.writeAsync((isar) async {
isar.contacts.putAll(contacts);
});❌ Yapmayın: Çoklu Transaction
// ❌ Kötü - Çok sayıda transaction (yavaş!)
for (var contact in contacts) {
await isar.writeAsync((isar) async {
isar.contacts.put(contact);
});
}✅ Yapın: Transaction Kapsamını Küçültün
// ✅ İyi - Veriyi dışında hazırlayın
final processedContacts = contacts.map((c) =>
Contact()
..name = c.name.toUpperCase()
..age = c.age
).toList();
await isar.writeAsync((isar) async {
isar.contacts.putAll(processedContacts);
});❌ Yapmayın: Ağır İşlemler İçeride
// ❌ Kötü - Transaction içinde ağır işlem
await isar.writeAsync((isar) async {
final processedContacts = contacts.map((c) =>
Contact()
..name = c.name.toUpperCase()
..age = c.age
).toList();
isar.contacts.putAll(processedContacts);
});❌ Yapmayın: Ağ Çağrıları
// ❌ Çok Kötü - Transaction içinde network çağrısı
await isar.writeAsync((isar) async {
final response = await http.get('https://api.example.com/data');
final contacts = parseContacts(response.body);
isar.contacts.putAll(contacts);
});
// ✅ İyi - Network çağrısı dışarıda
final response = await http.get('https://api.example.com/data');
final contacts = parseContacts(response.body);
await isar.writeAsync((isar) async {
isar.contacts.putAll(contacts);
});Transaction içinde ağ çağrısı, dosya I/O veya uzun süren işlemler yapmayın!
Karmaşık İşlemler
Çoklu Koleksiyon
await isar.writeAsync((isar) async {
// Kullanıcı oluştur
final user = User()..name = 'John';
isar.users.put(user);
// Kullanıcıya bağlı profil
final profile = Profile()
..userId = user.id
..bio = 'Developer';
isar.profiles.put(profile);
// Gönderiler
final posts = [
Post()..userId = user.id..title = 'First Post',
Post()..userId = user.id..title = 'Second Post',
];
isar.posts.putAll(posts);
// Hepsi birlikte commit ✅
});Koşullu İşlemler
await isar.writeAsync((isar) async {
final user = await isar.users.getAsync(userId);
if (user != null && user.age >= 18) {
user.verified = true;
isar.users.put(user);
} else {
throw Exception('User not eligible');
}
});Doğrulamalı Güncelleme
await isar.writeAsync((isar) async {
final users = await isar.users
.where()
.ageGreaterThan(18)
.findAllAsync();
for (var user in users) {
if (!user.verified) {
user.verified = true;
user.verifiedAt = DateTime.now();
isar.users.put(user);
}
}
});Transaction İzolasyonu
// Birden fazla okuma işlemi paralel çalışır
final future1 = isar.readAsync((isar) async {
return await isar.contacts.where().findAllAsync();
});
final future2 = isar.readAsync((isar) async {
return await isar.contacts.countAsync();
});
// İkisi de aynı anda çalışır ⚡
final results = await Future.wait([future1, future2]);// Okuyucular tutarlı snapshot görür
unawaited(isar.writeAsync((isar) async {
await Future.delayed(Duration(seconds: 2));
isar.contacts.put(newContact);
}));
// Bu okuma eski veriyi görür (tutarlı snapshot)
final contacts = await isar.contacts.where().findAllAsync();
// newContact dahil değildir// Yazma işlemleri seri olarak çalışır
final future1 = isar.writeAsync((isar) async {
await Future.delayed(Duration(seconds: 1));
isar.contacts.put(contact1);
});
final future2 = isar.writeAsync((isar) async {
isar.contacts.put(contact2);
});
// future2, future1'in bitmesini beklerHata Yönetimi
Temel Hata Yönetimi
try {
await isar.writeAsync((isar) async {
isar.contacts.put(contact);
});
print('Transaction succeeded');
} catch (e) {
print('Transaction failed: $e');
// Değişiklikler otomatik geri alınır
}Özel Doğrulamalar
class ValidationException implements Exception {
final String message;
ValidationException(this.message);
}
try {
await isar.writeAsync((isar) async {
if (contact.age < 0) {
throw ValidationException('Age cannot be negative');
}
await isar.contacts.put(contact);
});
} on ValidationException catch (e) {
print('Validation error: ${e.message}');
} catch (e) {
print('Unexpected error: $e');
}Retry Mantığı
Future<void> putWithRetry(Contact contact, {int maxAttempts = 3}) async {
for (var attempt = 1; attempt <= maxAttempts; attempt++) {
try {
await isar.writeAsync((isar) async {
isar.contacts.put(contact);
});
return; // Başarılı
} catch (e) {
if (attempt == maxAttempts) rethrow;
await Future.delayed(Duration(milliseconds: 100 * attempt));
}
}
}Senkron vs Asenkron
// ✅ UI izolatında async kullanın
await isar.writeAsync((isar) async {
isar.contacts.put(contact);
});
// UI'ı bloklamaz// ✅ Arka plan izolatında sync kullanın
isar.write((isar) {
isar.contacts.put(contact);
});
// Daha hızlıdır ancak mevcut izolatı bloklarUI kodunda varsayılan olarak async kullanın. Maksimum performans için yalnızca arka plan izolatlarında sync tercih edin.
Performans İpuçları
-
Toplu İşlemler
// ✅ Hızlı - 1 transaction await isar.writeAsync((isar) => isar.contacts.putAll(list)); // ❌ Yavaş - N transaction for (var item in list) { await isar.writeAsync((isar) => isar.contacts.put(item)); } -
Süreyi Minimize Edin
// ✅ Hızlı final data = prepareData(); await isar.writeAsync((isar) => isar.contacts.putAll(data)); // ❌ Yavaş await isar.writeAsync((isar) { final data = prepareData(); // Ağır işlem isar.contacts.putAll(data); }); -
Bulk Operasyonları Kullanın
// ✅ Optimize await isar.writeAsync((isar) async { isar.contacts.putAll(contacts); isar.posts.deleteAll(postIds); });
Yaygın Desenler
Oluştur veya Güncelle
await isar.writeAsync((isar) async {
final existing = await isar.users
.where()
.emailEqualTo(user.email)
.findFirstAsync();
if (existing != null) {
user.id = existing.id; // ID'yi yeniden kullan
}
isar.users.put(user);
});Atomik Sayaç
Future<int> incrementCounter(String key) async {
return await isar.writeAsync((isar) async {
final counter = await isar.counters
.where()
.keyEqualTo(key)
.findFirstAsync() ?? Counter()..key = key..value = 0;
counter.value++;
isar.counters.put(counter);
return counter.value;
});
}Toplu Güncelleme
await isar.writeAsync((isar) async {
final users = await isar.users
.where()
.statusEqualTo('pending')
.findAllAsync();
for (var user in users) {
user.status = 'active';
}
isar.users.putAll(users);
});Sonraki Adımlar
Son Güncelleme