使用 SQLite 持久化資料
如果您正在撰寫需要在本機裝置上持久保存和查詢大量資料的應用程式,請考慮使用資料庫而不是本機檔案或鍵值儲存。一般而言,與其他本機持久性解決方案相比,資料庫提供更快的插入、更新和查詢速度。
Flutter 應用程式可以透過 pub.dev 上提供的 sqflite
外掛程式來使用 SQLite 資料庫。這個範例示範了使用 sqflite
來插入、讀取、更新和移除關於各種 Dog 的資料的基本方法。
如果您是 SQLite 和 SQL 陳述式的新手,請在完成這個範例之前,先複習 SQLite 教學,以了解基本知識。
這個範例使用以下步驟
- 新增相依性。
- 定義
Dog
資料模型。 - 開啟資料庫。
- 建立
dogs
資料表。 - 將
Dog
插入資料庫。 - 擷取 dogs 清單。
- 更新資料庫中的
Dog
。 - 從資料庫刪除
Dog
。
1. 新增相依性
#若要使用 SQLite 資料庫,請匯入 sqflite
和 path
套件。
sqflite
套件提供類別和函式,用於與 SQLite 資料庫互動。path
套件提供函式,用於定義將資料庫儲存在磁碟上的位置。
若要將這些套件新增為相依性,請執行 flutter pub add
flutter pub add sqflite path
請務必在您將使用的檔案中匯入這些套件。
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
2. 定義 Dog 資料模型
#在建立資料表以儲存 Dog 的資訊之前,請花一些時間定義需要儲存的資料。在此範例中,定義一個 Dog 類別,其中包含三筆資料:每個狗的唯一 id
、name
和 age
。
class Dog {
final int id;
final String name;
final int age;
const Dog({
required this.id,
required this.name,
required this.age,
});
}
3. 開啟資料庫
#在讀取和寫入資料庫之前,請先開啟與資料庫的連線。這包含兩個步驟
- 使用
sqflite
套件中的getDatabasesPath()
,結合path
套件中的join
函式,定義資料庫檔案的路徑。 - 使用
sqflite
中的openDatabase()
函式開啟資料庫。
// Avoid errors caused by flutter upgrade.
// Importing 'package:flutter/widgets.dart' is required.
WidgetsFlutterBinding.ensureInitialized();
// Open the database and store the reference.
final database = openDatabase(
// Set the path to the database. Note: Using the `join` function from the
// `path` package is best practice to ensure the path is correctly
// constructed for each platform.
join(await getDatabasesPath(), 'doggie_database.db'),
);
4. 建立 dogs
資料表
#接下來,建立一個資料表來儲存各種 Dog 的資訊。在此範例中,建立一個名為 dogs
的資料表,定義可以儲存的資料。每個 Dog
都包含 id
、name
和 age
。因此,這些在 dogs
資料表中表示為三個欄位。
id
是一個 Dartint
,並儲存為INTEGER
SQLite 資料類型。將id
作為資料表的主鍵也是一個好習慣,可以縮短查詢和更新時間。name
是一個 DartString
,並儲存為TEXT
SQLite 資料類型。age
也是一個 Dartint
,並儲存為INTEGER
資料類型。
如需更多關於可以在 SQLite 資料庫中儲存的可用資料類型的資訊,請參閱 官方 SQLite 資料類型文件。
final database = openDatabase(
// Set the path to the database. Note: Using the `join` function from the
// `path` package is best practice to ensure the path is correctly
// constructed for each platform.
join(await getDatabasesPath(), 'doggie_database.db'),
// When the database is first created, create a table to store dogs.
onCreate: (db, version) {
// Run the CREATE TABLE statement on the database.
return db.execute(
'CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
);
},
// Set the version. This executes the onCreate function and provides a
// path to perform database upgrades and downgrades.
version: 1,
);
5. 將 Dog 插入資料庫
#現在您有了一個資料庫,其中包含一個適合儲存各種狗的資訊的資料表,現在是讀取和寫入資料的時候了。
首先,將 Dog
插入 dogs
資料表。這包含兩個步驟
- 將
Dog
轉換為Map
- 使用
insert()
方法將Map
儲存在dogs
資料表中。
class Dog {
final int id;
final String name;
final int age;
Dog({
required this.id,
required this.name,
required this.age,
});
// Convert a Dog into a Map. The keys must correspond to the names of the
// columns in the database.
Map<String, Object?> toMap() {
return {
'id': id,
'name': name,
'age': age,
};
}
// Implement toString to make it easier to see information about
// each dog when using the print statement.
@override
String toString() {
return 'Dog{id: $id, name: $name, age: $age}';
}
}
// Define a function that inserts dogs into the database
Future<void> insertDog(Dog dog) async {
// Get a reference to the database.
final db = await database;
// Insert the Dog into the correct table. You might also specify the
// `conflictAlgorithm` to use in case the same dog is inserted twice.
//
// In this case, replace any previous data.
await db.insert(
'dogs',
dog.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// Create a Dog and add it to the dogs table
var fido = Dog(
id: 0,
name: 'Fido',
age: 35,
);
await insertDog(fido);
6. 擷取 Dog 清單
#現在 Dog
已儲存在資料庫中,請查詢資料庫以取得特定的狗或所有狗的清單。這包含兩個步驟
- 針對
dogs
資料表執行query
。這會傳回List<Map>
。 - 將
List<Map>
轉換為List<Dog>
。
// A method that retrieves all the dogs from the dogs table.
Future<List<Dog>> dogs() async {
// Get a reference to the database.
final db = await database;
// Query the table for all the dogs.
final List<Map<String, Object?>> dogMaps = await db.query('dogs');
// Convert the list of each dog's fields into a list of `Dog` objects.
return [
for (final {
'id': id as int,
'name': name as String,
'age': age as int,
} in dogMaps)
Dog(id: id, name: name, age: age),
];
}
// Now, use the method above to retrieve all the dogs.
print(await dogs()); // Prints a list that include Fido.
7. 更新資料庫中的 Dog
#將資訊插入資料庫後,您可能希望稍後更新該資訊。您可以使用 sqflite
程式庫中的 update()
方法來執行此操作。
這包含兩個步驟
- 將 Dog 轉換為 Map。
- 使用
where
子句來確保您更新的是正確的 Dog。
Future<void> updateDog(Dog dog) async {
// Get a reference to the database.
final db = await database;
// Update the given Dog.
await db.update(
'dogs',
dog.toMap(),
// Ensure that the Dog has a matching id.
where: 'id = ?',
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [dog.id],
);
}
// Update Fido's age and save it to the database.
fido = Dog(
id: fido.id,
name: fido.name,
age: fido.age + 7,
);
await updateDog(fido);
// Print the updated results.
print(await dogs()); // Prints Fido with age 42.
8. 從資料庫刪除 Dog
#除了插入和更新關於 Dog 的資訊之外,您也可以從資料庫中移除 Dog。若要刪除資料,請使用 sqflite
程式庫中的 delete()
方法。
在本節中,建立一個函式,該函式會接受 id 並從資料庫中刪除具有相符 id 的狗。為了讓它正常運作,您必須提供 where
子句來限制要刪除的記錄。
Future<void> deleteDog(int id) async {
// Get a reference to the database.
final db = await database;
// Remove the Dog from the database.
await db.delete(
'dogs',
// Use a `where` clause to delete a specific dog.
where: 'id = ?',
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [id],
);
}
範例
#若要執行此範例
- 建立一個新的 Flutter 專案。
- 將
sqflite
和path
套件新增至您的pubspec.yaml
。 - 將以下程式碼貼到名為
lib/db_test.dart
的新檔案中。 - 使用
flutter run lib/db_test.dart
執行程式碼。
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
void main() async {
// Avoid errors caused by flutter upgrade.
// Importing 'package:flutter/widgets.dart' is required.
WidgetsFlutterBinding.ensureInitialized();
// Open the database and store the reference.
final database = openDatabase(
// Set the path to the database. Note: Using the `join` function from the
// `path` package is best practice to ensure the path is correctly
// constructed for each platform.
join(await getDatabasesPath(), 'doggie_database.db'),
// When the database is first created, create a table to store dogs.
onCreate: (db, version) {
// Run the CREATE TABLE statement on the database.
return db.execute(
'CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT, age INTEGER)',
);
},
// Set the version. This executes the onCreate function and provides a
// path to perform database upgrades and downgrades.
version: 1,
);
// Define a function that inserts dogs into the database
Future<void> insertDog(Dog dog) async {
// Get a reference to the database.
final db = await database;
// Insert the Dog into the correct table. You might also specify the
// `conflictAlgorithm` to use in case the same dog is inserted twice.
//
// In this case, replace any previous data.
await db.insert(
'dogs',
dog.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
// A method that retrieves all the dogs from the dogs table.
Future<List<Dog>> dogs() async {
// Get a reference to the database.
final db = await database;
// Query the table for all the dogs.
final List<Map<String, Object?>> dogMaps = await db.query('dogs');
// Convert the list of each dog's fields into a list of `Dog` objects.
return [
for (final {
'id': id as int,
'name': name as String,
'age': age as int,
} in dogMaps)
Dog(id: id, name: name, age: age),
];
}
Future<void> updateDog(Dog dog) async {
// Get a reference to the database.
final db = await database;
// Update the given Dog.
await db.update(
'dogs',
dog.toMap(),
// Ensure that the Dog has a matching id.
where: 'id = ?',
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [dog.id],
);
}
Future<void> deleteDog(int id) async {
// Get a reference to the database.
final db = await database;
// Remove the Dog from the database.
await db.delete(
'dogs',
// Use a `where` clause to delete a specific dog.
where: 'id = ?',
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [id],
);
}
// Create a Dog and add it to the dogs table
var fido = Dog(
id: 0,
name: 'Fido',
age: 35,
);
await insertDog(fido);
// Now, use the method above to retrieve all the dogs.
print(await dogs()); // Prints a list that include Fido.
// Update Fido's age and save it to the database.
fido = Dog(
id: fido.id,
name: fido.name,
age: fido.age + 7,
);
await updateDog(fido);
// Print the updated results.
print(await dogs()); // Prints Fido with age 42.
// Delete Fido from the database.
await deleteDog(fido.id);
// Print the list of dogs (empty).
print(await dogs());
}
class Dog {
final int id;
final String name;
final int age;
Dog({
required this.id,
required this.name,
required this.age,
});
// Convert a Dog into a Map. The keys must correspond to the names of the
// columns in the database.
Map<String, Object?> toMap() {
return {
'id': id,
'name': name,
'age': age,
};
}
// Implement toString to make it easier to see information about
// each dog when using the print statement.
@override
String toString() {
return 'Dog{id: $id, name: $name, age: $age}';
}
}
除非另有說明,本網站上的文件反映了 Flutter 的最新穩定版本。頁面最後更新於 2024-04-04。 檢視原始碼 或 回報問題。