Isar Plus

İş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ürSync MetoduAsync MetoduKullanı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ır

Async 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 bekler

Hata 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ı bloklar

UI kodunda varsayılan olarak async kullanın. Maksimum performans için yalnızca arka plan izolatlarında sync tercih edin.

Performans İpuçları

  1. 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));
    }
  2. 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);
    });
  3. 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