💨
【Flutter】SQLiteを用いたトランザクションとバッチの処理の違い
使用するライブラリ
基本的なトランザクションとバッチの違いに関して
トランザクションとバッチの違いを表にまとめました。
基本的な違い
項目 | トランザクション | バッチ処理 |
---|---|---|
目的 | データの整合性を保つ | 処理の効率化 |
実行方法 | 個別の操作を順番に実行 | 複数の操作をまとめて実行 |
主な用途 | 送金処理、在庫管理など | データの一括登録、一括更新 |
使用シーン
状況 | トランザクション | バッチ処理 | 説明 |
---|---|---|---|
データの整合性が重要 | ◎ | ○ | トランザクションの方が制御しやすい |
大量データの処理 | △ | ◎ | バッチ処理の方が効率的 |
条件分岐が必要 | ◎ | × | トランザクションで制御する |
一括更新 | ○ | ◎ | バッチ処理が適している |
sqflite でのトランザクション
トランザクションは sqflite の基本的な機能の一つで、データベースの一貫性を保証するために使用されます。トランザクションはBEGIN TRANSACTION
で開始し、COMMIT
で終了します。
transaction_example.dart
// トランザクションの基本的な使用例
Future<void> transferMoney(int fromAccount, int toAccount, double amount) async {
final db = await database;
await db.transaction((txn) async {
// 送金元の残高確認
final senderBalance = await txn.query(
'accounts',
columns: ['balance'],
where: 'id = ?',
whereArgs: [fromAccount]
);
if (senderBalance.first['balance'] < amount) {
// 例外をスローすることで、トランザクションが自動的にロールバックされます
throw Exception('残高不足です');
}
// 送金元から引き出し
await txn.update(
'accounts',
{'balance': senderBalance.first['balance'] - amount},
where: 'id = ?',
whereArgs: [fromAccount]
);
// 送金先に入金
await txn.update(
'accounts',
{'balance': senderBalance.first['balance'] + amount},
where: 'id = ?',
whereArgs: [toAccount]
);
});
}
トランザクションの重要な特徴は、すべての処理が成功するか、すべての処理が行われないかのどちらかということです。途中でエラーが発生した場合、それまでに行われた変更はすべて取り消されます。
sqflite でのバッチ処理
バッチ処理は、複数の SQL 文を一度に実行するための機能です。また、今回はデータの整合性をあわせるために、トランザクションとバッチの両方を実装しています。バッチ処理を一つのトランザクション内で複数行う場合は、複数の batch の変数の宣言を行う必要があります。
batch_example.dart
Future<void> createNewUserWithSettings(User user, List<UserSetting> settings) async {
final db = await database;
// バッチ処理はトランザクション内で実行可能
await db.transaction((txn) async {
final batch = txn.batch();
// ユーザーの作成
batch.insert('users', user.toMap());
// ユーザー設定の一括登録
for (var setting in settings) {
batch.insert('user_settings', setting.toMap());
}
// commitが実行されてから、上記のbatchの処理が実行される。
// (トランザクション内なのでここではまだ確定しない)
await batch.commit();
// トランザクションが終了するときに全ての変更が確定します
});
}
使い分けのガイドライン
-
トランザクションを使用すべき場合:
- データの整合性が重要な処理
- 条件に基づいて処理を分岐させる必要がある場合
- クエリ結果を確認してから更新を行う場合
-
バッチ処理を使用すべき場合:
- 大量のデータを一括で処理する場合
- 処理の順序が決まっていて条件分岐が不要な場合
- パフォーマンスの最適化が必要な場合
-
組み合わせが有効な場合:
- 大量データの処理と整合性チェックの両方が必要な場合
- 複数のバッチ処理を小さい単位で実行したい場合
- 処理の一部で条件分岐が必要な場合
この使い分けを適切に行うことで、効率的かつ安全なデータベース操作を実現できます。
参照
Discussion